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