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