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