svn update: 48958 (latest:48959)
[framework/uifw/ecore.git] / src / lib / ecore / ecore.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <fcntl.h>
13 #include <errno.h>
14
15 #ifndef _MSC_VER
16 # include <unistd.h>
17 #endif
18
19 #ifdef HAVE_LOCALE_H
20 # include <locale.h>
21 #endif
22
23 #ifdef HAVE_LANGINFO_H
24 # include <langinfo.h>
25 #endif
26
27 #ifdef HAVE_SYS_MMAN_H
28 # include <sys/mman.h>
29 #endif
30
31 #ifdef HAVE_EVIL
32 # include <Evil.h>
33 #endif
34 #include <Eina.h>
35
36 #include "Ecore.h"
37 #include "ecore_private.h"
38
39 #if HAVE_MALLINFO
40 #include <malloc.h>
41
42 #define KEEP_MAX(Global, Local)                 \
43    if (Global < (Local))                        \
44      Global = Local;
45
46 static int _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 /** OpenBSD does not define CODESET
58  * FIXME ??
59  */
60
61 #ifndef CODESET
62 # define CODESET "INVALID"
63 #endif
64
65 /**
66  * Set up connections, signal handlers, sockets etc.
67  * @return 1 or greater on success, 0 otherwise
68  *
69  * This function sets up all singal handlers and the basic event loop. If it
70  * succeeds, 1 will be returned, otherwise 0 will be returned.
71  *
72  * @code
73  * #include <Ecore.h>
74  *
75  * int main(int argc, char **argv)
76  * {
77  *   if (!ecore_init())
78  *   {
79  *     printf("ERROR: Cannot init Ecore!\n");
80  *     return -1;
81  *   }
82  *   ecore_main_loop_begin();
83  *   ecore_shutdown();
84  * }
85  * @endcode
86  */
87 EAPI int
88 ecore_init(void)
89 {
90    if (++_ecore_init_count != 1)
91      return _ecore_init_count;
92
93 #ifdef HAVE_LOCALE_H
94    setlocale(LC_CTYPE, "");
95 #endif
96    /*
97      if (strcmp(nl_langinfo(CODESET), "UTF-8"))
98      {
99         WRN("Not a utf8 locale!");
100      }
101    */
102 #ifdef HAVE_EVIL
103    if (!evil_init())
104      return --_ecore_init_count;
105 #endif
106    if (!eina_init())
107      goto shutdown_evil;
108    _ecore_log_dom = eina_log_domain_register("Ecore",ECORE_DEFAULT_LOG_COLOR);
109    if (_ecore_log_dom < 0) {
110      EINA_LOG_ERR("Ecore was unable to create a log domain.");
111      goto shutdown_log_dom;
112    }
113    if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
114    if (_ecore_fps_debug) _ecore_fps_debug_init();
115    _ecore_signal_init();
116    _ecore_exe_init();
117    _ecore_thread_init();
118    _ecore_glib_init();
119    _ecore_job_init();
120    _ecore_loop_time = ecore_time_get();
121
122 #if HAVE_MALLINFO
123    if (getenv("ECORE_MEM_STAT"))
124      {
125         _ecore_memory_pid = getpid();
126         ecore_animator_add(_ecore_memory_statistic, NULL);
127      }
128 #endif
129
130 #ifdef GLIB_INTEGRATION_ALWAYS   
131    if (_ecore_glib_always_integrate) ecore_main_loop_glib_integrate();
132 #endif
133    
134    return _ecore_init_count;
135
136  shutdown_log_dom:
137    eina_shutdown();
138  shutdown_evil:
139 #ifdef HAVE_EVIL
140    evil_shutdown();
141 #endif
142    return --_ecore_init_count;
143 }
144
145 /**
146  * Shut down connections, signal handlers sockets etc.
147  *
148  * This function shuts down all things set up in ecore_init() and cleans up all
149  * event queues, handlers, filters, timers, idlers, idle enterers/exiters
150  * etc. set up after ecore_init() was called.
151  *
152  * Do not call this function from any callback that may be called from the main
153  * loop, as the main loop will then fall over and not function properly.
154  */
155 EAPI int
156 ecore_shutdown(void)
157 {
158    if (--_ecore_init_count != 0)
159      return _ecore_init_count;
160
161    if (_ecore_fps_debug) _ecore_fps_debug_shutdown();
162    _ecore_poller_shutdown();
163    _ecore_animator_shutdown();
164    _ecore_glib_shutdown();
165    _ecore_job_shutdown();
166    _ecore_thread_shutdown();
167    _ecore_exe_shutdown();
168    _ecore_idle_enterer_shutdown();
169    _ecore_idle_exiter_shutdown();
170    _ecore_idler_shutdown();
171    _ecore_timer_shutdown();
172    _ecore_event_shutdown();
173    _ecore_main_shutdown();
174    _ecore_signal_shutdown();
175
176 #if HAVE_MALLINFO
177    if (getenv("ECORE_MEM_STAT"))
178      {
179         _ecore_memory_statistic(NULL);
180
181         ERR("[%i] Memory MAX total: %i, free: %i",
182             _ecore_memory_pid,
183             _ecore_memory_max_total,
184             _ecore_memory_max_free);
185      }
186 #endif
187
188    eina_log_domain_unregister(_ecore_log_dom);
189    _ecore_log_dom = -1;
190    eina_shutdown();
191 #ifdef HAVE_EVIL
192    evil_shutdown();
193 #endif
194
195    return _ecore_init_count;
196 }
197
198 EAPI void
199 ecore_print_warning(const char *function, const char *sparam)
200 {
201    WRN("***** Developer Warning ***** :\n"
202        "\tThis program is calling:\n\n"
203        "\t%s();\n\n"
204        "\tWith the parameter:\n\n"
205        "\t%s\n\n"
206        "\tbeing NULL. Please fix your program.", function, sparam);
207    if (getenv("ECORE_ERROR_ABORT")) abort();
208 }
209
210 EAPI void
211 _ecore_magic_fail(const void *d, Ecore_Magic m, Ecore_Magic req_m, const char *fname)
212 {
213    ERR("\n"
214        "*** ECORE ERROR: Ecore Magic Check Failed!!!\n"
215        "*** IN FUNCTION: %s()", fname);
216    if (!d)
217      ERR("  Input handle pointer is NULL!");
218    else if (m == ECORE_MAGIC_NONE)
219      ERR("  Input handle has already been freed!");
220    else if (m != req_m)
221      ERR("  Input handle is wrong type\n"
222          "    Expected: %08x - %s\n"
223          "    Supplied: %08x - %s",
224          (unsigned int)req_m, _ecore_magic_string_get(req_m),
225          (unsigned int)m, _ecore_magic_string_get(m));
226      ERR("*** NAUGHTY PROGRAMMER!!!\n"
227          "*** SPANK SPANK SPANK!!!\n"
228          "*** Now go fix your code. Tut tut tut!");
229    if (getenv("ECORE_ERROR_ABORT")) abort();
230 }
231
232 static const char *
233 _ecore_magic_string_get(Ecore_Magic m)
234 {
235    switch (m)
236      {
237       case ECORE_MAGIC_NONE:
238         return "None (Freed Object)";
239         break;
240       case ECORE_MAGIC_EXE:
241         return "Ecore_Exe (Executable)";
242         break;
243       case ECORE_MAGIC_TIMER:
244         return "Ecore_Timer (Timer)";
245         break;
246       case ECORE_MAGIC_IDLER:
247         return "Ecore_Idler (Idler)";
248         break;
249       case ECORE_MAGIC_IDLE_ENTERER:
250         return "Ecore_Idle_Enterer (Idler Enterer)";
251         break;
252       case ECORE_MAGIC_IDLE_EXITER:
253         return "Ecore_Idle_Exiter (Idler Exiter)";
254         break;
255       case ECORE_MAGIC_FD_HANDLER:
256         return "Ecore_Fd_Handler (Fd Handler)";
257         break;
258       case ECORE_MAGIC_WIN32_HANDLER:
259         return "Ecore_Win32_Handler (Win32 Handler)";
260         break;
261       case ECORE_MAGIC_EVENT_HANDLER:
262         return "Ecore_Event_Handler (Event Handler)";
263         break;
264       case ECORE_MAGIC_EVENT:
265         return "Ecore_Event (Event)";
266         break;
267       default:
268         return "<UNKNOWN>";
269      };
270 }
271
272 /* fps debug calls - for debugging how much time your app actually spends */
273 /* "running" (and the inverse being time spent running)... this does not */
274 /* account for other apps and multitasking... */
275
276 static int _ecore_fps_debug_init_count = 0;
277 static int _ecore_fps_debug_fd = -1;
278 unsigned int *_ecore_fps_runtime_mmap = NULL;
279
280 void
281 _ecore_fps_debug_init(void)
282 {
283    char  buf[4096];
284    const char *tmp;
285    int   pid;
286
287    _ecore_fps_debug_init_count++;
288    if (_ecore_fps_debug_init_count > 1) return;
289
290 #ifndef HAVE_EVIL
291    tmp = "/tmp";
292 #else
293    tmp = (char *)evil_tmpdir_get ();
294 #endif /* HAVE_EVIL */
295    pid = (int)getpid();
296    snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
297    _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
298    if (_ecore_fps_debug_fd < 0)
299      {
300         unlink(buf);
301         _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
302      }
303    if (_ecore_fps_debug_fd >= 0)
304      {
305         unsigned int zero = 0;
306         char *buf = (char *)&zero;
307         ssize_t todo = sizeof(unsigned int);
308
309         while (todo > 0)
310           {
311              ssize_t r = write(_ecore_fps_debug_fd, buf, todo);
312              if (r > 0)
313                {
314                   todo -= r;
315                   buf += r;
316                }
317              else if ((r < 0) && (errno == EINTR))
318                continue;
319              else
320                {
321                   ERR("could not write to file '%s' fd %d: %s",
322                       tmp, _ecore_fps_debug_fd, strerror(errno));
323                   close(_ecore_fps_debug_fd);
324                   _ecore_fps_debug_fd = -1;
325                   return;
326                }
327           }
328         _ecore_fps_runtime_mmap = mmap(NULL, sizeof(unsigned int),
329                                        PROT_READ | PROT_WRITE,
330                                        MAP_SHARED,
331                                        _ecore_fps_debug_fd, 0);
332         if (_ecore_fps_runtime_mmap == MAP_FAILED)
333           _ecore_fps_runtime_mmap = NULL;
334      }
335 }
336
337 void
338 _ecore_fps_debug_shutdown(void)
339 {
340    _ecore_fps_debug_init_count--;
341    if (_ecore_fps_debug_init_count > 0) return;
342    if (_ecore_fps_debug_fd >= 0)
343      {
344         char buf[4096];
345         const char *tmp;
346         int   pid;
347
348 #ifndef HAVE_EVIL
349    tmp = "/tmp";
350 #else
351    tmp = (char *)evil_tmpdir_get ();
352 #endif /* HAVE_EVIL */
353    pid = (int)getpid();
354         snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
355         unlink(buf);
356         if (_ecore_fps_runtime_mmap)
357           {
358              munmap(_ecore_fps_runtime_mmap, sizeof(int));
359              _ecore_fps_runtime_mmap = NULL;
360           }
361         close(_ecore_fps_debug_fd);
362         _ecore_fps_debug_fd = -1;
363      }
364 }
365
366 void
367 _ecore_fps_debug_runtime_add(double t)
368 {
369    if ((_ecore_fps_debug_fd >= 0) &&
370        (_ecore_fps_runtime_mmap))
371      {
372         unsigned int tm;
373
374         tm = (unsigned int)(t * 1000000.0);
375         /* i know its not 100% theoretically guaranteed, but i'd say a write */
376         /* of an int could be considered atomic for all practical purposes */
377         /* oh and since this is cumulative, 1 second = 1,000,000 ticks, so */
378         /* this can run for about 4294 seconds becore looping. if you are */
379         /* doing performance testing in one run for over an hour... well */
380         /* time to restart or handle a loop condition :) */
381         *(_ecore_fps_runtime_mmap) += tm;
382      }
383 }
384
385 #if HAVE_MALLINFO
386 static int
387 _ecore_memory_statistic(__UNUSED__ void *data)
388 {
389    struct mallinfo mi;
390    static int uordblks = 0;
391    static int fordblks = 0;
392    Eina_Bool changed = EINA_FALSE;
393
394    mi = mallinfo();
395
396 #define HAS_CHANGED(Global, Local)              \
397    if (Global != Local)                         \
398      {                                          \
399         Global = Local;                         \
400         changed = EINA_TRUE;                    \
401      }
402
403    HAS_CHANGED(uordblks, mi.uordblks);
404    HAS_CHANGED(fordblks, mi.fordblks);
405
406    if (changed)
407      ERR("[%i] Memory total: %i, free: %i",
408          _ecore_memory_pid,
409          mi.uordblks,
410          mi.fordblks);
411
412    KEEP_MAX(_ecore_memory_max_total, mi.uordblks);
413    KEEP_MAX(_ecore_memory_max_free, mi.fordblks);
414
415    return 1;
416 }
417 #endif