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