and fully de-modelify eina
[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_main_count = 1;
302    return 1;
303 }
304
305 EAPI int
306 eina_shutdown(void)
307 {
308    _eina_main_count--;
309    if (EINA_UNLIKELY(_eina_main_count == 0))
310      {
311         _eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
312
313 #ifdef EINA_HAVE_DEBUG_THREADS
314         pthread_mutex_destroy(&_eina_tracking_lock);
315 #endif
316 #ifdef MT
317         if (_mt_enabled)
318           {
319              muntrace();
320              _mt_enabled = 0;
321           }
322 #endif
323      }
324
325    return _eina_main_count;
326 }
327
328
329 EAPI int
330 eina_threads_init(void)
331 {
332 #ifdef EFL_HAVE_THREADS
333    int ret;
334
335 #ifdef EINA_HAVE_DEBUG_THREADS
336    assert(pthread_equal(_eina_main_loop, pthread_self()));
337 #endif
338
339    ++_eina_main_thread_count;
340    ret = _eina_main_thread_count;
341
342    if(_eina_main_thread_count > 1)
343      return ret;
344
345    eina_share_common_threads_init();
346    eina_log_threads_init();
347    _eina_threads_activated = EINA_TRUE;
348
349    return ret;
350 #else
351    return 0;
352 #endif
353 }
354
355 EAPI int
356 eina_threads_shutdown(void)
357 {
358 #ifdef EFL_HAVE_THREADS
359    int ret;
360
361 #ifdef EINA_HAVE_DEBUG_THREADS
362    const Eina_Lock *lk;
363
364    assert(pthread_equal(_eina_main_loop, pthread_self()));
365    assert(_eina_main_thread_count > 0);
366 #endif
367
368    ret = --_eina_main_thread_count;
369    if(_eina_main_thread_count > 0)
370      return ret;
371
372 #ifdef EINA_HAVE_DEBUG_THREADS
373    pthread_mutex_lock(&_eina_tracking_lock);
374    if (_eina_tracking)
375      {
376        fprintf(stderr, "*************************\n");
377        fprintf(stderr, "* The IMPOSSIBLE HAPPEN *\n");
378        fprintf(stderr, "* LOCK STILL TAKEN :    *\n");
379        fprintf(stderr, "*************************\n");
380        EINA_INLIST_FOREACH(_eina_tracking, lk)
381          {
382             fprintf(stderr, "=======\n");
383             eina_lock_debug(lk);
384          }
385        fprintf(stderr, "*************************\n");
386        abort();
387      }
388    pthread_mutex_unlock(&_eina_tracking_lock);
389 #endif
390
391    eina_share_common_threads_shutdown();
392    eina_log_threads_shutdown();
393
394    _eina_threads_activated = EINA_FALSE;
395
396    return ret;
397 #else
398    return 0;
399 #endif
400 }
401
402 EAPI Eina_Bool
403 eina_main_loop_is(void)
404 {
405 #ifdef EFL_HAVE_THREADS
406    pid_t pid = getpid();
407
408 # ifdef _WIN32
409    if (pid != _eina_pid)
410      {
411         _eina_pid = pid;
412         _eina_main_loop = GetCurrentThreadId();
413         return EINA_TRUE;
414      }
415    if (_eina_main_loop == GetCurrentThreadId())
416      return EINA_TRUE;
417 # else
418    if (pid != _eina_pid)
419      {
420         /* This is in case of a fork, but don't like the solution */
421         _eina_pid = pid;
422         _eina_main_loop = pthread_self();
423         return EINA_TRUE;
424      }
425
426    if (pthread_equal(_eina_main_loop, pthread_self()))
427      return EINA_TRUE;
428 # endif
429 #endif
430    return EINA_FALSE;
431 }
432
433 /** The purpose of this API should not be documented, it is used only by the one who know what they are doing. */
434 EAPI void
435 eina_main_loop_define(void)
436 {
437 #ifdef EFL_HAVE_THREADS
438    _eina_pid = getpid();
439 # ifdef _WIN32
440    _eina_main_loop = GetCurrentThreadId();
441 # else
442    _eina_main_loop = pthread_self();
443 # endif
444 #endif
445 }
446
447 /**
448  * @}
449  */