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