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