eina: make sure eina_threads_init/eina_threads_shutdown are correctly called.
[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 = NULL;
82 #endif
83
84 static Eina_Lock _mutex;
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    itr = _eina_desc_setup;
209    itr_end = itr + _eina_desc_setup_len;
210    for (; itr < itr_end; itr++)
211      {
212         if (!itr->init())
213           {
214              ERR("Could not initialize eina module '%s'.", itr->name);
215              _eina_shutdown_from_desc(itr);
216              return 0;
217           }
218      }
219
220
221    eina_lock_new(&_mutex);
222 #ifdef EINA_HAVE_DEBUG_THREADS
223    _eina_main_loop = pthread_self();
224
225    if (getenv("EINA_DEBUG_THREADS"))
226      _eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS");
227 #endif
228
229    _eina_main_count = 1;
230    return 1;
231 }
232
233 EAPI int
234 eina_shutdown(void)
235 {
236    _eina_main_count--;
237    if (EINA_UNLIKELY(_eina_main_count == 0))
238      {
239         _eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
240
241         eina_lock_free(&_mutex);
242      }
243
244    return _eina_main_count;
245 }
246
247
248 EAPI int
249 eina_threads_init(void)
250 {
251 #ifdef EFL_HAVE_THREADS
252    int ret;
253
254 #ifdef EINA_HAVE_DEBUG_THREADS
255    assert(pthread_equal(_eina_main_loop, pthread_self()));
256 #endif
257
258    eina_lock_take(&_mutex);
259    ++_eina_main_thread_count;
260    ret = _eina_main_thread_count;
261
262    if(_eina_main_thread_count > 1)
263      {
264         eina_lock_release(&_mutex);
265         return ret;
266      }
267
268    eina_share_common_threads_init();
269    eina_log_threads_init();
270    _eina_threads_activated = EINA_TRUE;
271
272    eina_lock_release(&_mutex);
273
274    return ret;
275 #else
276    return 0;
277 #endif
278 }
279
280 EAPI int
281 eina_threads_shutdown(void)
282 {
283 #ifdef EFL_HAVE_THREADS
284    int ret;
285
286 #ifdef EINA_HAVE_DEBUG_THREADS
287    assert(pthread_equal(_eina_main_loop, pthread_self()));
288    assert(_eina_main_thread_count > 0);
289 #endif
290
291    eina_lock_take(&_mutex);
292    ret = --_eina_main_thread_count;
293    if(_eina_main_thread_count > 0)
294      {
295         eina_lock_release(&_mutex);
296         return ret;
297      }
298
299    eina_share_common_threads_shutdown();
300    eina_log_threads_shutdown();
301
302    eina_lock_release(&_mutex);
303
304    _eina_threads_activated = EINA_FALSE;
305
306    return ret;
307 #else
308    return 0;
309 #endif
310 }
311
312 /**
313  * @}
314  */