1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <locale.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 
14 #ifdef HAVE_LANGINFO_H
15 # include <langinfo.h>
16 #endif
17 
18 #ifdef _WIN32
19 # include <evil_private.h> /* mmap */
20 #else
21 # include <sys/mman.h>
22 #endif
23 
24 #ifdef _WIN32
25 # include <evil_private.h> /* evil_init/shutdown */
26 #endif
27 #include <Eina.h>
28 #include <Efl.h>
29 
30 #include "Ecore.h"
31 #include "Efl_Core.h"
32 #include "ecore_private.h"
33 #include "../../static_libs/buildsystem/buildsystem.h"
34 
35 #if defined(HAVE_MALLINFO) || defined(HAVE_MALLOC_INFO)
36 #include <malloc.h>
37 #endif
38 
39 #ifndef O_BINARY
40 # define O_BINARY 0
41 #endif
42 
43 static Ecore_Version _version = { VMAJ, VMIN, VMIC, VREV };
44 EAPI Ecore_Version *ecore_version = &_version;
45 
46 EAPI double _efl_startup_time = 0;
47 
48 #if defined(HAVE_MALLINFO) || defined(HAVE_MALLOC_INFO)
49 #define KEEP_MAX(Global, Local) \
50   if (Global < (Local))         \
51     Global = Local;
52 
53 static Eina_Bool _ecore_memory_statistic(void *data);
54 static int _ecore_memory_max_total = 0;
55 static int _ecore_memory_max_free = 0;
56 static pid_t _ecore_memory_pid = 0;
57 #ifdef HAVE_MALLOC_INFO
58 static FILE *_ecore_memory_statistic_file = NULL;
59 #endif
60 #endif
61 
62 static Eina_Bool _no_system_modules = 0xff;
63 
64 static const char *_ecore_magic_string_get(Ecore_Magic m);
65 static int _ecore_init_count = 0;
66 static int _ecore_init_count_threshold = 0;
67 int _ecore_log_dom = -1;
68 int _ecore_fps_debug = 0;
69 
70 extern void _ecore_thread_join();
71 
72 typedef struct _Ecore_Safe_Call Ecore_Safe_Call;
73 struct _Ecore_Safe_Call
74 {
75    union {
76       Ecore_Cb      async;
77       Ecore_Data_Cb sync;
78    } cb;
79    void          *data;
80 
81    Eina_Lock      m;
82    Eina_Condition c;
83 
84    Efl_Domain_Data *eo_domain_data;
85    int              current_id;
86 
87    Eina_Bool      sync : 1;
88    Eina_Bool      suspend : 1;
89 };
90 
91 static void _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order);
92 static void _thread_safe_cleanup(void *data);
93 static void _thread_callback(void        *data,
94                              void        *buffer,
95                              unsigned int nbyte);
96 static Eina_List *_thread_cb = NULL;
97 static Ecore_Pipe *_thread_call = NULL;
98 static Eina_Lock _thread_safety;
99 static const int wakeup = 42;
100 
101 static int _thread_loop = 0;
102 static Eina_Lock _thread_mutex;
103 static Eina_Condition _thread_cond;
104 static Eina_Lock _thread_feedback_mutex;
105 static Eina_Condition _thread_feedback_cond;
106 
107 static Eina_Lock _thread_id_lock;
108 static int _thread_id = -1;
109 static int _thread_id_max = 0;
110 static int _thread_id_update = 0;
111 
112 static Ecore_Power_State _ecore_power_state = ECORE_POWER_STATE_MAINS;
113 static Ecore_Memory_State _ecore_memory_state = ECORE_MEMORY_STATE_NORMAL;
114 
115 #ifdef HAVE_SYSTEMD
116 static void _systemd_watchdog_cb(void *data, const Efl_Event *event);
117 
118 static Efl_Loop_Timer *_systemd_watchdog = NULL;
119 #endif
120 
121 Eina_Lock _ecore_main_loop_lock;
122 int _ecore_main_lock_count;
123 
124 /* OpenBSD does not define CODESET
125  * FIXME ??
126  */
127 
128 #ifndef CODESET
129 # define CODESET "INVALID"
130 #endif
131 
132 static Eina_Prefix *_ecore_pfx = NULL;
133 static Eina_Array *module_list = NULL;
134 
135 static void
ecore_system_modules_load(void)136 ecore_system_modules_load(void)
137 {
138    char buf[PATH_MAX] = "";
139 
140 #ifdef NEED_RUN_IN_TREE
141 #if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
142    if (getuid() == geteuid())
143 #endif
144      {
145         if (getenv("EFL_RUN_IN_TREE"))
146           {
147              struct stat st;
148              snprintf(buf, sizeof(buf), "%s/src/modules/ecore/system",
149                       PACKAGE_BUILD_DIR);
150              if (stat(buf, &st) == 0)
151                {
152                   const char *built_modules[] = {
153 #ifdef HAVE_SYSTEMD
154                      "systemd",
155 #endif
156 #ifdef HAVE_TIZEN_CONFIGURATION_MANAGER
157                      "tizen",
158 #endif
159                      NULL
160                   };
161                   const char **itr;
162                   for (itr = built_modules; *itr != NULL; itr++)
163                     {
164                        bs_mod_get(buf, sizeof(buf), "ecore/system", "system");
165                        module_list = eina_module_list_get(module_list, buf,
166                                                           EINA_FALSE, NULL, NULL);
167                     }
168 
169                   if (module_list)
170                     eina_module_list_load(module_list);
171                   return;
172                }
173           }
174      }
175 #endif
176 
177    snprintf(buf, sizeof(buf), "%s/ecore/system",
178             eina_prefix_lib_get(_ecore_pfx));
179    module_list = eina_module_arch_list_get(module_list, buf, MODULE_ARCH);
180 
181    // XXX: MODFIX: do not list ALL modules and load them ALL! this is
182    // just polluting memory pages and I/O with modules and code that
183    // is then never used. detetc the module we need to use them use
184    // that. if anything load each module, have it do a detect and if
185    // it fails UNLOAD and try the next one.
186    eina_module_list_load(module_list);
187 }
188 
189 static void
ecore_system_modules_unload(void)190 ecore_system_modules_unload(void)
191 {
192    if (module_list)
193      {
194         eina_module_list_free(module_list);
195         eina_array_free(module_list);
196         module_list = NULL;
197      }
198 }
199 
200 static void
_efl_first_loop_iterate(void * data,const Efl_Event * event)201 _efl_first_loop_iterate(void *data, const Efl_Event *event)
202 {
203    double end = ecore_time_unix_get();
204    char *first = data;
205 
206    switch (*first)
207      {
208       case 'A': abort();
209       case 'E':
210       case 'D': exit(-1);
211       case 'T': fprintf(stderr, "Loop started: '%f' - '%f' = '%f' sec\n", end, _efl_startup_time, end - _efl_startup_time);
212          break;
213      }
214    efl_event_callback_del(event->object, EFL_APP_EVENT_RESUME,
215                           _efl_first_loop_iterate, data);
216 }
217 
218 EAPI void
ecore_app_no_system_modules(void)219 ecore_app_no_system_modules(void)
220 {
221    _no_system_modules = EINA_TRUE;
222 }
223 
224 EAPI int
ecore_init(void)225 ecore_init(void)
226 {
227    if (++_ecore_init_count != 1)
228      return _ecore_init_count;
229 
230    /* make sure libecore is linked to libefl - workaround gcc bug */
231    __efl_internal_init();
232 
233    setlocale(LC_CTYPE, "");
234    /*
235       if (strcmp(nl_langinfo(CODESET), "UTF-8"))
236       {
237         WRN("Not a utf8 locale!");
238       }
239     */
240 #ifdef _WIN32
241    if (!evil_init())
242      return --_ecore_init_count;
243 #endif
244    if (!eina_init())
245      goto shutdown_evil;
246    eina_evlog(">RUN", NULL, 0.0, NULL);
247    _ecore_log_dom = eina_log_domain_register("ecore", ECORE_DEFAULT_LOG_COLOR);
248    if (_ecore_log_dom < 0)
249      {
250         EINA_LOG_ERR("Ecore was unable to create a log domain.");
251         goto shutdown_log_dom;
252      }
253    _ecore_animator_init();
254 
255    _ecore_pfx = eina_prefix_new(NULL, ecore_init,
256                                 "ECORE", "ecore", "checkme",
257                                 PACKAGE_BIN_DIR, PACKAGE_LIB_DIR,
258                                 PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
259    if (!_ecore_pfx)
260      {
261         ERR("Could not get ecore installation prefix");
262         goto shutdown_log_dom;
263      }
264 
265    efl_object_init();
266 
267    if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
268    if (_ecore_fps_debug) _ecore_fps_debug_init();
269    if (!ecore_mempool_init()) goto shutdown_mempool;
270    _ecore_main_loop_init();
271    if (!_ecore_event_init()) goto shutdown_event;
272 
273    _ecore_signal_init();
274    _ecore_exe_init();
275    _ecore_thread_init();
276    _ecore_job_init();
277    _ecore_time_init();
278 
279    eina_lock_new(&_thread_mutex);
280    eina_condition_new(&_thread_cond, &_thread_mutex);
281    eina_lock_new(&_thread_feedback_mutex);
282    eina_condition_new(&_thread_feedback_cond, &_thread_feedback_mutex);
283    _thread_call = _ecore_pipe_add(_thread_callback, NULL);
284    eina_lock_new(&_thread_safety);
285 
286    eina_lock_new(&_thread_id_lock);
287 
288    eina_lock_new(&_ecore_main_loop_lock);
289 
290 #if defined(GLIB_INTEGRATION_ALWAYS)
291    if (_ecore_glib_always_integrate) ecore_main_loop_glib_integrate();
292 #endif
293 
294 #if defined(HAVE_MALLINFO) || defined(HAVE_MALLOC_INFO)
295    if (getenv("ECORE_MEM_STAT"))
296      {
297 #ifdef HAVE_MALLOC_INFO
298        char tmp[1024];
299 
300        snprintf(tmp, sizeof(tmp), "ecore_mem_stat.%i", getpid());
301        _ecore_memory_statistic_file = fopen(tmp, "wb");
302 #endif
303         _ecore_memory_pid = getpid();
304         ecore_poller_add(ECORE_POLLER_CORE, 1, _ecore_memory_statistic, NULL);
305         _ecore_memory_statistic(NULL);
306      }
307 #endif
308 
309 #ifdef HAVE_SYSTEMD
310    if (getenv("WATCHDOG_USEC"))
311      {
312         double sec = ((double) atoi(getenv("WATCHDOG_USEC"))) / 1000 / 1000;
313 
314         _systemd_watchdog =
315            efl_add(EFL_LOOP_TIMER_CLASS, efl_main_loop_get(),
316                    efl_loop_timer_interval_set(efl_added, sec / 2),
317                    efl_event_callback_add(efl_added,
318                                           EFL_LOOP_TIMER_EVENT_TIMER_TICK,
319                                           _systemd_watchdog_cb, NULL));
320         unsetenv("WATCHDOG_USEC");
321 
322         INF("Setup systemd watchdog to : %f", sec);
323         _systemd_watchdog_cb(NULL, NULL);
324      }
325 #endif
326 
327    if (_no_system_modules == 0xff)
328      {
329         const char *s = getenv("ECORE_NO_SYSTEM_MODULES");
330         if (s) _no_system_modules = atoi(s);
331         else _no_system_modules = EINA_FALSE;
332      }
333 
334    if (!_no_system_modules)
335      ecore_system_modules_load();
336    if (getenv("EFL_FIRST_LOOP"))
337      efl_event_callback_add(efl_main_loop_get(),
338                             EFL_APP_EVENT_RESUME,
339                             _efl_first_loop_iterate,
340                             getenv("EFL_FIRST_LOOP"));
341    _ecore_init_count_threshold = _ecore_init_count;
342 
343    eina_log_timing(_ecore_log_dom,
344                    EINA_LOG_STATE_STOP,
345                    EINA_LOG_STATE_INIT);
346 
347    return _ecore_init_count;
348 
349 shutdown_event:
350    _ecore_event_shutdown();
351    _ecore_main_shutdown();
352 shutdown_mempool:
353    ecore_mempool_shutdown();
354    efl_object_shutdown();
355 shutdown_log_dom:
356    eina_shutdown();
357 shutdown_evil:
358 #ifdef _WIN32
359    evil_shutdown();
360 #endif
361 
362    return --_ecore_init_count;
363 }
364 
365 EAPI int
ecore_shutdown(void)366 ecore_shutdown(void)
367 {
368      Ecore_Pipe *p;
369    /*
370     * take a lock here because _ecore_event_shutdown() does callbacks
371     */
372      if (_ecore_init_count <= 0)
373        {
374           ERR("Init count not greater than 0 in shutdown.");
375           return 0;
376        }
377      if (_ecore_init_count-- != _ecore_init_count_threshold)
378        goto end;
379      efl_event_callback_call(efl_main_loop_get(), EFL_APP_EVENT_TERMINATE, NULL);
380 
381      ecore_system_modules_unload();
382 
383      eina_log_timing(_ecore_log_dom,
384                      EINA_LOG_STATE_START,
385                      EINA_LOG_STATE_SHUTDOWN);
386 
387 #ifdef HAVE_SYSTEMD
388      if (_systemd_watchdog)
389        {
390           efl_del(_systemd_watchdog);
391           _systemd_watchdog = NULL;
392        }
393 #endif
394 
395      if (_ecore_fps_debug) _ecore_fps_debug_shutdown();
396      _ecore_poller_shutdown();
397      _ecore_animator_shutdown();
398      _ecore_glib_shutdown();
399      _ecore_job_shutdown();
400      _ecore_thread_shutdown();
401 
402    /* this looks horrible - a hack for now, but something to note. as
403     * we delete the _thread_call pipe a thread COULD be doing
404     * ecore_pipe_write() or what not to it at the same time - we
405     * must ensure all possible users of this _thread_call are finished
406     * and exited before we delete it here */
407    /*
408     * ok - this causes other valgrind complaints regarding glib aquiring
409     * locks internally. so fix bug a or bug b. let's leave the original
410     * bug in then and leave this as a note for now
411     */
412    /*
413     * It should be fine now as we do wait for thread to shutdown before
414     * we try to destroy the pipe.
415     */
416      _ecore_pipe_wait(_thread_call, 1, 0);
417      p = _thread_call;
418      _thread_call = NULL;
419      _ecore_pipe_wait(p, 1, 0);
420      _ecore_pipe_del(p);
421      eina_lock_free(&_thread_safety);
422      eina_condition_free(&_thread_cond);
423      eina_lock_free(&_thread_mutex);
424      eina_condition_free(&_thread_feedback_cond);
425      eina_lock_free(&_thread_feedback_mutex);
426      eina_lock_free(&_thread_id_lock);
427 
428      _ecore_exe_shutdown();
429      _ecore_event_shutdown();
430      _ecore_main_shutdown();
431      _ecore_signal_shutdown();
432 
433      _ecore_main_loop_shutdown();
434 
435 #if defined(HAVE_MALLINFO) || defined(HAVE_MALLOC_INFO)
436      if (getenv("ECORE_MEM_STAT"))
437        {
438           _ecore_memory_statistic(NULL);
439 
440           ERR("[%i] Memory MAX total: %i, free: %i",
441               _ecore_memory_pid,
442               _ecore_memory_max_total,
443               _ecore_memory_max_free);
444 
445 
446 #ifdef HAVE_MALLOC_INFO
447           fclose(_ecore_memory_statistic_file);
448           _ecore_memory_statistic_file = NULL;
449 #endif
450        }
451 #endif
452      ecore_mempool_shutdown();
453      eina_log_domain_unregister(_ecore_log_dom);
454      _ecore_log_dom = -1;
455 
456      eina_prefix_free(_ecore_pfx);
457      _ecore_pfx = NULL;
458 
459      efl_object_shutdown();
460 
461      eina_evlog("<RUN", NULL, 0.0, NULL);
462      eina_shutdown();
463 #ifdef _WIN32
464      evil_shutdown();
465 #endif
466 
467  end:
468      return _ecore_init_count;
469 }
470 
471 static unsigned int _ecore_init_ex = 0;
472 
473 EAPI unsigned int
ecore_init_ex(int argc,char ** argv)474 ecore_init_ex(int argc, char **argv)
475 {
476    if (_ecore_init_ex++ != 0) return _ecore_init_ex;
477 
478    ecore_init();
479    ecore_loop_arguments_send(argc,
480                              (argc > 0) ? ((const char **)argv) : NULL);
481    ecore_app_args_set(argc, (const char**) argv);
482 
483    return _ecore_init_ex;
484 }
485 
486 EAPI unsigned int
ecore_shutdown_ex(void)487 ecore_shutdown_ex(void)
488 {
489    if (--_ecore_init_ex != 0) return _ecore_init_ex;
490 
491    ecore_shutdown();
492 
493    return _ecore_init_ex;
494 }
495 
496 struct _Ecore_Fork_Cb
497 {
498    Ecore_Cb func;
499    void *data;
500    Eina_Bool delete_me : 1;
501 };
502 
503 typedef struct _Ecore_Fork_Cb Ecore_Fork_Cb;
504 
505 static int fork_cbs_walking = 0;
506 static Eina_List *fork_cbs = NULL;
507 
508 EAPI Eina_Bool
ecore_fork_reset_callback_add(Ecore_Cb func,const void * data)509 ecore_fork_reset_callback_add(Ecore_Cb func, const void *data)
510 {
511    Ecore_Fork_Cb *fcb;
512 
513    if (!func) return EINA_FALSE;
514    fcb = calloc(1, sizeof(Ecore_Fork_Cb));
515    if (!fcb) return EINA_FALSE;
516    fcb->func = func;
517    fcb->data = (void *)data;
518    fork_cbs = eina_list_append(fork_cbs, fcb);
519    return EINA_TRUE;
520 }
521 
522 EAPI Eina_Bool
ecore_fork_reset_callback_del(Ecore_Cb func,const void * data)523 ecore_fork_reset_callback_del(Ecore_Cb func, const void *data)
524 {
525    Eina_List *l;
526    Ecore_Fork_Cb *fcb;
527 
528    EINA_LIST_FOREACH(fork_cbs, l, fcb)
529      {
530         if ((fcb->func == func) && (fcb->data == data))
531           {
532              if (!fork_cbs_walking)
533                {
534                   fork_cbs = eina_list_remove_list(fork_cbs, l);
535                   free(fcb);
536                }
537              else
538                fcb->delete_me = EINA_TRUE;
539              return EINA_TRUE;
540           }
541      }
542    return EINA_FALSE;
543 }
544 
545 EAPI void
ecore_fork_reset(void)546 ecore_fork_reset(void)
547 {
548    Eina_List *l, *ln;
549    Ecore_Fork_Cb *fcb;
550 
551    eina_debug_fork_reset();
552 
553    eina_main_loop_define();
554    eina_lock_take(&_thread_safety);
555 
556    ecore_pipe_del(_thread_call);
557    _thread_call = ecore_pipe_add(_thread_callback, NULL);
558    /* If there was something in the pipe, trigger a wakeup again */
559    if (_thread_cb)
560      {
561         Ecore_Safe_Call *call;
562 
563         EINA_LIST_FOREACH_SAFE(_thread_cb, l, ln, call)
564           {
565              //if something is supsend, then the mainloop will be blocked until until thread is calling ecore_thread_main_loop_end()
566              //if something tries to join a thread as callback, ensure that we remove this
567              if (call->suspend || (call->cb.async == (Ecore_Cb)&_ecore_thread_join))
568                {
569                   _thread_cb = eina_list_remove_list(_thread_cb, l);
570                   free(call);
571                }
572           }
573         if (_thread_cb) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
574      }
575 
576    eina_lock_release(&_thread_safety);
577 
578    // should this be done withing the eina lock stuff?
579    fork_cbs_walking++;
580    EINA_LIST_FOREACH(fork_cbs, l, fcb)
581      {
582         fcb->func(fcb->data);
583      }
584    fork_cbs_walking--;
585 
586    EINA_LIST_FOREACH_SAFE(fork_cbs, l, ln, fcb)
587      {
588         if (fcb->delete_me)
589           {
590              fork_cbs = eina_list_remove_list(fork_cbs, l);
591              free(fcb);
592           }
593      }
594 
595 #ifdef HAVE_SYSTEMD
596    unsetenv("NOTIFY_SOCKET");
597 #endif
598 }
599 
600 EAPI void
ecore_main_loop_thread_safe_call_async(Ecore_Cb callback,void * data)601 ecore_main_loop_thread_safe_call_async(Ecore_Cb callback,
602                                        void    *data)
603 {
604    Ecore_Safe_Call *order;
605 
606    if (!callback) return;
607 
608    if (eina_main_loop_is())
609      {
610         callback(data);
611         return;
612      }
613 
614    order = malloc(sizeof (Ecore_Safe_Call));
615    if (!order) return;
616 
617    order->cb.async = callback;
618    order->data = data;
619    order->sync = EINA_FALSE;
620    order->suspend = EINA_FALSE;
621 
622    _ecore_main_loop_thread_safe_call(order);
623 }
624 
625 EAPI void *
ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback,void * data)626 ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback,
627                                       void         *data)
628 {
629    Ecore_Safe_Call *order;
630    void *ret;
631 
632    if (!callback) return NULL;
633 
634    if (eina_main_loop_is())
635      {
636         return callback(data);
637      }
638 
639    order = malloc(sizeof (Ecore_Safe_Call));
640    if (!order) return NULL;
641 
642    order->cb.sync = callback;
643    order->data = data;
644    eina_lock_new(&order->m);
645    eina_condition_new(&order->c, &order->m);
646    order->sync = EINA_TRUE;
647    order->suspend = EINA_FALSE;
648 
649    eina_lock_take(&order->m);
650    _ecore_main_loop_thread_safe_call(order);
651    eina_condition_wait(&order->c);
652    eina_lock_release(&order->m);
653 
654    ret = order->data;
655 
656    order->sync = EINA_FALSE;
657    order->cb.async = _thread_safe_cleanup;
658    order->data = order;
659 
660    _ecore_main_loop_thread_safe_call(order);
661 
662    return ret;
663 }
664 
665 EAPI void
ecore_main_loop_thread_safe_call_wait(double wait)666 ecore_main_loop_thread_safe_call_wait(double wait)
667 {
668    ecore_pipe_wait(_thread_call, 1, wait);
669 }
670 
671 static Efl_Id_Domain _ecore_main_domain = EFL_ID_DOMAIN_INVALID;
672 
673 EAPI int
ecore_thread_main_loop_begin(void)674 ecore_thread_main_loop_begin(void)
675 {
676    Ecore_Safe_Call *order;
677 
678    if (eina_main_loop_is())
679      {
680         return ++_thread_loop;
681      }
682 
683    order = calloc(1, sizeof (Ecore_Safe_Call));
684    if (!order) return -1;
685 
686    eina_lock_take(&_thread_id_lock);
687    order->current_id = ++_thread_id_max;
688    if (order->current_id < 0)
689      {
690         _thread_id_max = 0;
691         order->current_id = ++_thread_id_max;
692      }
693    eina_lock_release(&_thread_id_lock);
694 
695    eina_lock_new(&order->m);
696    eina_condition_new(&order->c, &order->m);
697    order->suspend = EINA_TRUE;
698    order->eo_domain_data = NULL;
699 
700    _ecore_main_loop_thread_safe_call(order);
701 
702    eina_lock_take(&order->m);
703    while (order->current_id != _thread_id)
704      eina_condition_wait(&order->c);
705 
706    if (order->eo_domain_data)
707      {
708         _ecore_main_domain =
709           efl_domain_data_adopt(order->eo_domain_data);
710         if (_ecore_main_domain == EFL_ID_DOMAIN_INVALID)
711           ERR("Cannot adopt mainloop eo domain");
712      }
713 
714    eina_lock_release(&order->m);
715 
716    eina_main_loop_define();
717 
718    _thread_loop = 1;
719 
720    return _thread_loop;
721 }
722 
723 EAPI int
ecore_thread_main_loop_end(void)724 ecore_thread_main_loop_end(void)
725 {
726    int current_id;
727 
728    if (_thread_loop == 0)
729      {
730         ERR("the main loop is not locked ! No matching call to ecore_thread_main_loop_begin().");
731         return -1;
732      }
733 
734    /* until we unlock the main loop, this thread has the main loop id */
735    if (!eina_main_loop_is())
736      {
737         ERR("Not in a locked thread !");
738         return -1;
739      }
740 
741    _thread_loop--;
742    if (_thread_loop > 0)
743      return _thread_loop;
744 
745    if (_ecore_main_domain != EFL_ID_DOMAIN_INVALID)
746      {
747         efl_domain_data_return(_ecore_main_domain);
748         _ecore_main_domain = EFL_ID_DOMAIN_INVALID;
749      }
750 
751    current_id = _thread_id;
752 
753    eina_lock_take(&_thread_mutex);
754    _thread_id_update = _thread_id;
755    eina_condition_broadcast(&_thread_cond);
756    eina_lock_release(&_thread_mutex);
757 
758    eina_lock_take(&_thread_feedback_mutex);
759    while (current_id == _thread_id && _thread_id != -1)
760      eina_condition_wait(&_thread_feedback_cond);
761    eina_lock_release(&_thread_feedback_mutex);
762 
763    return 0;
764 }
765 
766 EAPI void
ecore_print_warning(const char * function EINA_UNUSED,const char * sparam EINA_UNUSED)767 ecore_print_warning(const char *function EINA_UNUSED,
768                     const char *sparam EINA_UNUSED)
769 {
770    WRN("***** Developer Warning ***** :\n"
771        "\tThis program is calling:\n\n"
772        "\t%s();\n\n"
773        "\tWith the parameter:\n\n"
774        "\t%s\n\n"
775        "\tbeing NULL. Please fix your program.", function, sparam);
776    if (getenv("ECORE_ERROR_ABORT")) abort();
777 }
778 
779 EAPI void
_ecore_magic_fail(const void * d,Ecore_Magic m,Ecore_Magic req_m,const char * fname EINA_UNUSED)780 _ecore_magic_fail(const void *d,
781                   Ecore_Magic m,
782                   Ecore_Magic req_m,
783                   const char *fname EINA_UNUSED)
784 {
785    ERR("*** ECORE ERROR: Ecore Magic Check Failed!!! in: %s()", fname);
786    if (!d)
787      ERR("    Input handle pointer is NULL!");
788    else if (m == ECORE_MAGIC_NONE)
789      ERR("    Input handle has already been freed!");
790    else if (m != req_m)
791      ERR("    Input handle is wrong type\n"
792          "      Expected: %08x - %s\n"
793          "      Supplied: %08x - %s",
794          (unsigned int)req_m, _ecore_magic_string_get(req_m),
795          (unsigned int)m, _ecore_magic_string_get(m));
796 
797    if (getenv("ECORE_ERROR_ABORT")) abort();
798 }
799 
800 static const char *
_ecore_magic_string_get(Ecore_Magic m)801 _ecore_magic_string_get(Ecore_Magic m)
802 {
803    switch (m)
804      {
805       case ECORE_MAGIC_NONE:
806         return "None (Freed Object)";
807         break;
808 
809       case ECORE_MAGIC_EXE:
810         return "Ecore_Exe (Executable)";
811         break;
812 
813       case ECORE_MAGIC_TIMER:
814         return "Ecore_Timer (Timer)";
815         break;
816 
817       case ECORE_MAGIC_IDLER:
818         return "Ecore_Idler (Idler)";
819         break;
820 
821       case ECORE_MAGIC_IDLE_ENTERER:
822         return "Ecore_Idle_Enterer (Idler Enterer)";
823         break;
824 
825       case ECORE_MAGIC_IDLE_EXITER:
826         return "Ecore_Idle_Exiter (Idler Exiter)";
827         break;
828 
829       case ECORE_MAGIC_FD_HANDLER:
830         return "Ecore_Fd_Handler (Fd Handler)";
831         break;
832 
833       case ECORE_MAGIC_WIN32_HANDLER:
834         return "Ecore_Win32_Handler (Win32 Handler)";
835         break;
836 
837       case ECORE_MAGIC_EVENT_HANDLER:
838         return "Ecore_Event_Handler (Event Handler)";
839         break;
840 
841       case ECORE_MAGIC_EVENT:
842         return "Ecore_Event (Event)";
843         break;
844 
845       default:
846         return "<UNKNOWN>";
847      }
848 }
849 
850 /* fps debug calls - for debugging how much time your app actually spends */
851 /* "running" (and the inverse being time spent running)... this does not */
852 /* account for other apps and multitasking... */
853 
854 static int _ecore_fps_debug_init_count = 0;
855 static int _ecore_fps_debug_fd = -1;
856 unsigned int *_ecore_fps_runtime_mmap = NULL;
857 
858 void
_ecore_fps_debug_init(void)859 _ecore_fps_debug_init(void)
860 {
861    char buf[PATH_MAX];
862    const char *tmp;
863    int pid;
864 
865    _ecore_fps_debug_init_count++;
866    if (_ecore_fps_debug_init_count > 1) return;
867 
868    tmp = eina_environment_tmp_get();
869    pid = (int)getpid();
870    snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
871    _ecore_fps_debug_fd = open(buf, O_CREAT | O_BINARY | O_TRUNC | O_RDWR, 0644);
872    if (_ecore_fps_debug_fd < 0)
873      {
874         unlink(buf);
875         _ecore_fps_debug_fd = open(buf, O_CREAT | O_BINARY | O_TRUNC | O_RDWR, 0644);
876      }
877    if (_ecore_fps_debug_fd >= 0)
878      {
879         unsigned int zero = 0;
880         char *buf2 = (char *)&zero;
881         ssize_t todo = sizeof(unsigned int);
882 
883         while (todo > 0)
884           {
885              ssize_t r = write(_ecore_fps_debug_fd, buf2, todo);
886              if (r > 0)
887                {
888                   todo -= r;
889                   buf2 += r;
890                }
891              else if ((r < 0) && (errno == EINTR))
892                continue;
893              else
894                {
895                   ERR("could not write to file '%s' fd %d: %s",
896                       tmp, _ecore_fps_debug_fd, strerror(errno));
897                   close(_ecore_fps_debug_fd);
898                   _ecore_fps_debug_fd = -1;
899                   return;
900                }
901           }
902         _ecore_fps_runtime_mmap = mmap(NULL, sizeof(unsigned int),
903                                        PROT_READ | PROT_WRITE,
904                                        MAP_SHARED,
905                                        _ecore_fps_debug_fd, 0);
906         if (_ecore_fps_runtime_mmap == MAP_FAILED)
907           _ecore_fps_runtime_mmap = NULL;
908      }
909 }
910 
911 void
_ecore_fps_debug_shutdown(void)912 _ecore_fps_debug_shutdown(void)
913 {
914    _ecore_fps_debug_init_count--;
915    if (_ecore_fps_debug_init_count > 0) return;
916    if (_ecore_fps_debug_fd >= 0)
917      {
918         char buf[4096];
919         int pid;
920 
921         pid = (int)getpid();
922         snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i",
923                  eina_environment_tmp_get(), pid);
924         unlink(buf);
925         if (_ecore_fps_runtime_mmap)
926           {
927              munmap(_ecore_fps_runtime_mmap, sizeof(unsigned int));
928              _ecore_fps_runtime_mmap = NULL;
929           }
930         close(_ecore_fps_debug_fd);
931         _ecore_fps_debug_fd = -1;
932      }
933 }
934 
935 void
_ecore_fps_debug_runtime_add(double t)936 _ecore_fps_debug_runtime_add(double t)
937 {
938    if ((_ecore_fps_debug_fd >= 0) &&
939        (_ecore_fps_runtime_mmap))
940      {
941         unsigned int tm;
942 
943         tm = (unsigned int)(t * 1000000.0);
944         /* i know its not 100% theoretically guaranteed, but i'd say a write */
945         /* of an int could be considered atomic for all practical purposes */
946         /* oh and since this is cumulative, 1 second = 1,000,000 ticks, so */
947         /* this can run for about 4294 seconds becore looping. if you are */
948         /* doing performance testing in one run for over an hour... well */
949         /* time to restart or handle a loop condition :) */
950         *(_ecore_fps_runtime_mmap) += tm;
951      }
952 }
953 
954 #ifdef HAVE_SYSTEMD
955 static void
_systemd_watchdog_cb(void * data EINA_UNUSED,const Efl_Event * event EINA_UNUSED)956 _systemd_watchdog_cb(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
957 {
958    if (getenv("NOTIFY_SOCKET"))
959      {
960         _ecore_sd_init();
961         if (_ecore_sd_notify) _ecore_sd_notify(0, "WATCHDOG=1");
962      }
963 }
964 #endif
965 
966 #if defined(HAVE_MALLINFO) || defined(HAVE_MALLOC_INFO)
967 static Eina_Bool
_ecore_memory_statistic(EINA_UNUSED void * data)968 _ecore_memory_statistic(EINA_UNUSED void *data)
969 {
970 #ifdef HAVE_MALLOC_INFO
971    static int frame = 0;
972 #endif
973 #ifdef HAVE_MALLINFO
974    struct mallinfo mi;
975    static int uordblks = 0;
976    static int fordblks = 0;
977    Eina_Bool changed = EINA_FALSE;
978 
979    mi = mallinfo();
980 
981 #define HAS_CHANGED(Global, Local) \
982   if (Global != Local)             \
983     {                              \
984        Global = Local;             \
985        changed = EINA_TRUE;        \
986     }
987 
988    HAS_CHANGED(uordblks, mi.uordblks);
989    HAS_CHANGED(fordblks, mi.fordblks);
990 
991    if (changed)
992      ERR("[%i] Memory total: %i, free: %i",
993          _ecore_memory_pid,
994          mi.uordblks,
995          mi.fordblks);
996 
997    KEEP_MAX(_ecore_memory_max_total, mi.uordblks);
998    KEEP_MAX(_ecore_memory_max_free, mi.fordblks);
999 #endif
1000 #ifdef HAVE_MALLOC_INFO
1001    if (frame) fputs("\n", _ecore_memory_statistic_file);
1002    malloc_info(0, _ecore_memory_statistic_file);
1003 #endif
1004 
1005    return ECORE_CALLBACK_RENEW;
1006 }
1007 
1008 #endif
1009 
1010 static void
_ecore_main_loop_thread_safe_call(Ecore_Safe_Call * order)1011 _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order)
1012 {
1013    Eina_Bool count;
1014 
1015    eina_lock_take(&_thread_safety);
1016 
1017    count = _thread_cb ? 0 : 1;
1018    _thread_cb = eina_list_append(_thread_cb, order);
1019    if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
1020 
1021    eina_lock_release(&_thread_safety);
1022 }
1023 
1024 static void
_thread_safe_cleanup(void * data)1025 _thread_safe_cleanup(void *data)
1026 {
1027    Ecore_Safe_Call *call = data;
1028 
1029    eina_condition_free(&call->c);
1030    eina_lock_free(&call->m);
1031 }
1032 
1033 void
_ecore_main_call_flush(void)1034 _ecore_main_call_flush(void)
1035 {
1036    Ecore_Safe_Call *call;
1037    Eina_List *callback;
1038 
1039    eina_lock_take(&_thread_safety);
1040    callback = _thread_cb;
1041    _thread_cb = NULL;
1042    eina_lock_release(&_thread_safety);
1043 
1044    EINA_LIST_FREE(callback, call)
1045      {
1046         if (call->suspend)
1047           {
1048              eina_lock_take(&_thread_mutex);
1049 
1050              eina_lock_take(&call->m);
1051              _thread_id = call->current_id;
1052              call->eo_domain_data = efl_domain_data_get();
1053              eina_condition_broadcast(&call->c);
1054              eina_lock_release(&call->m);
1055 
1056              while (_thread_id_update != _thread_id)
1057                eina_condition_wait(&_thread_cond);
1058              eina_lock_release(&_thread_mutex);
1059 
1060              eina_main_loop_define();
1061 
1062              eina_lock_take(&_thread_feedback_mutex);
1063 
1064              _thread_id = -1;
1065 
1066              eina_condition_broadcast(&_thread_feedback_cond);
1067              eina_lock_release(&_thread_feedback_mutex);
1068 
1069              _thread_safe_cleanup(call);
1070              free(call);
1071           }
1072         else if (call->sync)
1073           {
1074              call->data = call->cb.sync(call->data);
1075              eina_lock_take(&call->m);
1076              eina_condition_broadcast(&call->c);
1077              eina_lock_release(&call->m);
1078           }
1079         else
1080           {
1081              call->cb.async(call->data);
1082              free(call);
1083           }
1084      }
1085 }
1086 
1087 static void
_thread_callback(void * data EINA_UNUSED,void * buffer EINA_UNUSED,unsigned int nbyte EINA_UNUSED)1088 _thread_callback(void        *data EINA_UNUSED,
1089                  void        *buffer EINA_UNUSED,
1090                  unsigned int nbyte EINA_UNUSED)
1091 {
1092    _ecore_main_call_flush();
1093 }
1094 
1095 EAPI Ecore_Power_State
ecore_power_state_get(void)1096 ecore_power_state_get(void)
1097 {
1098    return _ecore_power_state;
1099 }
1100 
1101 EAPI void
ecore_power_state_set(Ecore_Power_State state)1102 ecore_power_state_set(Ecore_Power_State state)
1103 {
1104    if (_ecore_power_state == state) return;
1105    _ecore_power_state = state;
1106    ecore_event_add(ECORE_EVENT_POWER_STATE, NULL, NULL, NULL);
1107 }
1108 
1109 EAPI Ecore_Memory_State
ecore_memory_state_get(void)1110 ecore_memory_state_get(void)
1111 {
1112    return _ecore_memory_state;
1113 }
1114 
1115 EAPI void
ecore_memory_state_set(Ecore_Memory_State state)1116 ecore_memory_state_set(Ecore_Memory_State state)
1117 {
1118    if (_ecore_memory_state == state) return;
1119    _ecore_memory_state = state;
1120    ecore_event_add(ECORE_EVENT_MEMORY_STATE, NULL, NULL, NULL);
1121 }
1122 
1123 #ifdef HAVE_SYSTEMD
1124 static Eina_Module *_libsystemd = NULL;
1125 static Eina_Bool _libsystemd_broken = EINA_FALSE;
1126 
1127 int (*_ecore_sd_notify) (int unset_environment, const char *state) = NULL;
1128 
1129 void
_ecore_sd_init(void)1130 _ecore_sd_init(void)
1131 {
1132    if (_libsystemd_broken) return;
1133    _libsystemd = eina_module_new("libsystemd.so.0");
1134    if (_libsystemd)
1135      {
1136         if (!eina_module_load(_libsystemd))
1137           {
1138              eina_module_free(_libsystemd);
1139              _libsystemd = NULL;
1140           }
1141      }
1142    if (!_libsystemd)
1143      {
1144         _libsystemd_broken = EINA_TRUE;
1145         return;
1146      }
1147    _ecore_sd_notify =
1148      eina_module_symbol_get(_libsystemd, "sd_notify");
1149    if (!_ecore_sd_notify)
1150      {
1151         _ecore_sd_notify = NULL;
1152         eina_module_free(_libsystemd);
1153         _libsystemd = NULL;
1154         _libsystemd_broken = EINA_TRUE;
1155      }
1156 }
1157 #endif
1158