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