EFL 1.7 svn doobies
[profile/ivi/eina.git] / src / lib / eina_main.c
1 /* EINA - EFL data type library
2  * Copyright (C) 2008 Cedric Bail
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library;
16  * if not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22
23 #include <stdio.h>
24
25 #ifdef EFL_HAVE_WIN32_THREADS
26 # define WIN32_LEAN_AND_MEAN
27 # include <windows.h>
28 # undef WIN32_LEAN_AND_MEAN
29 #endif
30
31 #ifdef EFL_HAVE_THREADS
32 # ifdef HAVE_SYS_TYPES_H
33 #  include <sys/types.h>
34 # endif
35 # ifdef HAVE_UNISTD_H
36 #  include <unistd.h>
37 # endif
38 #endif
39
40 #ifdef HAVE_MCHECK_H
41 # ifdef HAVE_MTRACE
42 #  define MT 1
43 # endif
44 #endif
45
46 #ifdef MT
47 #include <mcheck.h>
48 #endif
49
50 #include "eina_lock.h"
51 #include "eina_config.h"
52 #include "eina_private.h"
53 #include "eina_types.h"
54 #include "eina_main.h"
55 #include "eina_error.h"
56 #include "eina_log.h"
57 #include "eina_hash.h"
58 #include "eina_binshare.h"
59 #include "eina_stringshare.h"
60 #include "eina_ustringshare.h"
61 #include "eina_list.h"
62 #include "eina_matrixsparse.h"
63 #include "eina_array.h"
64 #include "eina_counter.h"
65 #include "eina_benchmark.h"
66 #include "eina_magic.h"
67 #include "eina_rectangle.h"
68 #include "eina_safety_checks.h"
69 #include "eina_inlist.h"
70 #include "eina_inarray.h"
71 #include "eina_value.h"
72 /* no model for now
73 #include "eina_model.h"
74  */
75
76 /*============================================================================*
77 *                                  Local                                     *
78 *============================================================================*/
79
80 /**
81  * @cond LOCAL
82  */
83
84 static Eina_Version _version = { VMAJ, VMIN, VMIC, VREV };
85
86 static int _eina_main_count = 0;
87 #ifdef EFL_HAVE_THREADS
88 static int _eina_main_thread_count = 0;
89 #endif
90 static int _eina_log_dom = -1;
91
92 #ifdef ERR
93 #undef ERR
94 #endif
95 #define ERR(...) EINA_LOG_DOM_ERR(_eina_log_dom, __VA_ARGS__)
96
97 #ifdef DBG
98 #undef DBG
99 #endif
100 #define DBG(...) EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__)
101
102 EAPI Eina_Bool _eina_threads_activated = EINA_FALSE;
103 EAPI Eina_Error EINA_ERROR_NOT_MAIN_LOOP = 0;
104
105 static const char EINA_ERROR_NOT_MAIN_LOOP_STR[] = "Main loop thread check failed.";
106
107 #ifdef EFL_HAVE_THREADS
108 # ifdef _WIN32
109 EAPI DWORD _eina_main_loop;
110 # else
111 EAPI pthread_t _eina_main_loop;
112 # endif
113 static pid_t _eina_pid;
114 #endif
115
116 #ifdef MT
117 static int _mt_enabled = 0;
118 #endif
119
120 #ifdef EFL_HAVE_THREADS
121 EAPI int _eina_threads_debug = 0;
122 # if !defined(_WIN32_WCE) && !defined(_WIN32)
123 EAPI pthread_mutex_t _eina_tracking_lock;
124 EAPI Eina_Inlist *_eina_tracking = NULL;
125 # endif
126 #endif
127
128 /* place module init/shutdown functions here to avoid other modules
129  * calling them by mistake.
130  */
131 #define S(x) extern Eina_Bool eina_ ## x ## _init(void); \
132    extern Eina_Bool eina_ ## x ## _shutdown(void)
133    S(log);
134    S(error);
135    S(safety_checks);
136    S(magic_string);
137    S(iterator);
138    S(accessor);
139    S(inarray);
140    S(array);
141    S(module);
142    S(mempool);
143    S(list);
144    S(binshare);
145    S(stringshare);
146    S(ustringshare);
147    S(matrixsparse);
148    S(convert);
149    S(counter);
150    S(benchmark);
151    S(rectangle);
152    S(strbuf);
153    S(ustrbuf);
154    S(quadtree);
155    S(simple_xml);
156    S(file);
157    S(prefix);
158    S(value);
159 /* no model for now
160    S(model);
161  */
162 #undef S
163
164 struct eina_desc_setup
165 {
166    const char *name;
167    Eina_Bool (*init)(void);
168    Eina_Bool (*shutdown)(void);
169 };
170
171 static const struct eina_desc_setup _eina_desc_setup[] = {
172 #define S(x) {# x, eina_ ## x ## _init, eina_ ## x ## _shutdown}
173    /* log is a special case as it needs printf */
174    S(stringshare),
175    S(error),
176    S(safety_checks),
177    S(magic_string),
178    S(iterator),
179    S(accessor),
180    S(inarray),
181    S(array),
182    S(module),
183    S(mempool),
184    S(list),
185    S(binshare),
186    S(ustringshare),
187    S(matrixsparse),
188    S(convert),
189    S(counter),
190    S(benchmark),
191    S(rectangle),
192    S(strbuf),
193    S(ustrbuf),
194    S(quadtree),
195    S(simple_xml),
196    S(file),
197    S(prefix),
198    S(value),
199 /* no model for now
200    S(model)
201  */
202 #undef S
203 };
204 static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) /
205    sizeof(_eina_desc_setup[0]);
206
207 static void
208 _eina_shutdown_from_desc(const struct eina_desc_setup *itr)
209 {
210    for (itr--; itr >= _eina_desc_setup; itr--)
211      {
212         if (!itr->shutdown())
213            ERR("Problems shutting down eina module '%s', ignored.", itr->name);
214      }
215
216    eina_log_domain_unregister(_eina_log_dom);
217    _eina_log_dom = -1;
218    eina_log_shutdown();
219 }
220
221 /**
222  * @endcond
223  */
224
225 /*============================================================================*
226 *                                 Global                                     *
227 *============================================================================*/
228
229
230 /*============================================================================*
231 *                                   API                                      *
232 *============================================================================*/
233
234 /**
235  * @var eina_version
236  * @brief Eina version (defined at configuration time)
237  */
238 EAPI Eina_Version *eina_version = &_version;
239
240 EAPI int
241 eina_init(void)
242 {
243    const struct eina_desc_setup *itr, *itr_end;
244
245    if (EINA_LIKELY(_eina_main_count > 0))
246       return ++_eina_main_count;
247
248 #ifdef MT
249    if ((getenv("EINA_MTRACE")) && (getenv("MALLOC_TRACE")))
250      {
251         _mt_enabled = 1;
252         mtrace();
253      }
254 #endif
255
256    if (!eina_log_init())
257      {
258         fprintf(stderr, "Could not initialize eina logging system.\n");
259         return 0;
260      }
261
262    _eina_log_dom = eina_log_domain_register("eina", EINA_LOG_COLOR_DEFAULT);
263    if (_eina_log_dom < 0)
264      {
265         EINA_LOG_ERR("Could not register log domain: eina");
266         eina_log_shutdown();
267         return 0;
268      }
269
270    EINA_ERROR_NOT_MAIN_LOOP = eina_error_msg_static_register(
271          EINA_ERROR_NOT_MAIN_LOOP_STR);
272
273 #ifdef EFL_HAVE_THREADS
274 # ifdef _WIN32
275    _eina_main_loop = GetCurrentThreadId();
276 # else
277    _eina_main_loop = pthread_self();
278 # endif
279    _eina_pid = getpid();
280 #endif
281
282 #ifdef EINA_HAVE_DEBUG_THREADS
283    pthread_mutex_init(&_eina_tracking_lock, NULL);
284
285    if (getenv("EINA_DEBUG_THREADS"))
286      _eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS"));
287 #endif
288
289    itr = _eina_desc_setup;
290    itr_end = itr + _eina_desc_setup_len;
291    for (; itr < itr_end; itr++)
292      {
293         if (!itr->init())
294           {
295              ERR("Could not initialize eina module '%s'.", itr->name);
296              _eina_shutdown_from_desc(itr);
297              return 0;
298           }
299      }
300
301    eina_cpu_count_internal();
302
303    _eina_main_count = 1;
304    return 1;
305 }
306
307 EAPI int
308 eina_shutdown(void)
309 {
310    if (_eina_main_count <= 0)
311      {
312         ERR("Init count not greater than 0 in shutdown.");
313         return 0;
314      }
315    _eina_main_count--;
316    if (EINA_UNLIKELY(_eina_main_count == 0))
317      {
318         _eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
319
320 #ifdef EINA_HAVE_DEBUG_THREADS
321         pthread_mutex_destroy(&_eina_tracking_lock);
322 #endif
323 #ifdef MT
324         if (_mt_enabled)
325           {
326              muntrace();
327              _mt_enabled = 0;
328           }
329 #endif
330      }
331
332    return _eina_main_count;
333 }
334
335
336 EAPI int
337 eina_threads_init(void)
338 {
339 #ifdef EFL_HAVE_THREADS
340    int ret;
341
342 #ifdef EINA_HAVE_DEBUG_THREADS
343    assert(pthread_equal(_eina_main_loop, pthread_self()));
344 #endif
345
346    ++_eina_main_thread_count;
347    ret = _eina_main_thread_count;
348
349    if(_eina_main_thread_count > 1)
350      return ret;
351
352    eina_share_common_threads_init();
353    eina_log_threads_init();
354    _eina_threads_activated = EINA_TRUE;
355
356    return ret;
357 #else
358    return 0;
359 #endif
360 }
361
362 EAPI int
363 eina_threads_shutdown(void)
364 {
365 #ifdef EFL_HAVE_THREADS
366    int ret;
367
368 #ifdef EINA_HAVE_DEBUG_THREADS
369    const Eina_Lock *lk;
370
371    assert(pthread_equal(_eina_main_loop, pthread_self()));
372    assert(_eina_main_thread_count > 0);
373 #endif
374
375    ret = --_eina_main_thread_count;
376    if(_eina_main_thread_count > 0)
377      return ret;
378
379 #ifdef EINA_HAVE_DEBUG_THREADS
380    pthread_mutex_lock(&_eina_tracking_lock);
381    if (_eina_tracking)
382      {
383        fprintf(stderr, "*************************\n");
384        fprintf(stderr, "* The IMPOSSIBLE HAPPEN *\n");
385        fprintf(stderr, "* LOCK STILL TAKEN :    *\n");
386        fprintf(stderr, "*************************\n");
387        EINA_INLIST_FOREACH(_eina_tracking, lk)
388          {
389             fprintf(stderr, "=======\n");
390             eina_lock_debug(lk);
391          }
392        fprintf(stderr, "*************************\n");
393        abort();
394      }
395    pthread_mutex_unlock(&_eina_tracking_lock);
396 #endif
397
398    eina_share_common_threads_shutdown();
399    eina_log_threads_shutdown();
400
401    _eina_threads_activated = EINA_FALSE;
402
403    return ret;
404 #else
405    return 0;
406 #endif
407 }
408
409 EAPI Eina_Bool
410 eina_main_loop_is(void)
411 {
412 #ifdef EFL_HAVE_THREADS
413   pid_t pid;
414
415 # ifdef _WIN32
416    if (_eina_main_loop == GetCurrentThreadId())
417      return EINA_TRUE;
418 # else
419    if (pthread_equal(_eina_main_loop, pthread_self()))
420      return EINA_TRUE;
421 # endif
422
423    pid = getpid();
424 # ifdef _WIN32
425    if (pid != _eina_pid)
426      {
427         _eina_pid = pid;
428         _eina_main_loop = GetCurrentThreadId();
429         return EINA_TRUE;
430      }
431 #else
432    if (pid != _eina_pid)
433      {
434         /* This is in case of a fork, but don't like the solution */
435         _eina_pid = pid;
436         _eina_main_loop = pthread_self();
437         return EINA_TRUE;
438      }
439 #endif
440 #endif
441
442    return EINA_FALSE;
443 }
444
445 /** The purpose of this API should not be documented, it is used only by the one who know what they are doing. */
446 EAPI void
447 eina_main_loop_define(void)
448 {
449 #ifdef EFL_HAVE_THREADS
450    _eina_pid = getpid();
451 # ifdef _WIN32
452    _eina_main_loop = GetCurrentThreadId();
453 # else
454    _eina_main_loop = pthread_self();
455 # endif
456 #endif
457 }
458
459 /**
460  * @}
461  */