77f486ca3a9c0b4bdfc5ac9080d78a6759ba8830
[profile/ivi/ecore.git] / src / lib / ecore / ecore.c
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
38 static Ecore_Version _version = { VERS_MAJ, VERS_MIN, VERS_MIC, VERS_REV };
39 EAPI Ecore_Version *ecore_version = &_version;
40
41 #define KEEP_MAX(Global, Local)                 \
42    if (Global < (Local))                        \
43      Global = Local;
44
45 static Eina_Bool _ecore_memory_statistic(void *data);
46 static int _ecore_memory_max_total = 0;
47 static int _ecore_memory_max_free = 0;
48 static pid_t _ecore_memory_pid = 0;
49 #endif
50
51 static const char *_ecore_magic_string_get(Ecore_Magic m);
52 static int _ecore_init_count = 0;
53 EAPI int _ecore_log_dom = -1;
54 int _ecore_fps_debug = 0;
55
56 /** OpenBSD does not define CODESET
57  * FIXME ??
58  */
59
60 #ifndef CODESET
61 # define CODESET "INVALID"
62 #endif
63
64 /**
65  * Set up connections, signal handlers, sockets etc.
66  * @return 1 or greater on success, 0 otherwise
67  *
68  * This function sets up all singal handlers and the basic event loop. If it
69  * succeeds, 1 will be returned, otherwise 0 will be returned.
70  *
71  * @code
72  * #include <Ecore.h>
73  *
74  * int main(int argc, char **argv)
75  * {
76  *   if (!ecore_init())
77  *   {
78  *     printf("ERROR: Cannot init Ecore!\n");
79  *     return -1;
80  *   }
81  *   ecore_main_loop_begin();
82  *   ecore_shutdown();
83  * }
84  * @endcode
85  */
86 EAPI int
87 ecore_init(void)
88 {
89    if (++_ecore_init_count != 1)
90      return _ecore_init_count;
91
92 #ifdef HAVE_LOCALE_H
93    setlocale(LC_CTYPE, "");
94 #endif
95    /*
96      if (strcmp(nl_langinfo(CODESET), "UTF-8"))
97      {
98         WRN("Not a utf8 locale!");
99      }
100    */
101 #ifdef HAVE_EVIL
102    if (!evil_init())
103      return --_ecore_init_count;
104 #endif
105    if (!eina_init())
106      goto shutdown_evil;
107    _ecore_log_dom = eina_log_domain_register("Ecore",ECORE_DEFAULT_LOG_COLOR);
108    if (_ecore_log_dom < 0) {
109      EINA_LOG_ERR("Ecore was unable to create a log domain.");
110      goto shutdown_log_dom;
111    }
112    if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
113    if (_ecore_fps_debug) _ecore_fps_debug_init();
114    _ecore_main_loop_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 #if defined(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    _ecore_main_loop_shutdown();
176
177 #if HAVE_MALLINFO
178    if (getenv("ECORE_MEM_STAT"))
179      {
180         _ecore_memory_statistic(NULL);
181
182         ERR("[%i] Memory MAX total: %i, free: %i",
183             _ecore_memory_pid,
184             _ecore_memory_max_total,
185             _ecore_memory_max_free);
186      }
187 #endif
188
189    eina_log_domain_unregister(_ecore_log_dom);
190    _ecore_log_dom = -1;
191    eina_shutdown();
192 #ifdef HAVE_EVIL
193    evil_shutdown();
194 #endif
195
196    return _ecore_init_count;
197 }
198
199 EAPI void
200 ecore_print_warning(const char *function, const char *sparam)
201 {
202    WRN("***** Developer Warning ***** :\n"
203        "\tThis program is calling:\n\n"
204        "\t%s();\n\n"
205        "\tWith the parameter:\n\n"
206        "\t%s\n\n"
207        "\tbeing NULL. Please fix your program.", function, sparam);
208    if (getenv("ECORE_ERROR_ABORT")) abort();
209 }
210
211 EAPI void
212 _ecore_magic_fail(const void *d, Ecore_Magic m, Ecore_Magic req_m, const char *fname)
213 {
214    ERR("\n"
215        "*** ECORE ERROR: Ecore Magic Check Failed!!!\n"
216        "*** IN FUNCTION: %s()", fname);
217    if (!d)
218      ERR("  Input handle pointer is NULL!");
219    else if (m == ECORE_MAGIC_NONE)
220      ERR("  Input handle has already been freed!");
221    else if (m != req_m)
222      ERR("  Input handle is wrong type\n"
223          "    Expected: %08x - %s\n"
224          "    Supplied: %08x - %s",
225          (unsigned int)req_m, _ecore_magic_string_get(req_m),
226          (unsigned int)m, _ecore_magic_string_get(m));
227      ERR("*** NAUGHTY PROGRAMMER!!!\n"
228          "*** SPANK SPANK SPANK!!!\n"
229          "*** Now go fix your code. Tut tut tut!");
230    if (getenv("ECORE_ERROR_ABORT")) abort();
231 }
232
233 static const char *
234 _ecore_magic_string_get(Ecore_Magic m)
235 {
236    switch (m)
237      {
238       case ECORE_MAGIC_NONE:
239         return "None (Freed Object)";
240         break;
241       case ECORE_MAGIC_EXE:
242         return "Ecore_Exe (Executable)";
243         break;
244       case ECORE_MAGIC_TIMER:
245         return "Ecore_Timer (Timer)";
246         break;
247       case ECORE_MAGIC_IDLER:
248         return "Ecore_Idler (Idler)";
249         break;
250       case ECORE_MAGIC_IDLE_ENTERER:
251         return "Ecore_Idle_Enterer (Idler Enterer)";
252         break;
253       case ECORE_MAGIC_IDLE_EXITER:
254         return "Ecore_Idle_Exiter (Idler Exiter)";
255         break;
256       case ECORE_MAGIC_FD_HANDLER:
257         return "Ecore_Fd_Handler (Fd Handler)";
258         break;
259       case ECORE_MAGIC_WIN32_HANDLER:
260         return "Ecore_Win32_Handler (Win32 Handler)";
261         break;
262       case ECORE_MAGIC_EVENT_HANDLER:
263         return "Ecore_Event_Handler (Event Handler)";
264         break;
265       case ECORE_MAGIC_EVENT:
266         return "Ecore_Event (Event)";
267         break;
268       default:
269         return "<UNKNOWN>";
270      };
271 }
272
273 /* fps debug calls - for debugging how much time your app actually spends */
274 /* "running" (and the inverse being time spent running)... this does not */
275 /* account for other apps and multitasking... */
276
277 static int _ecore_fps_debug_init_count = 0;
278 static int _ecore_fps_debug_fd = -1;
279 unsigned int *_ecore_fps_runtime_mmap = NULL;
280
281 void
282 _ecore_fps_debug_init(void)
283 {
284    char  buf[4096];
285    const char *tmp;
286    int   pid;
287
288    _ecore_fps_debug_init_count++;
289    if (_ecore_fps_debug_init_count > 1) return;
290
291 #ifndef HAVE_EVIL
292    tmp = "/tmp";
293 #else
294    tmp = (char *)evil_tmpdir_get ();
295 #endif /* HAVE_EVIL */
296    pid = (int)getpid();
297    snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
298    _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
299    if (_ecore_fps_debug_fd < 0)
300      {
301         unlink(buf);
302         _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
303      }
304    if (_ecore_fps_debug_fd >= 0)
305      {
306         unsigned int zero = 0;
307         char *buf = (char *)&zero;
308         ssize_t todo = sizeof(unsigned int);
309
310         while (todo > 0)
311           {
312              ssize_t r = write(_ecore_fps_debug_fd, buf, todo);
313              if (r > 0)
314                {
315                   todo -= r;
316                   buf += r;
317                }
318              else if ((r < 0) && (errno == EINTR))
319                continue;
320              else
321                {
322                   ERR("could not write to file '%s' fd %d: %s",
323                       tmp, _ecore_fps_debug_fd, strerror(errno));
324                   close(_ecore_fps_debug_fd);
325                   _ecore_fps_debug_fd = -1;
326                   return;
327                }
328           }
329         _ecore_fps_runtime_mmap = mmap(NULL, sizeof(unsigned int),
330                                        PROT_READ | PROT_WRITE,
331                                        MAP_SHARED,
332                                        _ecore_fps_debug_fd, 0);
333         if (_ecore_fps_runtime_mmap == MAP_FAILED)
334           _ecore_fps_runtime_mmap = NULL;
335      }
336 }
337
338 void
339 _ecore_fps_debug_shutdown(void)
340 {
341    _ecore_fps_debug_init_count--;
342    if (_ecore_fps_debug_init_count > 0) return;
343    if (_ecore_fps_debug_fd >= 0)
344      {
345         char buf[4096];
346         const char *tmp;
347         int   pid;
348
349 #ifndef HAVE_EVIL
350    tmp = "/tmp";
351 #else
352    tmp = (char *)evil_tmpdir_get ();
353 #endif /* HAVE_EVIL */
354    pid = (int)getpid();
355         snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
356         unlink(buf);
357         if (_ecore_fps_runtime_mmap)
358           {
359              munmap(_ecore_fps_runtime_mmap, sizeof(int));
360              _ecore_fps_runtime_mmap = NULL;
361           }
362         close(_ecore_fps_debug_fd);
363         _ecore_fps_debug_fd = -1;
364      }
365 }
366
367 void
368 _ecore_fps_debug_runtime_add(double t)
369 {
370    if ((_ecore_fps_debug_fd >= 0) &&
371        (_ecore_fps_runtime_mmap))
372      {
373         unsigned int tm;
374
375         tm = (unsigned int)(t * 1000000.0);
376         /* i know its not 100% theoretically guaranteed, but i'd say a write */
377         /* of an int could be considered atomic for all practical purposes */
378         /* oh and since this is cumulative, 1 second = 1,000,000 ticks, so */
379         /* this can run for about 4294 seconds becore looping. if you are */
380         /* doing performance testing in one run for over an hour... well */
381         /* time to restart or handle a loop condition :) */
382         *(_ecore_fps_runtime_mmap) += tm;
383      }
384 }
385
386 #if HAVE_MALLINFO
387 static Eina_Bool
388 _ecore_memory_statistic(__UNUSED__ void *data)
389 {
390    struct mallinfo mi;
391    static int uordblks = 0;
392    static int fordblks = 0;
393    Eina_Bool changed = EINA_FALSE;
394
395    mi = mallinfo();
396
397 #define HAS_CHANGED(Global, Local)              \
398    if (Global != Local)                         \
399      {                                          \
400         Global = Local;                         \
401         changed = EINA_TRUE;                    \
402      }
403
404    HAS_CHANGED(uordblks, mi.uordblks);
405    HAS_CHANGED(fordblks, mi.fordblks);
406
407    if (changed)
408      ERR("[%i] Memory total: %i, free: %i",
409          _ecore_memory_pid,
410          mi.uordblks,
411          mi.fordblks);
412
413    KEEP_MAX(_ecore_memory_max_total, mi.uordblks);
414    KEEP_MAX(_ecore_memory_max_free, mi.fordblks);
415
416    return ECORE_CALLBACK_RENEW;
417 }
418 #endif