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