eina: detect main loop for windows to.
[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 # if !(defined(_WIN32_WCE)) && !(defined(_WIN32))
33 #  include <sys/types.h>
34 #  include <unistd.h>
35 # endif
36 #endif
37
38 #include "eina_lock.h"
39 #include "eina_config.h"
40 #include "eina_private.h"
41 #include "eina_types.h"
42 #include "eina_main.h"
43 #include "eina_error.h"
44 #include "eina_log.h"
45 #include "eina_hash.h"
46 #include "eina_binshare.h"
47 #include "eina_stringshare.h"
48 #include "eina_ustringshare.h"
49 #include "eina_list.h"
50 #include "eina_matrixsparse.h"
51 #include "eina_array.h"
52 #include "eina_counter.h"
53 #include "eina_benchmark.h"
54 #include "eina_magic.h"
55 #include "eina_rectangle.h"
56 #include "eina_safety_checks.h"
57
58 /*============================================================================*
59 *                                  Local                                     *
60 *============================================================================*/
61
62 /**
63  * @cond LOCAL
64  */
65
66 static Eina_Version _version = { VMAJ, VMIN, VMIC, VREV };
67
68 static int _eina_main_count = 0;
69 #ifdef EFL_HAVE_THREADS
70 static int _eina_main_thread_count = 0;
71 #endif
72 static int _eina_log_dom = -1;
73
74 #ifdef ERR
75 #undef ERR
76 #endif
77 #define ERR(...) EINA_LOG_DOM_ERR(_eina_log_dom, __VA_ARGS__)
78
79 #ifdef DBG
80 #undef DBG
81 #endif
82 #define DBG(...) EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__)
83
84 EAPI Eina_Bool _eina_threads_activated = EINA_FALSE;
85
86 #ifdef EFL_HAVE_THREADS
87 # ifdef _WIN32_WCE
88 EAPI HANDLE _eina_main_loop;
89 # elif defined(_WIN32)
90 EAPI HANDLE _eina_main_loop;
91 # else
92 EAPI pthread_t _eina_main_loop;
93 static pid_t _eina_pid;
94 # endif
95 #endif
96
97 #ifdef EINA_HAVE_DEBUG_THREADS
98 EAPI int _eina_threads_debug = 0;
99 EAPI pthread_mutex_t _eina_tracking_lock;
100 EAPI Eina_Inlist *_eina_tracking = NULL;
101 #endif
102
103 /* place module init/shutdown functions here to avoid other modules
104  * calling them by mistake.
105  */
106 #define S(x) extern Eina_Bool eina_ ## x ## _init(void); \
107    extern Eina_Bool eina_ ## x ## _shutdown(void)
108    S(log);
109    S(error);
110    S(safety_checks);
111    S(magic_string);
112    S(iterator);
113    S(accessor);
114    S(array);
115    S(module);
116    S(mempool);
117    S(list);
118    S(binshare);
119    S(stringshare);
120    S(ustringshare);
121    S(matrixsparse);
122    S(convert);
123    S(counter);
124    S(benchmark);
125    S(rectangle);
126    S(strbuf);
127    S(ustrbuf);
128    S(quadtree);
129    S(simple_xml);
130    S(file);
131 #undef S
132
133 struct eina_desc_setup
134 {
135    const char *name;
136    Eina_Bool (*init)(void);
137    Eina_Bool (*shutdown)(void);
138 };
139
140 static const struct eina_desc_setup _eina_desc_setup[] = {
141 #define S(x) {# x, eina_ ## x ## _init, eina_ ## x ## _shutdown}
142    /* log is a special case as it needs printf */
143    S(error),
144    S(safety_checks),
145    S(magic_string),
146    S(iterator),
147    S(accessor),
148    S(array),
149    S(module),
150    S(mempool),
151    S(list),
152    S(binshare),
153    S(stringshare),
154    S(ustringshare),
155    S(matrixsparse),
156    S(convert),
157    S(counter),
158    S(benchmark),
159    S(rectangle),
160    S(strbuf),
161    S(ustrbuf),
162    S(quadtree),
163    S(simple_xml),
164    S(file)
165 #undef S
166 };
167 static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) /
168    sizeof(_eina_desc_setup[0]);
169
170 static void
171 _eina_shutdown_from_desc(const struct eina_desc_setup *itr)
172 {
173    for (itr--; itr >= _eina_desc_setup; itr--)
174      {
175         if (!itr->shutdown())
176            ERR("Problems shutting down eina module '%s', ignored.", itr->name);
177      }
178
179    eina_log_domain_unregister(_eina_log_dom);
180    _eina_log_dom = -1;
181    eina_log_shutdown();
182 }
183
184 /**
185  * @endcond
186  */
187
188 /*============================================================================*
189 *                                 Global                                     *
190 *============================================================================*/
191
192
193 /*============================================================================*
194 *                                   API                                      *
195 *============================================================================*/
196
197 /**
198  * @var eina_version
199  * @brief Eina version (defined at configuration time)
200  */
201 EAPI Eina_Version *eina_version = &_version;
202
203 EAPI int
204 eina_init(void)
205 {
206    const struct eina_desc_setup *itr, *itr_end;
207
208    if (EINA_LIKELY(_eina_main_count > 0))
209       return ++_eina_main_count;
210
211    if (!eina_log_init())
212      {
213         fprintf(stderr, "Could not initialize eina logging system.\n");
214         return 0;
215      }
216
217    _eina_log_dom = eina_log_domain_register("eina", EINA_LOG_COLOR_DEFAULT);
218    if (_eina_log_dom < 0)
219      {
220         EINA_LOG_ERR("Could not register log domain: eina");
221         eina_log_shutdown();
222         return 0;
223      }
224
225 #ifdef EFL_HAVE_THREADS
226 # ifdef _WIN32_CE
227    _eina_main_loop = (HANDLE) GetCurrentThreadId();
228 # elif defined (_WIN32)
229    _eina_main_loop = (HANDLE) GetCurrentThreadId();
230 # else
231    _eina_main_loop = pthread_self();
232    _eina_pid = getpid();
233 # endif
234 #endif
235
236 #ifdef EINA_HAVE_DEBUG_THREADS
237    pthread_mutex_init(&_eina_tracking_lock, NULL);
238
239    if (getenv("EINA_DEBUG_THREADS"))
240      _eina_threads_debug = atoi(getenv("EINA_DEBUG_THREADS"));
241 #endif
242
243    itr = _eina_desc_setup;
244    itr_end = itr + _eina_desc_setup_len;
245    for (; itr < itr_end; itr++)
246      {
247         if (!itr->init())
248           {
249              ERR("Could not initialize eina module '%s'.", itr->name);
250              _eina_shutdown_from_desc(itr);
251              return 0;
252           }
253      }
254
255    _eina_main_count = 1;
256    return 1;
257 }
258
259 EAPI int
260 eina_shutdown(void)
261 {
262    _eina_main_count--;
263    if (EINA_UNLIKELY(_eina_main_count == 0))
264      {
265         _eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
266
267 #ifdef EINA_HAVE_DEBUG_THREADS
268         pthread_mutex_destroy(&_eina_tracking_lock);
269 #endif
270      }
271
272    return _eina_main_count;
273 }
274
275
276 EAPI int
277 eina_threads_init(void)
278 {
279 #ifdef EFL_HAVE_THREADS
280    int ret;
281
282 #ifdef EINA_HAVE_DEBUG_THREADS
283    assert(pthread_equal(_eina_main_loop, pthread_self()));
284 #endif
285
286    ++_eina_main_thread_count;
287    ret = _eina_main_thread_count;
288
289    if(_eina_main_thread_count > 1)
290      return ret;
291
292    eina_share_common_threads_init();
293    eina_log_threads_init();
294    _eina_threads_activated = EINA_TRUE;
295
296    return ret;
297 #else
298    return 0;
299 #endif
300 }
301
302 EAPI int
303 eina_threads_shutdown(void)
304 {
305 #ifdef EFL_HAVE_THREADS
306    int ret;
307
308 #ifdef EINA_HAVE_DEBUG_THREADS
309    const Eina_Lock *lk;
310
311    assert(pthread_equal(_eina_main_loop, pthread_self()));
312    assert(_eina_main_thread_count > 0);
313 #endif
314
315    ret = --_eina_main_thread_count;
316    if(_eina_main_thread_count > 0)
317      return ret;
318
319 #ifdef EINA_HAVE_DEBUG_THREADS
320    pthread_mutex_lock(&_eina_tracking_lock);
321    if (_eina_tracking)
322      {
323        fprintf(stderr, "*************************\n");
324        fprintf(stderr, "* The IMPOSSIBLE HAPPEN *\n");
325        fprintf(stderr, "* LOCK STILL TAKEN :    *\n");
326        fprintf(stderr, "*************************\n");
327        EINA_INLIST_FOREACH(_eina_tracking, lk)
328          eina_lock_debug(lk);
329        fprintf(stderr, "*************************\n");
330        abort();
331      }
332    pthread_mutex_unlock(&_eina_tracking_lock);
333 #endif
334
335    eina_share_common_threads_shutdown();
336    eina_log_threads_shutdown();
337
338    _eina_threads_activated = EINA_FALSE;
339
340    return ret;
341 #else
342    return 0;
343 #endif
344 }
345
346 EAPI Eina_Bool
347 eina_main_loop_is(void)
348 {
349 #ifdef EFL_HAVE_THREADS
350    /* FIXME: need to check how to do this on windows */
351 # ifdef _WIN32_CE
352    if (_eina_main_loop == (HANDLE) GetCurrentThreadId())
353      return EINA_TRUE;
354    return EINA_FALSE;
355 # elif defined(_WIN32)
356    if (_eina_main_loop == (HANDLE) GetCurrentThreadId())
357      return EINA_TRUE;
358    return EINA_FALSE;
359 # else
360    pid_t pid = getpid();
361
362    if (pid != _eina_pid)
363      {
364         /* This is in case of a fork, but don't like the solution */
365         _eina_pid = pid;
366         _eina_main_loop = pthread_self();
367         return EINA_TRUE;
368      }
369
370    if (pthread_equal(_eina_main_loop, pthread_self()))
371      return EINA_TRUE;
372 # endif
373 #endif
374    return EINA_FALSE;
375 }
376
377 /**
378  * @}
379  */