Add AM_GNU_GETTEXT_VERSION(0.17) to configure.in to fix build error
[profile/ivi/ecore.git] / src / lib / ecore / ecore.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <errno.h>
11
12 #ifndef _MSC_VER
13 # include <unistd.h>
14 #endif
15
16 #ifdef HAVE_LOCALE_H
17 # include <locale.h>
18 #endif
19
20 #ifdef HAVE_LANGINFO_H
21 # include <langinfo.h>
22 #endif
23
24 #ifdef HAVE_SYS_MMAN_H
25 # include <sys/mman.h>
26 #endif
27
28 #ifdef HAVE_EVIL
29 # include <Evil.h>
30 #endif
31 #include <Eina.h>
32
33 #include "Ecore.h"
34 #include "ecore_private.h"
35
36 #if HAVE_MALLINFO
37 #include <malloc.h>
38
39 static Ecore_Version _version = { VERS_MAJ, VERS_MIN, VERS_MIC, VERS_REV };
40 EAPI Ecore_Version *ecore_version = &_version;
41
42 #define KEEP_MAX(Global, Local) \
43   if (Global < (Local))         \
44     Global = Local;
45
46 static Eina_Bool _ecore_memory_statistic(void *data);
47 static int _ecore_memory_max_total = 0;
48 static int _ecore_memory_max_free = 0;
49 static pid_t _ecore_memory_pid = 0;
50 #endif
51
52 static const char *_ecore_magic_string_get(Ecore_Magic m);
53 static int _ecore_init_count = 0;
54 int _ecore_log_dom = -1;
55 int _ecore_fps_debug = 0;
56
57 typedef struct _Ecore_Safe_Call Ecore_Safe_Call;
58 struct _Ecore_Safe_Call
59 {
60    union {
61       Ecore_Cb      async;
62       Ecore_Data_Cb sync;
63    } cb;
64    void          *data;
65
66    Eina_Lock      m;
67    Eina_Condition c;
68
69    int            current_id;
70
71    Eina_Bool      sync : 1;
72    Eina_Bool      suspend : 1;
73 };
74
75 static void _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order);
76 static void _thread_safe_cleanup(void *data);
77 static void _thread_callback(void        *data,
78                              void        *buffer,
79                              unsigned int nbyte);
80 static Eina_List *_thread_cb = NULL;
81 static Ecore_Pipe *_thread_call = NULL;
82 static Eina_Lock _thread_safety;
83 static const int wakeup = 42;
84
85 static int _thread_loop = 0;
86 static Eina_Lock _thread_mutex;
87 static Eina_Condition _thread_cond;
88 static Eina_Lock _thread_feedback_mutex;
89 static Eina_Condition _thread_feedback_cond;
90
91 static Eina_Lock _thread_id_lock;
92 static int _thread_id = -1;
93 static int _thread_id_max = 0;
94 static int _thread_id_update = 0;
95
96 Eina_Lock _ecore_main_loop_lock;
97 int _ecore_main_lock_count;
98
99 /** OpenBSD does not define CODESET
100  * FIXME ??
101  */
102
103 #ifndef CODESET
104 # define CODESET "INVALID"
105 #endif
106
107 /**
108  * @addtogroup Ecore_Init_Group
109  *
110  * @{
111  */
112
113 /**
114  * Set up connections, signal handlers, sockets etc.
115  * @return 1 or greater on success, 0 otherwise
116  *
117  * This function sets up all singal handlers and the basic event loop. If it
118  * succeeds, 1 will be returned, otherwise 0 will be returned.
119  *
120  * @code
121  * #include <Ecore.h>
122  *
123  * int main(int argc, char **argv)
124  * {
125  *   if (!ecore_init())
126  *   {
127  *     printf("ERROR: Cannot init Ecore!\n");
128  *     return -1;
129  *   }
130  *   ecore_main_loop_begin();
131  *   ecore_shutdown();
132  * }
133  * @endcode
134  */
135 EAPI int
136 ecore_init(void)
137 {
138    if (++_ecore_init_count != 1)
139      return _ecore_init_count;
140
141 #ifdef HAVE_LOCALE_H
142    setlocale(LC_CTYPE, "");
143 #endif
144    /*
145       if (strcmp(nl_langinfo(CODESET), "UTF-8"))
146       {
147         WRN("Not a utf8 locale!");
148       }
149     */
150 #ifdef HAVE_EVIL
151    if (!evil_init())
152      return --_ecore_init_count;
153 #endif
154    if (!eina_init())
155      goto shutdown_evil;
156    _ecore_log_dom = eina_log_domain_register("ecore", ECORE_DEFAULT_LOG_COLOR);
157    if (_ecore_log_dom < 0)
158      {
159         EINA_LOG_ERR("Ecore was unable to create a log domain.");
160         goto shutdown_log_dom;
161      }
162    if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
163    if (_ecore_fps_debug) _ecore_fps_debug_init();
164    if (!ecore_mempool_init()) goto shutdown_mempool;
165    _ecore_main_loop_init();
166    _ecore_signal_init();
167 #ifndef HAVE_EXOTIC
168    _ecore_exe_init();
169 #endif
170    _ecore_thread_init();
171    _ecore_glib_init();
172    _ecore_job_init();
173    _ecore_time_init();
174
175    eina_lock_new(&_thread_mutex);
176    eina_condition_new(&_thread_cond, &_thread_mutex);
177    eina_lock_new(&_thread_feedback_mutex);
178    eina_condition_new(&_thread_feedback_cond, &_thread_feedback_mutex);
179    _thread_call = ecore_pipe_add(_thread_callback, NULL);
180    eina_lock_new(&_thread_safety);
181
182    eina_lock_new(&_thread_id_lock);
183
184    eina_lock_new(&_ecore_main_loop_lock);
185
186 #if HAVE_MALLINFO
187    if (getenv("ECORE_MEM_STAT"))
188      {
189         _ecore_memory_pid = getpid();
190         ecore_animator_add(_ecore_memory_statistic, NULL);
191      }
192 #endif
193
194 #if defined(GLIB_INTEGRATION_ALWAYS)
195    if (_ecore_glib_always_integrate) ecore_main_loop_glib_integrate();
196 #endif
197
198    return _ecore_init_count;
199
200 shutdown_mempool:
201    ecore_mempool_shutdown();
202 shutdown_log_dom:
203    eina_shutdown();
204 shutdown_evil:
205 #ifdef HAVE_EVIL
206    evil_shutdown();
207 #endif
208    return --_ecore_init_count;
209 }
210
211 /**
212  * Shut down connections, signal handlers sockets etc.
213  *
214  * @return 0 if ecore shuts down, greater than 0 otherwise.
215  * This function shuts down all things set up in ecore_init() and cleans up all
216  * event queues, handlers, filters, timers, idlers, idle enterers/exiters
217  * etc. set up after ecore_init() was called.
218  *
219  * Do not call this function from any callback that may be called from the main
220  * loop, as the main loop will then fall over and not function properly.
221  */
222 EAPI int
223 ecore_shutdown(void)
224 {
225      Ecore_Pipe *p;
226    /*
227     * take a lock here because _ecore_event_shutdown() does callbacks
228     */
229      _ecore_lock();
230      if (_ecore_init_count <= 0)
231        {
232           ERR("Init count not greater than 0 in shutdown.");
233           _ecore_unlock();
234           return 0;
235        }
236      if (--_ecore_init_count != 0)
237        goto unlock;
238    
239      if (_ecore_fps_debug) _ecore_fps_debug_shutdown();
240      _ecore_poller_shutdown();
241      _ecore_animator_shutdown();
242      _ecore_glib_shutdown();
243      _ecore_job_shutdown();
244      _ecore_thread_shutdown();
245
246    /* this looks horrible - a hack for now, but something to note. as
247     * we delete the _thread_call pipe a thread COULD be doing
248     * ecore_pipe_write() or what not to it at the same time - we
249     * must ensure all possible users of this _thread_call are finished
250     * and exited before we delete it here */
251    /*
252     * ok - this causes other valgrind complaints regarding glib aquiring
253     * locks internally. so fix bug a or bug b. let's leave the original
254     * bug in then and leave this as a note for now
255     */
256    /*
257     * It should be fine now as we do wait for thread to shutdown before
258     * we try to destroy the pipe.
259     */
260      p = _thread_call;
261      _thread_call = NULL;
262      ecore_pipe_wait(p, 1, 0.1);
263      ecore_pipe_del(p);
264      eina_lock_free(&_thread_safety);
265      eina_condition_free(&_thread_cond);
266      eina_lock_free(&_thread_mutex);
267      eina_condition_free(&_thread_feedback_cond);
268      eina_lock_free(&_thread_feedback_mutex);
269      eina_lock_free(&_thread_id_lock);
270
271
272 #ifndef HAVE_EXOTIC
273      _ecore_exe_shutdown();
274 #endif
275      _ecore_idle_enterer_shutdown();
276      _ecore_idle_exiter_shutdown();
277      _ecore_idler_shutdown();
278      _ecore_timer_shutdown();
279      _ecore_event_shutdown();
280      _ecore_main_shutdown();
281      _ecore_signal_shutdown();
282      _ecore_main_loop_shutdown();
283
284 #if HAVE_MALLINFO
285      if (getenv("ECORE_MEM_STAT"))
286        {
287           _ecore_memory_statistic(NULL);
288
289           ERR("[%i] Memory MAX total: %i, free: %i",
290               _ecore_memory_pid,
291               _ecore_memory_max_total,
292               _ecore_memory_max_free);
293        }
294 #endif
295      ecore_mempool_shutdown();
296      eina_log_domain_unregister(_ecore_log_dom);
297      _ecore_log_dom = -1;
298      eina_shutdown();
299 #ifdef HAVE_EVIL
300      evil_shutdown();
301 #endif
302 unlock:
303      _ecore_unlock();
304
305      return _ecore_init_count;
306 }
307
308 struct _Ecore_Fork_Cb
309 {
310    Ecore_Cb func;
311    void *data;
312    Eina_Bool delete_me : 1;
313 };
314
315 typedef struct _Ecore_Fork_Cb Ecore_Fork_Cb;
316
317 static int fork_cbs_walking = 0;
318 static Eina_List *fork_cbs = NULL;
319
320 EAPI Eina_Bool
321 ecore_fork_reset_callback_add(Ecore_Cb func, const void *data)
322 {
323    Ecore_Fork_Cb *fcb;
324    
325    fcb = calloc(1, sizeof(Ecore_Fork_Cb));
326    if (!fcb) return EINA_FALSE;
327    fcb->func = func;
328    fcb->data = (void *)data;
329    fork_cbs = eina_list_append(fork_cbs, fcb);
330    return EINA_TRUE;
331 }
332
333 EAPI Eina_Bool
334 ecore_fork_reset_callback_del(Ecore_Cb func, const void *data)
335 {
336    Eina_List *l;
337    Ecore_Fork_Cb *fcb;
338
339    EINA_LIST_FOREACH(fork_cbs, l, fcb)
340      {
341         if ((fcb->func == func) && (fcb->data == data))
342           {
343              if (!fork_cbs_walking)
344                {
345                   fork_cbs = eina_list_remove_list(fork_cbs, l);
346                   free(fcb);
347                }
348              else
349                fcb->delete_me = EINA_TRUE;
350              return EINA_TRUE;
351           }
352      }
353    return EINA_FALSE;
354 }
355
356 EAPI void
357 ecore_fork_reset(void)
358 {
359    Eina_List *l, *ln;
360    Ecore_Fork_Cb *fcb;
361    
362    eina_lock_take(&_thread_safety);
363
364    ecore_pipe_del(_thread_call);
365    _thread_call = ecore_pipe_add(_thread_callback, NULL);
366    /* If there was something in the pipe, trigger a wakeup again */
367    if (_thread_cb) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
368
369    eina_lock_release(&_thread_safety);
370
371    // should this be done withing the eina lock stuff?
372    
373    fork_cbs_walking++;
374    EINA_LIST_FOREACH(fork_cbs, l, fcb)
375      {
376         fcb->func(fcb->data);
377      }
378    fork_cbs_walking--;
379    
380    EINA_LIST_FOREACH_SAFE(fork_cbs, l, ln, fcb)
381      {
382         if (fcb->delete_me)
383           {
384              fork_cbs = eina_list_remove_list(fork_cbs, l);
385              free(fcb);
386           }
387      }
388 }
389
390 /**
391  * @}
392  */
393
394 EAPI void
395 ecore_main_loop_thread_safe_call_async(Ecore_Cb callback,
396                                        void    *data)
397 {
398    Ecore_Safe_Call *order;
399
400    if (!callback) return;
401
402    if (eina_main_loop_is())
403      {
404         callback(data);
405         return;
406      }
407
408    order = malloc(sizeof (Ecore_Safe_Call));
409    if (!order) return;
410
411    order->cb.async = callback;
412    order->data = data;
413    order->sync = EINA_FALSE;
414    order->suspend = EINA_FALSE;
415
416    _ecore_main_loop_thread_safe_call(order);
417 }
418
419 EAPI void *
420 ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback,
421                                       void         *data)
422 {
423    Ecore_Safe_Call *order;
424    void *ret;
425
426    if (!callback) return NULL;
427
428    if (eina_main_loop_is())
429      {
430         return callback(data);
431      }
432
433    order = malloc(sizeof (Ecore_Safe_Call));
434    if (!order) return NULL;
435
436    order->cb.sync = callback;
437    order->data = data;
438    eina_lock_new(&order->m);
439    eina_condition_new(&order->c, &order->m);
440    order->sync = EINA_TRUE;
441    order->suspend = EINA_FALSE;
442
443    _ecore_main_loop_thread_safe_call(order);
444
445    eina_lock_take(&order->m);
446    eina_condition_wait(&order->c);
447    eina_lock_release(&order->m);
448
449    ret = order->data;
450
451    order->sync = EINA_FALSE;
452    order->cb.async = _thread_safe_cleanup;
453    order->data = order;
454
455    _ecore_main_loop_thread_safe_call(order);
456
457    return ret;
458 }
459
460 EAPI int
461 ecore_thread_main_loop_begin(void)
462 {
463    Ecore_Safe_Call *order;
464
465    if (eina_main_loop_is())
466      {
467         return ++_thread_loop;
468      }
469
470    order = malloc(sizeof (Ecore_Safe_Call));
471    if (!order) return -1;
472
473    eina_lock_take(&_thread_id_lock);
474    order->current_id = ++_thread_id_max;
475    if (order->current_id < 0)
476      {
477         _thread_id_max = 0;
478         order->current_id = ++_thread_id_max;
479      }
480    eina_lock_release(&_thread_id_lock);
481
482    eina_lock_new(&order->m);
483    eina_condition_new(&order->c, &order->m);
484    order->suspend = EINA_TRUE;
485
486    _ecore_main_loop_thread_safe_call(order);
487
488    eina_lock_take(&order->m);
489    while (order->current_id != _thread_id)
490      eina_condition_wait(&order->c);
491    eina_lock_release(&order->m);
492
493    eina_main_loop_define();
494
495    _thread_loop = 1;
496
497    return EINA_TRUE;
498 }
499
500 EAPI int
501 ecore_thread_main_loop_end(void)
502 {
503    int current_id;
504
505    if (_thread_loop == 0)
506      {
507         ERR("the main loop is not locked ! No matching call to ecore_thread_main_loop_begin().");
508         return -1;
509      }
510
511    /* until we unlock the main loop, this thread has the main loop id */
512    if (!eina_main_loop_is())
513      {
514         ERR("Not in a locked thread !");
515         return -1;
516      }
517
518    _thread_loop--;
519    if (_thread_loop > 0)
520      return _thread_loop;
521
522    current_id = _thread_id;
523
524    eina_lock_take(&_thread_mutex);
525    _thread_id_update = _thread_id;
526    eina_condition_broadcast(&_thread_cond);
527    eina_lock_release(&_thread_mutex);
528
529    eina_lock_take(&_thread_feedback_mutex);
530    while (current_id == _thread_id && _thread_id != -1)
531      eina_condition_wait(&_thread_feedback_cond);
532    eina_lock_release(&_thread_feedback_mutex);
533
534    return 0;
535 }
536
537 EAPI void
538 ecore_print_warning(const char *function __UNUSED__,
539                     const char *sparam __UNUSED__)
540 {
541    WRN("***** Developer Warning ***** :\n"
542        "\tThis program is calling:\n\n"
543        "\t%s();\n\n"
544        "\tWith the parameter:\n\n"
545        "\t%s\n\n"
546        "\tbeing NULL. Please fix your program.", function, sparam);
547    if (getenv("ECORE_ERROR_ABORT")) abort();
548 }
549
550 EAPI void
551 _ecore_magic_fail(const void *d,
552                   Ecore_Magic m,
553                   Ecore_Magic req_m,
554                   const char *fname __UNUSED__)
555 {
556    ERR("\n"
557        "*** ECORE ERROR: Ecore Magic Check Failed!!!\n"
558        "*** IN FUNCTION: %s()", fname);
559    if (!d)
560      ERR("  Input handle pointer is NULL!");
561    else if (m == ECORE_MAGIC_NONE)
562      ERR("  Input handle has already been freed!");
563    else if (m != req_m)
564      ERR("  Input handle is wrong type\n"
565          "    Expected: %08x - %s\n"
566          "    Supplied: %08x - %s",
567          (unsigned int)req_m, _ecore_magic_string_get(req_m),
568          (unsigned int)m, _ecore_magic_string_get(m));
569    ERR("*** NAUGHTY PROGRAMMER!!!\n"
570        "*** SPANK SPANK SPANK!!!\n"
571        "*** Now go fix your code. Tut tut tut!");
572    if (getenv("ECORE_ERROR_ABORT")) abort();
573 }
574
575 static const char *
576 _ecore_magic_string_get(Ecore_Magic m)
577 {
578    switch (m)
579      {
580       case ECORE_MAGIC_NONE:
581         return "None (Freed Object)";
582         break;
583
584       case ECORE_MAGIC_EXE:
585         return "Ecore_Exe (Executable)";
586         break;
587
588       case ECORE_MAGIC_TIMER:
589         return "Ecore_Timer (Timer)";
590         break;
591
592       case ECORE_MAGIC_IDLER:
593         return "Ecore_Idler (Idler)";
594         break;
595
596       case ECORE_MAGIC_IDLE_ENTERER:
597         return "Ecore_Idle_Enterer (Idler Enterer)";
598         break;
599
600       case ECORE_MAGIC_IDLE_EXITER:
601         return "Ecore_Idle_Exiter (Idler Exiter)";
602         break;
603
604       case ECORE_MAGIC_FD_HANDLER:
605         return "Ecore_Fd_Handler (Fd Handler)";
606         break;
607
608       case ECORE_MAGIC_WIN32_HANDLER:
609         return "Ecore_Win32_Handler (Win32 Handler)";
610         break;
611
612       case ECORE_MAGIC_EVENT_HANDLER:
613         return "Ecore_Event_Handler (Event Handler)";
614         break;
615
616       case ECORE_MAGIC_EVENT:
617         return "Ecore_Event (Event)";
618         break;
619
620       default:
621         return "<UNKNOWN>";
622      }
623 }
624
625 /* fps debug calls - for debugging how much time your app actually spends */
626 /* "running" (and the inverse being time spent running)... this does not */
627 /* account for other apps and multitasking... */
628
629 static int _ecore_fps_debug_init_count = 0;
630 static int _ecore_fps_debug_fd = -1;
631 unsigned int *_ecore_fps_runtime_mmap = NULL;
632
633 void
634 _ecore_fps_debug_init(void)
635 {
636    char buf[PATH_MAX];
637    const char *tmp;
638    int pid;
639
640    _ecore_fps_debug_init_count++;
641    if (_ecore_fps_debug_init_count > 1) return;
642
643 #ifndef HAVE_EVIL
644    tmp = "/tmp";
645 #else
646    tmp = evil_tmpdir_get ();
647 #endif /* HAVE_EVIL */
648    pid = (int)getpid();
649    snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
650    _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
651    if (_ecore_fps_debug_fd < 0)
652      {
653         unlink(buf);
654         _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
655      }
656    if (_ecore_fps_debug_fd >= 0)
657      {
658         unsigned int zero = 0;
659         char *buf2 = (char *)&zero;
660         ssize_t todo = sizeof(unsigned int);
661
662         while (todo > 0)
663           {
664              ssize_t r = write(_ecore_fps_debug_fd, buf2, todo);
665              if (r > 0)
666                {
667                   todo -= r;
668                   buf2 += r;
669                }
670              else if ((r < 0) && (errno == EINTR))
671                continue;
672              else
673                {
674                   ERR("could not write to file '%s' fd %d: %s",
675                       tmp, _ecore_fps_debug_fd, strerror(errno));
676                   close(_ecore_fps_debug_fd);
677                   _ecore_fps_debug_fd = -1;
678                   return;
679                }
680           }
681         _ecore_fps_runtime_mmap = mmap(NULL, sizeof(unsigned int),
682                                        PROT_READ | PROT_WRITE,
683                                        MAP_SHARED,
684                                        _ecore_fps_debug_fd, 0);
685         if (_ecore_fps_runtime_mmap == MAP_FAILED)
686           _ecore_fps_runtime_mmap = NULL;
687      }
688 }
689
690 void
691 _ecore_fps_debug_shutdown(void)
692 {
693    _ecore_fps_debug_init_count--;
694    if (_ecore_fps_debug_init_count > 0) return;
695    if (_ecore_fps_debug_fd >= 0)
696      {
697         char buf[4096];
698         const char *tmp;
699         int pid;
700
701 #ifndef HAVE_EVIL
702         tmp = "/tmp";
703 #else
704         tmp = (char *)evil_tmpdir_get ();
705 #endif /* HAVE_EVIL */
706         pid = (int)getpid();
707         snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
708         unlink(buf);
709         if (_ecore_fps_runtime_mmap)
710           {
711              munmap(_ecore_fps_runtime_mmap, sizeof(int));
712              _ecore_fps_runtime_mmap = NULL;
713           }
714         close(_ecore_fps_debug_fd);
715         _ecore_fps_debug_fd = -1;
716      }
717 }
718
719 void
720 _ecore_fps_debug_runtime_add(double t)
721 {
722    if ((_ecore_fps_debug_fd >= 0) &&
723        (_ecore_fps_runtime_mmap))
724      {
725         unsigned int tm;
726
727         tm = (unsigned int)(t * 1000000.0);
728         /* i know its not 100% theoretically guaranteed, but i'd say a write */
729         /* of an int could be considered atomic for all practical purposes */
730         /* oh and since this is cumulative, 1 second = 1,000,000 ticks, so */
731         /* this can run for about 4294 seconds becore looping. if you are */
732         /* doing performance testing in one run for over an hour... well */
733         /* time to restart or handle a loop condition :) */
734         *(_ecore_fps_runtime_mmap) += tm;
735      }
736 }
737
738 #if HAVE_MALLINFO
739 static Eina_Bool
740 _ecore_memory_statistic(__UNUSED__ void *data)
741 {
742    struct mallinfo mi;
743    static int uordblks = 0;
744    static int fordblks = 0;
745    Eina_Bool changed = EINA_FALSE;
746
747    mi = mallinfo();
748
749 #define HAS_CHANGED(Global, Local) \
750   if (Global != Local)             \
751     {                              \
752        Global = Local;             \
753        changed = EINA_TRUE;        \
754     }
755
756    HAS_CHANGED(uordblks, mi.uordblks);
757    HAS_CHANGED(fordblks, mi.fordblks);
758
759    if (changed)
760      ERR("[%i] Memory total: %i, free: %i",
761          _ecore_memory_pid,
762          mi.uordblks,
763          mi.fordblks);
764
765    KEEP_MAX(_ecore_memory_max_total, mi.uordblks);
766    KEEP_MAX(_ecore_memory_max_free, mi.fordblks);
767
768    return ECORE_CALLBACK_RENEW;
769 }
770
771 #endif
772
773 static void
774 _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order)
775 {
776    Eina_Bool count;
777
778    eina_lock_take(&_thread_safety);
779
780    count = _thread_cb ? 0 : 1;
781    _thread_cb = eina_list_append(_thread_cb, order);
782    if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
783
784    eina_lock_release(&_thread_safety);
785 }
786
787 static void
788 _thread_safe_cleanup(void *data)
789 {
790    Ecore_Safe_Call *call = data;
791
792    eina_condition_free(&call->c);
793    eina_lock_free(&call->m);
794 }
795
796 void
797 _ecore_main_call_flush(void)
798 {
799    Ecore_Safe_Call *call;
800    Eina_List *callback;
801
802    eina_lock_take(&_thread_safety);
803    callback = _thread_cb;
804    _thread_cb = NULL;
805    eina_lock_release(&_thread_safety);
806
807    EINA_LIST_FREE(callback, call)
808      {
809         if (call->suspend)
810           {
811              eina_lock_take(&_thread_mutex);
812
813              eina_lock_take(&call->m);
814              _thread_id = call->current_id;
815              eina_condition_broadcast(&call->c);
816              eina_lock_release(&call->m);
817
818              while (_thread_id_update != _thread_id)
819                eina_condition_wait(&_thread_cond);
820              eina_lock_release(&_thread_mutex);
821
822              eina_main_loop_define();
823
824              eina_lock_take(&_thread_feedback_mutex);
825
826              _thread_id = -1;
827
828              eina_condition_broadcast(&_thread_feedback_cond);
829              eina_lock_release(&_thread_feedback_mutex);
830
831              _thread_safe_cleanup(call);
832              free(call);
833           }
834         else if (call->sync)
835           {
836              call->data = call->cb.sync(call->data);
837              eina_condition_broadcast(&call->c);
838           }
839         else
840           {
841              call->cb.async(call->data);
842              free(call);
843           }
844      }
845 }
846
847 static void
848 _thread_callback(void        *data __UNUSED__,
849                  void        *buffer __UNUSED__,
850                  unsigned int nbyte __UNUSED__)
851 {
852    _ecore_main_call_flush();
853 }
854