eina: Only declare _eina_tracking_lock with thread debugging
[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
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
71 /*============================================================================*
72 *                                  Local                                     *
73 *============================================================================*/
74
75 /**
76  * @cond LOCAL
77  */
78
79 static Eina_Version _version = { VMAJ, VMIN, VMIC, VREV };
80
81 static int _eina_main_count = 0;
82 #ifdef EFL_HAVE_THREADS
83 static int _eina_main_thread_count = 0;
84 #endif
85 static int _eina_log_dom = -1;
86
87 #ifdef ERR
88 #undef ERR
89 #endif
90 #define ERR(...) EINA_LOG_DOM_ERR(_eina_log_dom, __VA_ARGS__)
91
92 #ifdef DBG
93 #undef DBG
94 #endif
95 #define DBG(...) EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__)
96
97 EAPI Eina_Bool _eina_threads_activated = EINA_FALSE;
98 EAPI Eina_Error EINA_ERROR_NOT_MAIN_LOOP = 0;
99
100 static const char EINA_ERROR_NOT_MAIN_LOOP_STR[] = "Main loop thread check failed.";
101
102 #ifdef EFL_HAVE_THREADS
103 # ifdef _WIN32
104 EAPI DWORD _eina_main_loop;
105 # else
106 EAPI pthread_t _eina_main_loop;
107 # endif
108 static pid_t _eina_pid;
109 #endif
110
111 #ifdef MT
112 static int _mt_enabled = 0;
113 #endif
114
115 #ifdef EFL_HAVE_THREADS
116 EAPI int _eina_threads_debug = 0;
117 #endif
118 #ifdef EINA_HAVE_DEBUG_THREADS
119 EAPI pthread_mutex_t _eina_tracking_lock;
120 EAPI Eina_Inlist *_eina_tracking = NULL;
121 #endif
122
123 /* place module init/shutdown functions here to avoid other modules
124  * calling them by mistake.
125  */
126 #define S(x) extern Eina_Bool eina_ ## x ## _init(void); \
127    extern Eina_Bool eina_ ## x ## _shutdown(void)
128    S(log);
129    S(error);
130    S(safety_checks);
131    S(magic_string);
132    S(iterator);
133    S(accessor);
134    S(array);
135    S(module);
136    S(mempool);
137    S(list);
138    S(binshare);
139    S(stringshare);
140    S(ustringshare);
141    S(matrixsparse);
142    S(convert);
143    S(counter);
144    S(benchmark);
145    S(rectangle);
146    S(strbuf);
147    S(ustrbuf);
148    S(quadtree);
149    S(simple_xml);
150    S(file);
151    S(prefix);
152 #undef S
153
154 struct eina_desc_setup
155 {
156    const char *name;
157    Eina_Bool (*init)(void);
158    Eina_Bool (*shutdown)(void);
159 };
160
161 static const struct eina_desc_setup _eina_desc_setup[] = {
162 #define S(x) {# x, eina_ ## x ## _init, eina_ ## x ## _shutdown}
163    /* log is a special case as it needs printf */
164    S(error),
165    S(safety_checks),
166    S(magic_string),
167    S(iterator),
168    S(accessor),
169    S(array),
170    S(module),
171    S(mempool),
172    S(list),
173    S(binshare),
174    S(stringshare),
175    S(ustringshare),
176    S(matrixsparse),
177    S(convert),
178    S(counter),
179    S(benchmark),
180    S(rectangle),
181    S(strbuf),
182    S(ustrbuf),
183    S(quadtree),
184    S(simple_xml),
185    S(file),
186    S(prefix)
187 #undef S
188 };
189 static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) /
190    sizeof(_eina_desc_setup[0]);
191
192 static void
193 _eina_shutdown_from_desc(const struct eina_desc_setup *itr)
194 {
195    for (itr--; itr >= _eina_desc_setup; itr--)
196      {
197         if (!itr->shutdown())
198            ERR("Problems shutting down eina module '%s', ignored.", itr->name);
199      }
200
201    eina_log_domain_unregister(_eina_log_dom);
202    _eina_log_dom = -1;
203    eina_log_shutdown();
204 }
205
206 /**
207  * @endcond
208  */
209
210 /*============================================================================*
211 *                                 Global                                     *
212 *============================================================================*/
213
214
215 /*============================================================================*
216 *                                   API                                      *
217 *============================================================================*/
218
219 /**
220  * @var eina_version
221  * @brief Eina version (defined at configuration time)
222  */
223 EAPI Eina_Version *eina_version = &_version;
224
225 EAPI int
226 eina_init(void)
227 {
228    const struct eina_desc_setup *itr, *itr_end;
229
230    if (EINA_LIKELY(_eina_main_count > 0))
231       return ++_eina_main_count;
232
233 #ifdef MT
234    if ((getenv("EINA_MTRACE")) && (getenv("MALLOC_TRACE")))
235      {
236         _mt_enabled = 1;
237         mtrace();
238      }
239 #endif   
240    
241    if (!eina_log_init())
242      {
243         fprintf(stderr, "Could not initialize eina logging system.\n");
244         return 0;
245      }
246
247    _eina_log_dom = eina_log_domain_register("eina", EINA_LOG_COLOR_DEFAULT);
248    if (_eina_log_dom < 0)
249      {
250         EINA_LOG_ERR("Could not register log domain: eina");
251         eina_log_shutdown();
252         return 0;
253      }
254
255    EINA_ERROR_NOT_MAIN_LOOP = eina_error_msg_static_register(
256          EINA_ERROR_NOT_MAIN_LOOP_STR);
257
258 #ifdef EFL_HAVE_THREADS
259 # ifdef _WIN32
260    _eina_main_loop = GetCurrentThreadId();
261 # else
262    _eina_main_loop = pthread_self();
263 # endif
264    _eina_pid = getpid();
265 #endif
266
267 #ifdef EINA_HAVE_DEBUG_THREADS
268    pthread_mutex_init(&_eina_tracking_lock, NULL);
269
270    if (getenv("EINA_DEBUG_THREADS"))
271      _eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS"));
272 #endif
273
274    itr = _eina_desc_setup;
275    itr_end = itr + _eina_desc_setup_len;
276    for (; itr < itr_end; itr++)
277      {
278         if (!itr->init())
279           {
280              ERR("Could not initialize eina module '%s'.", itr->name);
281              _eina_shutdown_from_desc(itr);
282              return 0;
283           }
284      }
285
286    _eina_main_count = 1;
287    return 1;
288 }
289
290 EAPI int
291 eina_shutdown(void)
292 {
293    _eina_main_count--;
294    if (EINA_UNLIKELY(_eina_main_count == 0))
295      {
296         _eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
297
298 #ifdef EINA_HAVE_DEBUG_THREADS
299         pthread_mutex_destroy(&_eina_tracking_lock);
300 #endif
301 #ifdef MT
302         if (_mt_enabled)
303           {
304              muntrace();
305              _mt_enabled = 0;
306           }
307 #endif   
308      }
309
310    return _eina_main_count;
311 }
312
313
314 EAPI int
315 eina_threads_init(void)
316 {
317 #ifdef EFL_HAVE_THREADS
318    int ret;
319
320 #ifdef EINA_HAVE_DEBUG_THREADS
321    assert(pthread_equal(_eina_main_loop, pthread_self()));
322 #endif
323
324    ++_eina_main_thread_count;
325    ret = _eina_main_thread_count;
326
327    if(_eina_main_thread_count > 1)
328      return ret;
329
330    eina_share_common_threads_init();
331    eina_log_threads_init();
332    _eina_threads_activated = EINA_TRUE;
333
334    return ret;
335 #else
336    return 0;
337 #endif
338 }
339
340 EAPI int
341 eina_threads_shutdown(void)
342 {
343 #ifdef EFL_HAVE_THREADS
344    int ret;
345
346 #ifdef EINA_HAVE_DEBUG_THREADS
347    const Eina_Lock *lk;
348
349    assert(pthread_equal(_eina_main_loop, pthread_self()));
350    assert(_eina_main_thread_count > 0);
351 #endif
352
353    ret = --_eina_main_thread_count;
354    if(_eina_main_thread_count > 0)
355      return ret;
356
357 #ifdef EINA_HAVE_DEBUG_THREADS
358    pthread_mutex_lock(&_eina_tracking_lock);
359    if (_eina_tracking)
360      {
361        fprintf(stderr, "*************************\n");
362        fprintf(stderr, "* The IMPOSSIBLE HAPPEN *\n");
363        fprintf(stderr, "* LOCK STILL TAKEN :    *\n");
364        fprintf(stderr, "*************************\n");
365        EINA_INLIST_FOREACH(_eina_tracking, lk)
366          eina_lock_debug(lk);
367        fprintf(stderr, "*************************\n");
368        abort();
369      }
370    pthread_mutex_unlock(&_eina_tracking_lock);
371 #endif
372
373    eina_share_common_threads_shutdown();
374    eina_log_threads_shutdown();
375
376    _eina_threads_activated = EINA_FALSE;
377
378    return ret;
379 #else
380    return 0;
381 #endif
382 }
383
384 EAPI Eina_Bool
385 eina_main_loop_is(void)
386 {
387 #ifdef EFL_HAVE_THREADS
388    pid_t pid = getpid();
389
390 # ifdef _WIN32
391    if (pid != _eina_pid)
392      {
393         _eina_pid = pid;
394         _eina_main_loop = GetCurrentThreadId();
395         return EINA_TRUE;
396      }
397    if (_eina_main_loop == GetCurrentThreadId())
398      return EINA_TRUE;
399 # else
400    if (pid != _eina_pid)
401      {
402         /* This is in case of a fork, but don't like the solution */
403         _eina_pid = pid;
404         _eina_main_loop = pthread_self();
405         return EINA_TRUE;
406      }
407
408    if (pthread_equal(_eina_main_loop, pthread_self()))
409      return EINA_TRUE;
410 # endif
411 #endif
412    return EINA_FALSE;
413 }
414
415 /** The purpose of this API should not be documented, it is used only by the one who know what they are doing. */
416 EAPI void
417 eina_main_loop_define(void)
418 {
419 #ifdef EFL_HAVE_THREADS
420    _eina_pid = getpid();
421 # ifdef _WIN32
422    _eina_main_loop = GetCurrentThreadId();
423 # else
424    _eina_main_loop = pthread_self();
425 # endif
426 #endif
427 }
428
429 /**
430  * @}
431  */