eina: improve on/off and debugging lock.
[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 #include "eina_lock.h"
32 #include "eina_config.h"
33 #include "eina_private.h"
34 #include "eina_types.h"
35 #include "eina_main.h"
36 #include "eina_error.h"
37 #include "eina_log.h"
38 #include "eina_hash.h"
39 #include "eina_binshare.h"
40 #include "eina_stringshare.h"
41 #include "eina_ustringshare.h"
42 #include "eina_list.h"
43 #include "eina_matrixsparse.h"
44 #include "eina_array.h"
45 #include "eina_counter.h"
46 #include "eina_benchmark.h"
47 #include "eina_magic.h"
48 #include "eina_rectangle.h"
49 #include "eina_safety_checks.h"
50
51 /*============================================================================*
52 *                                  Local                                     *
53 *============================================================================*/
54
55 /**
56  * @cond LOCAL
57  */
58
59 static Eina_Version _version = { VMAJ, VMIN, VMIC, VREV };
60
61 static int _eina_main_count = 0;
62 #ifdef EFL_HAVE_THREADS
63 static int _eina_main_thread_count = 0;
64 #endif
65 static int _eina_log_dom = -1;
66
67 #ifdef ERR
68 #undef ERR
69 #endif
70 #define ERR(...) EINA_LOG_DOM_ERR(_eina_log_dom, __VA_ARGS__)
71
72 #ifdef DBG
73 #undef DBG
74 #endif
75 #define DBG(...) EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__)
76
77 EAPI Eina_Bool _eina_threads_activated = EINA_FALSE;
78
79 #ifdef EINA_HAVE_DEBUG_THREADS
80 EAPI int _eina_threads_debug = 0;
81 EAPI pthread_t _eina_main_loop;;
82 EAPI pthread_mutex_t _eina_tracking_lock;
83 EAPI Eina_Inlist *_eina_tracking = NULL;
84 #endif
85
86 static Eina_Lock _mutex;
87
88 /* place module init/shutdown functions here to avoid other modules
89  * calling them by mistake.
90  */
91 #define S(x) extern Eina_Bool eina_ ## x ## _init(void); \
92    extern Eina_Bool eina_ ## x ## _shutdown(void)
93    S(log);
94    S(error);
95    S(safety_checks);
96    S(magic_string);
97    S(iterator);
98    S(accessor);
99    S(array);
100    S(module);
101    S(mempool);
102    S(list);
103    S(binshare);
104    S(stringshare);
105    S(ustringshare);
106    S(matrixsparse);
107    S(convert);
108    S(counter);
109    S(benchmark);
110    S(rectangle);
111    S(strbuf);
112    S(ustrbuf);
113    S(quadtree);
114    S(simple_xml);
115    S(file);
116 #undef S
117
118 struct eina_desc_setup
119 {
120    const char *name;
121    Eina_Bool (*init)(void);
122    Eina_Bool (*shutdown)(void);
123 };
124
125 static const struct eina_desc_setup _eina_desc_setup[] = {
126 #define S(x) {# x, eina_ ## x ## _init, eina_ ## x ## _shutdown}
127    /* log is a special case as it needs printf */
128    S(error),
129    S(safety_checks),
130    S(magic_string),
131    S(iterator),
132    S(accessor),
133    S(array),
134    S(module),
135    S(mempool),
136    S(list),
137    S(binshare),
138    S(stringshare),
139    S(ustringshare),
140    S(matrixsparse),
141    S(convert),
142    S(counter),
143    S(benchmark),
144    S(rectangle),
145    S(strbuf),
146    S(ustrbuf),
147    S(quadtree),
148    S(simple_xml),
149    S(file)
150 #undef S
151 };
152 static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) /
153    sizeof(_eina_desc_setup[0]);
154
155 static void
156 _eina_shutdown_from_desc(const struct eina_desc_setup *itr)
157 {
158    for (itr--; itr >= _eina_desc_setup; itr--)
159      {
160         if (!itr->shutdown())
161            ERR("Problems shutting down eina module '%s', ignored.", itr->name);
162      }
163
164    eina_log_domain_unregister(_eina_log_dom);
165    _eina_log_dom = -1;
166    eina_log_shutdown();
167 }
168
169 /**
170  * @endcond
171  */
172
173 /*============================================================================*
174 *                                 Global                                     *
175 *============================================================================*/
176
177
178 /*============================================================================*
179 *                                   API                                      *
180 *============================================================================*/
181
182 /**
183  * @var eina_version
184  * @brief Eina version (defined at configuration time)
185  */
186 EAPI Eina_Version *eina_version = &_version;
187
188 EAPI int
189 eina_init(void)
190 {
191    const struct eina_desc_setup *itr, *itr_end;
192
193    if (EINA_LIKELY(_eina_main_count > 0))
194       return ++_eina_main_count;
195
196    if (!eina_log_init())
197      {
198         fprintf(stderr, "Could not initialize eina logging system.\n");
199         return 0;
200      }
201
202    _eina_log_dom = eina_log_domain_register("eina", EINA_LOG_COLOR_DEFAULT);
203    if (_eina_log_dom < 0)
204      {
205         EINA_LOG_ERR("Could not register log domain: eina");
206         eina_log_shutdown();
207         return 0;
208      }
209
210 #ifdef EINA_HAVE_DEBUG_THREADS
211    _eina_main_loop = pthread_self();
212    pthread_mutex_init(&_eina_tracking_lock, NULL);
213
214    if (getenv("EINA_DEBUG_THREADS"))
215      _eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS"));
216 #endif
217
218    itr = _eina_desc_setup;
219    itr_end = itr + _eina_desc_setup_len;
220    for (; itr < itr_end; itr++)
221      {
222         if (!itr->init())
223           {
224              ERR("Could not initialize eina module '%s'.", itr->name);
225              _eina_shutdown_from_desc(itr);
226              return 0;
227           }
228      }
229
230    eina_lock_new(&_mutex);
231
232    _eina_main_count = 1;
233    return 1;
234 }
235
236 EAPI int
237 eina_shutdown(void)
238 {
239    _eina_main_count--;
240    if (EINA_UNLIKELY(_eina_main_count == 0))
241      {
242         _eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
243
244 #ifdef EINA_HAVE_DEBUG_THREADS
245         pthread_mutex_destroy(&_eina_tracking_lock);
246 #endif
247
248         eina_lock_free(&_mutex);
249      }
250
251    return _eina_main_count;
252 }
253
254
255 EAPI int
256 eina_threads_init(void)
257 {
258 #ifdef EFL_HAVE_THREADS
259    int ret;
260
261 #ifdef EINA_HAVE_DEBUG_THREADS
262    assert(pthread_equal(_eina_main_loop, pthread_self()));
263 #endif
264
265    eina_lock_take(&_mutex);
266    ++_eina_main_thread_count;
267    ret = _eina_main_thread_count;
268
269    if(_eina_main_thread_count > 1)
270      {
271         eina_lock_release(&_mutex);
272         return ret;
273      }
274
275    eina_share_common_threads_init();
276    eina_log_threads_init();
277    _eina_threads_activated = EINA_TRUE;
278
279    eina_lock_release(&_mutex);
280
281    return ret;
282 #else
283    return 0;
284 #endif
285 }
286
287 EAPI int
288 eina_threads_shutdown(void)
289 {
290 #ifdef EFL_HAVE_THREADS
291    int ret;
292
293 #ifdef EINA_HAVE_DEBUG_THREADS
294    const Eina_Lock *lk;
295
296    assert(pthread_equal(_eina_main_loop, pthread_self()));
297    assert(_eina_main_thread_count > 0);
298
299    pthread_mutex_lock(&_eina_tracking_lock);
300    if (_eina_tracking)
301      {
302        fprintf(stderr, "*************************\n");
303        fprintf(stderr, "* The IMPOSSIBLE HAPPEN *\n");
304        fprintf(stderr, "* LOCK STILL TAKEN :    *\n");
305        fprintf(stderr, "*************************\n");
306        EINA_INLIST_FOREACH(_eina_tracking, lk)
307          eina_lock_debug(lk);
308        fprintf(stderr, "*************************\n");
309        abort();
310      }
311    pthread_mutex_unlock(&_eina_tracking_lock);
312
313 #endif
314
315    eina_lock_take(&_mutex);
316    ret = --_eina_main_thread_count;
317    if(_eina_main_thread_count > 0)
318      {
319         eina_lock_release(&_mutex);
320         return ret;
321      }
322
323    eina_share_common_threads_shutdown();
324    eina_log_threads_shutdown();
325
326    eina_lock_release(&_mutex);
327
328    _eina_threads_activated = EINA_FALSE;
329
330    return ret;
331 #else
332    return 0;
333 #endif
334 }
335
336 /**
337  * @}
338  */