eina: check pending lock at the right time.
[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 /* place module init/shutdown functions here to avoid other modules
87  * calling them by mistake.
88  */
89 #define S(x) extern Eina_Bool eina_ ## x ## _init(void); \
90    extern Eina_Bool eina_ ## x ## _shutdown(void)
91    S(log);
92    S(error);
93    S(safety_checks);
94    S(magic_string);
95    S(iterator);
96    S(accessor);
97    S(array);
98    S(module);
99    S(mempool);
100    S(list);
101    S(binshare);
102    S(stringshare);
103    S(ustringshare);
104    S(matrixsparse);
105    S(convert);
106    S(counter);
107    S(benchmark);
108    S(rectangle);
109    S(strbuf);
110    S(ustrbuf);
111    S(quadtree);
112    S(simple_xml);
113    S(file);
114 #undef S
115
116 struct eina_desc_setup
117 {
118    const char *name;
119    Eina_Bool (*init)(void);
120    Eina_Bool (*shutdown)(void);
121 };
122
123 static const struct eina_desc_setup _eina_desc_setup[] = {
124 #define S(x) {# x, eina_ ## x ## _init, eina_ ## x ## _shutdown}
125    /* log is a special case as it needs printf */
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 #undef S
149 };
150 static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) /
151    sizeof(_eina_desc_setup[0]);
152
153 static void
154 _eina_shutdown_from_desc(const struct eina_desc_setup *itr)
155 {
156    for (itr--; itr >= _eina_desc_setup; itr--)
157      {
158         if (!itr->shutdown())
159            ERR("Problems shutting down eina module '%s', ignored.", itr->name);
160      }
161
162    eina_log_domain_unregister(_eina_log_dom);
163    _eina_log_dom = -1;
164    eina_log_shutdown();
165 }
166
167 /**
168  * @endcond
169  */
170
171 /*============================================================================*
172 *                                 Global                                     *
173 *============================================================================*/
174
175
176 /*============================================================================*
177 *                                   API                                      *
178 *============================================================================*/
179
180 /**
181  * @var eina_version
182  * @brief Eina version (defined at configuration time)
183  */
184 EAPI Eina_Version *eina_version = &_version;
185
186 EAPI int
187 eina_init(void)
188 {
189    const struct eina_desc_setup *itr, *itr_end;
190
191    if (EINA_LIKELY(_eina_main_count > 0))
192       return ++_eina_main_count;
193
194    if (!eina_log_init())
195      {
196         fprintf(stderr, "Could not initialize eina logging system.\n");
197         return 0;
198      }
199
200    _eina_log_dom = eina_log_domain_register("eina", EINA_LOG_COLOR_DEFAULT);
201    if (_eina_log_dom < 0)
202      {
203         EINA_LOG_ERR("Could not register log domain: eina");
204         eina_log_shutdown();
205         return 0;
206      }
207
208 #ifdef EINA_HAVE_DEBUG_THREADS
209    _eina_main_loop = pthread_self();
210    pthread_mutex_init(&_eina_tracking_lock, NULL);
211
212    if (getenv("EINA_DEBUG_THREADS"))
213      _eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS"));
214 #endif
215
216    itr = _eina_desc_setup;
217    itr_end = itr + _eina_desc_setup_len;
218    for (; itr < itr_end; itr++)
219      {
220         if (!itr->init())
221           {
222              ERR("Could not initialize eina module '%s'.", itr->name);
223              _eina_shutdown_from_desc(itr);
224              return 0;
225           }
226      }
227
228    _eina_main_count = 1;
229    return 1;
230 }
231
232 EAPI int
233 eina_shutdown(void)
234 {
235    _eina_main_count--;
236    if (EINA_UNLIKELY(_eina_main_count == 0))
237      {
238         _eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
239
240 #ifdef EINA_HAVE_DEBUG_THREADS
241         pthread_mutex_destroy(&_eina_tracking_lock);
242 #endif
243      }
244
245    return _eina_main_count;
246 }
247
248
249 EAPI int
250 eina_threads_init(void)
251 {
252 #ifdef EFL_HAVE_THREADS
253    int ret;
254
255 #ifdef EINA_HAVE_DEBUG_THREADS
256    assert(pthread_equal(_eina_main_loop, pthread_self()));
257 #endif
258
259    ++_eina_main_thread_count;
260    ret = _eina_main_thread_count;
261
262    if(_eina_main_thread_count > 1)
263      return ret;
264
265    eina_share_common_threads_init();
266    eina_log_threads_init();
267    _eina_threads_activated = EINA_TRUE;
268
269    return ret;
270 #else
271    return 0;
272 #endif
273 }
274
275 EAPI int
276 eina_threads_shutdown(void)
277 {
278 #ifdef EFL_HAVE_THREADS
279    int ret;
280
281 #ifdef EINA_HAVE_DEBUG_THREADS
282    const Eina_Lock *lk;
283
284    assert(pthread_equal(_eina_main_loop, pthread_self()));
285    assert(_eina_main_thread_count > 0);
286 #endif
287
288    ret = --_eina_main_thread_count;
289    if(_eina_main_thread_count > 0)
290      return ret;
291
292 #ifdef EINA_HAVE_DEBUG_THREADS
293    pthread_mutex_lock(&_eina_tracking_lock);
294    if (_eina_tracking)
295      {
296        fprintf(stderr, "*************************\n");
297        fprintf(stderr, "* The IMPOSSIBLE HAPPEN *\n");
298        fprintf(stderr, "* LOCK STILL TAKEN :    *\n");
299        fprintf(stderr, "*************************\n");
300        EINA_INLIST_FOREACH(_eina_tracking, lk)
301          eina_lock_debug(lk);
302        fprintf(stderr, "*************************\n");
303        abort();
304      }
305    pthread_mutex_unlock(&_eina_tracking_lock);
306 #endif
307
308    eina_share_common_threads_shutdown();
309    eina_log_threads_shutdown();
310
311    _eina_threads_activated = EINA_FALSE;
312
313    return ret;
314 #else
315    return 0;
316 #endif
317 }
318
319 /**
320  * @}
321  */