blob: 25e2790887f08c993ee3179c605841fdd89d7e9b [file] [log] [blame]
Daniel Veillardb8478642001-10-12 17:29:10 +00001/**
Daniel Veillarddee23482008-04-11 12:58:43 +00002 * threads.c: set of generic threading related routines
Daniel Veillardb8478642001-10-12 17:29:10 +00003 *
4 * See Copyright for the status of this software.
5 *
6 * Gary Pennington <Gary.Pennington@uk.sun.com>
7 * daniel@veillard.com
8 */
9
Daniel Veillard34ce8be2002-03-18 19:37:11 +000010#define IN_LIBXML
Daniel Veillardb8478642001-10-12 17:29:10 +000011#include "libxml.h"
12
13#include <string.h>
14
15#include <libxml/threads.h>
16#include <libxml/globals.h>
17
18#ifdef HAVE_SYS_TYPES_H
19#include <sys/types.h>
20#endif
21#ifdef HAVE_UNISTD_H
22#include <unistd.h>
23#endif
24#ifdef HAVE_STDLIB_H
25#include <stdlib.h>
26#endif
27#ifdef HAVE_PTHREAD_H
28#include <pthread.h>
29#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +000030
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000031#ifdef HAVE_WIN32_THREADS
32#include <windows.h>
Igor Zlatkovicf2160a02002-10-31 15:58:42 +000033#ifndef HAVE_COMPILER_TLS
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000034#include <process.h>
35#endif
36#endif
Daniel Veillardb8478642001-10-12 17:29:10 +000037
Daniel Veillard82cb3192003-10-29 13:39:15 +000038#ifdef HAVE_BEOS_THREADS
39#include <OS.h>
40#include <TLS.h>
41#endif
42
Daniel Veillardb8478642001-10-12 17:29:10 +000043#if defined(SOLARIS)
44#include <note.h>
45#endif
46
Daniel Veillard6f350292001-10-14 09:56:15 +000047/* #define DEBUG_THREADS */
Daniel Veillardb8478642001-10-12 17:29:10 +000048
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000049#ifdef HAVE_PTHREAD_H
50
51static int libxml_is_threaded = -1;
52#ifdef __GNUC__
53#ifdef linux
54#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
55extern int pthread_once (pthread_once_t *__once_control,
56 void (*__init_routine) (void))
57 __attribute((weak));
58extern void *pthread_getspecific (pthread_key_t __key)
59 __attribute((weak));
60extern int pthread_setspecific (pthread_key_t __key,
61 __const void *__pointer)
62 __attribute((weak));
63extern int pthread_key_create (pthread_key_t *__key,
64 void (*__destr_function) (void *))
65 __attribute((weak));
Daniel Veillardd4a3f242009-01-18 15:41:30 +000066extern int pthread_key_delete (pthread_key_t __key)
67 __attribute((weak));
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000068extern int pthread_mutex_init ()
69 __attribute((weak));
70extern int pthread_mutex_destroy ()
71 __attribute((weak));
72extern int pthread_mutex_lock ()
73 __attribute((weak));
74extern int pthread_mutex_unlock ()
75 __attribute((weak));
76extern int pthread_cond_init ()
77 __attribute((weak));
Daniel Veillard2cba4152008-08-27 11:45:41 +000078extern int pthread_cond_destroy ()
79 __attribute((weak));
80extern int pthread_cond_wait ()
81 __attribute((weak));
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000082extern int pthread_equal ()
83 __attribute((weak));
84extern pthread_t pthread_self ()
85 __attribute((weak));
86extern int pthread_key_create ()
87 __attribute((weak));
Daniel Veillardd4a3f242009-01-18 15:41:30 +000088extern int pthread_key_delete ()
89 __attribute((weak));
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000090extern int pthread_cond_signal ()
91 __attribute((weak));
92#endif
93#endif /* linux */
94#endif /* __GNUC__ */
95#endif /* HAVE_PTHREAD_H */
96
Daniel Veillardb8478642001-10-12 17:29:10 +000097/*
98 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
99 * to avoid some crazyness since xmlMalloc/xmlFree may actually
100 * be hosted on allocated blocks needing them for the allocation ...
101 */
102
103/*
104 * xmlMutex are a simple mutual exception locks
105 */
106struct _xmlMutex {
107#ifdef HAVE_PTHREAD_H
108 pthread_mutex_t lock;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000109#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000110 HANDLE mutex;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000111#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000112 sem_id sem;
113 thread_id tid;
Daniel Veillardb8478642001-10-12 17:29:10 +0000114#else
115 int empty;
116#endif
117};
118
119/*
120 * xmlRMutex are reentrant mutual exception locks
121 */
122struct _xmlRMutex {
123#ifdef HAVE_PTHREAD_H
124 pthread_mutex_t lock;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000125 unsigned int held;
126 unsigned int waiters;
127 pthread_t tid;
128 pthread_cond_t cv;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000129#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000130 CRITICAL_SECTION cs;
131 unsigned int count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000132#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000133 xmlMutexPtr lock;
134 thread_id tid;
135 int32 count;
Daniel Veillardb8478642001-10-12 17:29:10 +0000136#else
137 int empty;
138#endif
139};
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000140
Daniel Veillardb8478642001-10-12 17:29:10 +0000141/*
142 * This module still has some internal static data.
143 * - xmlLibraryLock a global lock
144 * - globalkey used for per-thread data
Daniel Veillardb8478642001-10-12 17:29:10 +0000145 */
Daniel Veillard6f350292001-10-14 09:56:15 +0000146
Daniel Veillardb8478642001-10-12 17:29:10 +0000147#ifdef HAVE_PTHREAD_H
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000148static pthread_key_t globalkey;
149static pthread_t mainthread;
Daniel Veillarde28313b2001-12-06 14:08:31 +0000150static pthread_once_t once_control = PTHREAD_ONCE_INIT;
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000151static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000152#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000153#if defined(HAVE_COMPILER_TLS)
154static __declspec(thread) xmlGlobalState tlstate;
155static __declspec(thread) int tlstate_inited = 0;
156#else /* HAVE_COMPILER_TLS */
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000157static DWORD globalkey = TLS_OUT_OF_INDEXES;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000158#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000159static DWORD mainthread;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000160static struct {
Daniel Veillard36616dd2005-02-25 07:31:49 +0000161 DWORD done;
162 DWORD control;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000163} run_once = { 0, 0};
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000164static volatile LPCRITICAL_SECTION global_init_lock = NULL;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000165
Daniel Veillard82cb3192003-10-29 13:39:15 +0000166/* endif HAVE_WIN32_THREADS */
167#elif defined HAVE_BEOS_THREADS
168int32 globalkey = 0;
169thread_id mainthread = 0;
170int32 run_once_init = 0;
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000171static int32 global_init_lock = -1;
172static vint32 global_init_count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000173#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000174
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000175static xmlRMutexPtr xmlLibraryLock = NULL;
176
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000177#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000178static void xmlOnceInit(void);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000179#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000180
181/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000182 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000183 *
184 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
185 * synchronizing access to data.
186 *
187 * Returns a new simple mutex pointer or NULL in case of error
188 */
189xmlMutexPtr
190xmlNewMutex(void)
191{
192 xmlMutexPtr tok;
193
194 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
195 return (NULL);
196#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000197 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000198 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000199#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000200 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000201#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000202 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
203 free(tok);
204 return NULL;
205 }
206 tok->tid = -1;
Daniel Veillardb8478642001-10-12 17:29:10 +0000207#endif
208 return (tok);
209}
210
211/**
212 * xmlFreeMutex:
213 * @tok: the simple mutex
214 *
215 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
216 * struct.
217 */
218void
219xmlFreeMutex(xmlMutexPtr tok)
220{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000221 if (tok == NULL)
222 return;
Daniel Veillarddf101d82003-07-08 14:03:36 +0000223
Daniel Veillardb8478642001-10-12 17:29:10 +0000224#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000225 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000226 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000227#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000228 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000229#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000230 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000231#endif
232 free(tok);
233}
234
235/**
236 * xmlMutexLock:
237 * @tok: the simple mutex
238 *
239 * xmlMutexLock() is used to lock a libxml2 token.
240 */
241void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000242xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000243{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000244 if (tok == NULL)
245 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000246#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000247 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000248 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000249#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000250 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000251#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000252 if (acquire_sem(tok->sem) != B_NO_ERROR) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000253#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000254 xmlGenericError(xmlGenericErrorContext,
255 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
256 exit();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000257#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000258 }
259 tok->tid = find_thread(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000260#endif
261
262}
263
264/**
265 * xmlMutexUnlock:
266 * @tok: the simple mutex
267 *
268 * xmlMutexUnlock() is used to unlock a libxml2 token.
269 */
270void
Daniel Veillard5805be22003-08-28 08:03:23 +0000271xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000272{
Daniel Veillard5805be22003-08-28 08:03:23 +0000273 if (tok == NULL)
274 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000275#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000276 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000277 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000278#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000279 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000280#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000281 if (tok->tid == find_thread(NULL)) {
282 tok->tid = -1;
283 release_sem(tok->sem);
284 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000285#endif
286}
287
288/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000289 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000290 *
291 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
292 * synchronizing access to data. token_r is a re-entrant lock and thus useful
293 * for synchronizing access to data structures that may be manipulated in a
294 * recursive fashion.
295 *
296 * Returns the new reentrant mutex pointer or NULL in case of error
297 */
298xmlRMutexPtr
299xmlNewRMutex(void)
300{
301 xmlRMutexPtr tok;
302
303 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
304 return (NULL);
305#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000306 if (libxml_is_threaded != 0) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000307 pthread_mutex_init(&tok->lock, NULL);
308 tok->held = 0;
309 tok->waiters = 0;
310 pthread_cond_init(&tok->cv, NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000311 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000312#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000313 InitializeCriticalSection(&tok->cs);
314 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000315#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000316 if ((tok->lock = xmlNewMutex()) == NULL) {
317 free(tok);
318 return NULL;
319 }
320 tok->count = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000321#endif
322 return (tok);
323}
324
325/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000326 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000327 * @tok: the reentrant mutex
328 *
329 * xmlRFreeMutex() is used to reclaim resources associated with a
330 * reentrant mutex.
331 */
332void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000333xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000334{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000335 if (tok == NULL)
336 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000337#ifdef HAVE_PTHREAD_H
Daniel Veillarda8b54132006-06-29 11:50:18 +0000338 if (libxml_is_threaded != 0) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000339 pthread_mutex_destroy(&tok->lock);
340 pthread_cond_destroy(&tok->cv);
Daniel Veillarda8b54132006-06-29 11:50:18 +0000341 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000342#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000343 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000344#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000345 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000346#endif
347 free(tok);
348}
349
350/**
351 * xmlRMutexLock:
352 * @tok: the reentrant mutex
353 *
354 * xmlRMutexLock() is used to lock a libxml2 token_r.
355 */
356void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000357xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000358{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000359 if (tok == NULL)
360 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000361#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000362 if (libxml_is_threaded == 0)
363 return;
364
Daniel Veillardb8478642001-10-12 17:29:10 +0000365 pthread_mutex_lock(&tok->lock);
366 if (tok->held) {
367 if (pthread_equal(tok->tid, pthread_self())) {
368 tok->held++;
369 pthread_mutex_unlock(&tok->lock);
370 return;
371 } else {
372 tok->waiters++;
373 while (tok->held)
374 pthread_cond_wait(&tok->cv, &tok->lock);
375 tok->waiters--;
376 }
377 }
378 tok->tid = pthread_self();
379 tok->held = 1;
380 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000381#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000382 EnterCriticalSection(&tok->cs);
383 ++tok->count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000384#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000385 if (tok->lock->tid == find_thread(NULL)) {
386 tok->count++;
387 return;
388 } else {
389 xmlMutexLock(tok->lock);
390 tok->count = 1;
391 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000392#endif
393}
394
395/**
396 * xmlRMutexUnlock:
397 * @tok: the reentrant mutex
398 *
399 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
400 */
401void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000402xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000403{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000404 if (tok == NULL)
405 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000406#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000407 if (libxml_is_threaded == 0)
408 return;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000409
Daniel Veillardb8478642001-10-12 17:29:10 +0000410 pthread_mutex_lock(&tok->lock);
411 tok->held--;
412 if (tok->held == 0) {
413 if (tok->waiters)
414 pthread_cond_signal(&tok->cv);
415 tok->tid = 0;
416 }
417 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000418#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000419 if (!--tok->count)
420 LeaveCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000421#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000422 if (tok->lock->tid == find_thread(NULL)) {
423 tok->count--;
424 if (tok->count == 0) {
425 xmlMutexUnlock(tok->lock);
426 }
427 return;
428 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000429#endif
430}
431
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000432/**
433 * xmlGlobalInitMutexLock
434 *
435 * Makes sure that the global initialization mutex is initialized and
436 * locks it.
437 */
438void
439__xmlGlobalInitMutexLock(void)
440{
441 /* Make sure the global init lock is initialized and then lock it. */
442#ifdef HAVE_PTHREAD_H
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000443 /* The mutex is statically initialized, so we just lock it. */
444 pthread_mutex_lock(&global_init_lock);
445#elif defined HAVE_WIN32_THREADS
446 LPCRITICAL_SECTION cs;
447
448 /* Create a new critical section */
449 if (global_init_lock == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000450 cs = malloc(sizeof(CRITICAL_SECTION));
451 if (cs == NULL) {
452 xmlGenericError(xmlGenericErrorContext,
453 "xmlGlobalInitMutexLock: out of memory\n");
454 return;
455 }
456 InitializeCriticalSection(cs);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000457
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000458 /* Swap it into the global_init_lock */
Rob Richardse967f0b2007-06-08 19:36:04 +0000459#ifdef InterlockedCompareExchangePointer
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000460 InterlockedCompareExchangePointer(&global_init_lock, cs, NULL);
461#else /* Use older void* version */
462 InterlockedCompareExchange((void **) &global_init_lock,
463 (void *) cs, NULL);
Rob Richardse967f0b2007-06-08 19:36:04 +0000464#endif /* InterlockedCompareExchangePointer */
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000465
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000466 /* If another thread successfully recorded its critical
467 * section in the global_init_lock then discard the one
468 * allocated by this thread. */
469 if (global_init_lock != cs) {
470 DeleteCriticalSection(cs);
471 free(cs);
472 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000473 }
474
475 /* Lock the chosen critical section */
476 EnterCriticalSection(global_init_lock);
477#elif defined HAVE_BEOS_THREADS
478 int32 sem;
479
480 /* Allocate a new semaphore */
481 sem = create_sem(1, "xmlGlobalinitMutex");
482
483 while (global_init_lock == -1) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000484 if (atomic_add(&global_init_count, 1) == 0) {
485 global_init_lock = sem;
486 } else {
487 snooze(1);
488 atomic_add(&global_init_count, -1);
489 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000490 }
491
492 /* If another thread successfully recorded its critical
493 * section in the global_init_lock then discard the one
494 * allocated by this thread. */
495 if (global_init_lock != sem)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000496 delete_sem(sem);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000497
498 /* Acquire the chosen semaphore */
499 if (acquire_sem(global_init_lock) != B_NO_ERROR) {
500#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000501 xmlGenericError(xmlGenericErrorContext,
502 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
503 exit();
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000504#endif
505 }
506#endif
507}
508
509void
510__xmlGlobalInitMutexUnlock(void)
511{
512#ifdef HAVE_PTHREAD_H
513 pthread_mutex_unlock(&global_init_lock);
514#elif defined HAVE_WIN32_THREADS
Daniel Veillard14d465d2008-03-24 11:12:55 +0000515 if (global_init_lock != NULL) {
516 LeaveCriticalSection(global_init_lock);
517 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000518#elif defined HAVE_BEOS_THREADS
519 release_sem(global_init_lock);
520#endif
521}
522
Rob Richards91eb5602007-11-16 10:54:59 +0000523/**
524 * xmlGlobalInitMutexDestroy
525 *
526 * Makes sure that the global initialization mutex is destroyed before
527 * application termination.
528 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000529void
530__xmlGlobalInitMutexDestroy(void)
Rob Richards91eb5602007-11-16 10:54:59 +0000531{
532#if defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000533 if (global_init_lock != NULL) {
534 DeleteCriticalSection(global_init_lock);
535 free(global_init_lock);
536 global_init_lock = NULL;
Rob Richards91eb5602007-11-16 10:54:59 +0000537 }
538#endif
539}
540
Daniel Veillardb8478642001-10-12 17:29:10 +0000541/************************************************************************
542 * *
543 * Per thread global state handling *
544 * *
545 ************************************************************************/
546
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000547#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000548#ifdef xmlLastError
549#undef xmlLastError
550#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000551
Daniel Veillardb8478642001-10-12 17:29:10 +0000552/**
553 * xmlFreeGlobalState:
554 * @state: a thread global state
555 *
556 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
557 * global state. It is is used here to reclaim memory resources.
558 */
559static void
560xmlFreeGlobalState(void *state)
561{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000562 xmlGlobalState *gs = (xmlGlobalState *) state;
563
564 /* free any memory allocated in the thread's xmlLastError */
565 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000566 free(state);
567}
568
569/**
570 * xmlNewGlobalState:
571 *
572 * xmlNewGlobalState() allocates a global state. This structure is used to
573 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000574 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000575 *
576 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
577 */
578static xmlGlobalStatePtr
579xmlNewGlobalState(void)
580{
581 xmlGlobalState *gs;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000582
Daniel Veillardb8478642001-10-12 17:29:10 +0000583 gs = malloc(sizeof(xmlGlobalState));
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000584 if (gs == NULL) {
585 xmlGenericError(xmlGenericErrorContext,
586 "xmlGetGlobalState: out of memory\n");
587 return (NULL);
588 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000589
William M. Brack8b2c7f12002-11-22 05:07:29 +0000590 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000591 xmlInitializeGlobalState(gs);
592 return (gs);
593}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000594#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000595
596
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000597#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000598#if !defined(HAVE_COMPILER_TLS)
599#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000600typedef struct _xmlGlobalStateCleanupHelperParams {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000601 HANDLE thread;
602 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000603} xmlGlobalStateCleanupHelperParams;
604
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000605static void XMLCDECL
606xmlGlobalStateCleanupHelper(void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000607{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000608 xmlGlobalStateCleanupHelperParams *params =
609 (xmlGlobalStateCleanupHelperParams *) p;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000610 WaitForSingleObject(params->thread, INFINITE);
611 CloseHandle(params->thread);
612 xmlFreeGlobalState(params->memory);
613 free(params);
614 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000615}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000616#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
617
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000618typedef struct _xmlGlobalStateCleanupHelperParams {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000619 void *memory;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000620 struct _xmlGlobalStateCleanupHelperParams *prev;
621 struct _xmlGlobalStateCleanupHelperParams *next;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000622} xmlGlobalStateCleanupHelperParams;
623
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000624static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000625static CRITICAL_SECTION cleanup_helpers_cs;
626
627#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
628#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000629#endif /* HAVE_WIN32_THREADS */
630
Daniel Veillard82cb3192003-10-29 13:39:15 +0000631#if defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000632
William M. Brackb1d53162003-11-18 06:54:40 +0000633/**
634 * xmlGlobalStateCleanup:
635 * @data: unused parameter
636 *
637 * Used for Beos only
638 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000639void
640xmlGlobalStateCleanup(void *data)
Daniel Veillard82cb3192003-10-29 13:39:15 +0000641{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000642 void *globalval = tls_get(globalkey);
643
644 if (globalval != NULL)
645 xmlFreeGlobalState(globalval);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000646}
647#endif
648
Daniel Veillard01c13b52002-12-10 15:19:08 +0000649/**
650 * xmlGetGlobalState:
651 *
652 * xmlGetGlobalState() is called to retrieve the global state for a thread.
653 *
654 * Returns the thread global state or NULL in case of error
655 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000656xmlGlobalStatePtr
657xmlGetGlobalState(void)
658{
659#ifdef HAVE_PTHREAD_H
660 xmlGlobalState *globalval;
661
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000662 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000663 return (NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000664
Daniel Veillarde28313b2001-12-06 14:08:31 +0000665 pthread_once(&once_control, xmlOnceInit);
666
Daniel Veillardb8478642001-10-12 17:29:10 +0000667 if ((globalval = (xmlGlobalState *)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000668 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000669 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000670 if (tsd == NULL)
671 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000672
673 pthread_setspecific(globalkey, tsd);
674 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000675 }
676 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000677#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000678#if defined(HAVE_COMPILER_TLS)
679 if (!tlstate_inited) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000680 tlstate_inited = 1;
681 xmlInitializeGlobalState(&tlstate);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000682 }
683 return &tlstate;
684#else /* HAVE_COMPILER_TLS */
685 xmlGlobalState *globalval;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000686 xmlGlobalStateCleanupHelperParams *p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000687
Daniel Veillard62121e22005-02-24 15:38:52 +0000688 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000689#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000690 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000691#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000692 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
693 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000694#endif
695 if (globalval == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000696 xmlGlobalState *tsd = xmlNewGlobalState();
697
698 if (tsd == NULL)
699 return(NULL);
700 p = (xmlGlobalStateCleanupHelperParams *)
701 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
702 if (p == NULL) {
703 xmlGenericError(xmlGenericErrorContext,
704 "xmlGetGlobalState: out of memory\n");
Daniel Veillardbf2ebff2009-01-18 14:57:04 +0000705 xmlFreeGlobalState(tsd);
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000706 return(NULL);
707 }
708 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000709#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000710 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
711 GetCurrentProcess(), &p->thread, 0, TRUE,
712 DUPLICATE_SAME_ACCESS);
713 TlsSetValue(globalkey, tsd);
714 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000715#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000716 EnterCriticalSection(&cleanup_helpers_cs);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000717 if (cleanup_helpers_head != NULL) {
718 cleanup_helpers_head->prev = p;
719 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000720 p->next = cleanup_helpers_head;
721 p->prev = NULL;
722 cleanup_helpers_head = p;
723 TlsSetValue(globalkey, p);
724 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000725#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000726
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000727 return (tsd);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000728 }
729 return (globalval);
730#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000731#elif defined HAVE_BEOS_THREADS
732 xmlGlobalState *globalval;
733
734 xmlOnceInit();
735
Daniel Veillard14d465d2008-03-24 11:12:55 +0000736 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000737 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000738 if (tsd == NULL)
739 return (NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000740
741 tls_set(globalkey, tsd);
742 on_exit_thread(xmlGlobalStateCleanup, NULL);
743 return (tsd);
744 }
745 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000746#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000747 return (NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000748#endif
749}
750
Daniel Veillardb8478642001-10-12 17:29:10 +0000751/************************************************************************
752 * *
753 * Library wide thread interfaces *
754 * *
755 ************************************************************************/
756
757/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000758 * xmlGetThreadId:
759 *
760 * xmlGetThreadId() find the current thread ID number
761 *
762 * Returns the current thread ID number
763 */
764int
765xmlGetThreadId(void)
766{
767#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000768 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000769 return (0);
770 return ((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000771#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000772 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000773#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000774 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000775#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000776 return ((int) 0);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000777#endif
778}
779
780/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000781 * xmlIsMainThread:
782 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000783 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000784 *
785 * Returns 1 if the current thread is the main thread, 0 otherwise
786 */
787int
788xmlIsMainThread(void)
789{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000790#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000791 if (libxml_is_threaded == -1)
792 xmlInitThreads();
793 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000794 return (1);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000795 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000796#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000797 xmlOnceInit();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000798#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000799 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000800#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000801
Daniel Veillard6f350292001-10-14 09:56:15 +0000802#ifdef DEBUG_THREADS
803 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
804#endif
805#ifdef HAVE_PTHREAD_H
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000806 return (mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000807#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000808 return (mainthread == GetCurrentThreadId());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000809#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000810 return (mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000811#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000812 return (1);
Daniel Veillard6f350292001-10-14 09:56:15 +0000813#endif
814}
815
816/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000817 * xmlLockLibrary:
818 *
819 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
820 * library.
821 */
822void
823xmlLockLibrary(void)
824{
Daniel Veillard6f350292001-10-14 09:56:15 +0000825#ifdef DEBUG_THREADS
826 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
827#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000828 xmlRMutexLock(xmlLibraryLock);
829}
830
831/**
832 * xmlUnlockLibrary:
833 *
834 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
835 * library.
836 */
837void
838xmlUnlockLibrary(void)
839{
Daniel Veillard6f350292001-10-14 09:56:15 +0000840#ifdef DEBUG_THREADS
841 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
842#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000843 xmlRMutexUnlock(xmlLibraryLock);
844}
845
846/**
847 * xmlInitThreads:
848 *
849 * xmlInitThreads() is used to to initialize all the thread related
850 * data of the libxml2 library.
851 */
852void
853xmlInitThreads(void)
854{
Daniel Veillardc790bf42003-10-11 10:50:10 +0000855#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000856 InitializeCriticalSection(&cleanup_helpers_cs);
857#endif
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000858#ifdef HAVE_PTHREAD_H
859 if (libxml_is_threaded == -1) {
860 if ((pthread_once != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000861 (pthread_getspecific != NULL) &&
862 (pthread_setspecific != NULL) &&
863 (pthread_key_create != NULL) &&
Daniel Veillardd4a3f242009-01-18 15:41:30 +0000864 (pthread_key_delete != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000865 (pthread_mutex_init != NULL) &&
866 (pthread_mutex_destroy != NULL) &&
867 (pthread_mutex_lock != NULL) &&
868 (pthread_mutex_unlock != NULL) &&
869 (pthread_cond_init != NULL) &&
Daniel Veillard2cba4152008-08-27 11:45:41 +0000870 (pthread_cond_destroy != NULL) &&
871 (pthread_cond_wait != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000872 (pthread_equal != NULL) &&
873 (pthread_self != NULL) &&
874 (pthread_cond_signal != NULL)) {
875 libxml_is_threaded = 1;
876
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000877/* fprintf(stderr, "Running multithreaded\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000878 } else {
879
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000880/* fprintf(stderr, "Running without multithread\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000881 libxml_is_threaded = 0;
882 }
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000883 }
884#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000885}
886
887/**
888 * xmlCleanupThreads:
889 *
890 * xmlCleanupThreads() is used to to cleanup all the thread related
891 * data of the libxml2 library once processing has ended.
Daniel Veillard01101202009-02-21 09:22:04 +0000892 *
893 * WARNING: if your application is multithreaded or has plugin support
894 * calling this may crash the application if another thread or
895 * a plugin is still using libxml2. It's sometimes very hard to
896 * guess if libxml2 is in use in the application, some libraries
897 * or plugins may use it without notice. In case of doubt abstain
898 * from calling this function or do it just before calling exit()
899 * to avoid leak reports from valgrind !
Daniel Veillardb8478642001-10-12 17:29:10 +0000900 */
901void
902xmlCleanupThreads(void)
903{
Daniel Veillard6f350292001-10-14 09:56:15 +0000904#ifdef DEBUG_THREADS
905 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
906#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000907#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000908 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000909 xmlGlobalStateCleanupHelperParams *p;
910
911 EnterCriticalSection(&cleanup_helpers_cs);
912 p = cleanup_helpers_head;
913 while (p != NULL) {
914 xmlGlobalStateCleanupHelperParams *temp = p;
915
916 p = p->next;
917 xmlFreeGlobalState(temp->memory);
918 free(temp);
919 }
920 cleanup_helpers_head = 0;
921 LeaveCriticalSection(&cleanup_helpers_cs);
922 TlsFree(globalkey);
923 globalkey = TLS_OUT_OF_INDEXES;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000924 }
925 DeleteCriticalSection(&cleanup_helpers_cs);
Daniel Veillardd4a3f242009-01-18 15:41:30 +0000926#elif defined HAVE_PTHREAD_H
Daniel Veillardf63085d2009-01-18 20:53:59 +0000927 if ((libxml_is_threaded) && (pthread_key_delete != NULL))
Daniel Veillardd4a3f242009-01-18 15:41:30 +0000928 pthread_key_delete(globalkey);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000929#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000930}
Daniel Veillard6f350292001-10-14 09:56:15 +0000931
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000932#ifdef LIBXML_THREAD_ENABLED
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000933
Daniel Veillarde28313b2001-12-06 14:08:31 +0000934/**
935 * xmlOnceInit
936 *
937 * xmlOnceInit() is used to initialize the value of mainthread for use
938 * in other routines. This function should only be called using
939 * pthread_once() in association with the once_control variable to ensure
940 * that the function is only called once. See man pthread_once for more
941 * details.
942 */
943static void
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000944xmlOnceInit(void)
945{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000946#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000947 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000948 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000949#endif
950
951#if defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000952 if (!run_once.done) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000953 if (InterlockedIncrement(&run_once.control) == 1) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000954#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000955 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000956#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000957 mainthread = GetCurrentThreadId();
958 run_once.done = 1;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000959 } else {
Daniel Veillard62121e22005-02-24 15:38:52 +0000960 /* Another thread is working; give up our slice and
961 * wait until they're done. */
962 while (!run_once.done)
963 Sleep(0);
964 }
965 }
Daniel Veillarde28313b2001-12-06 14:08:31 +0000966#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000967
968#ifdef HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000969 if (atomic_add(&run_once_init, 1) == 0) {
970 globalkey = tls_allocate();
971 tls_set(globalkey, NULL);
972 mainthread = find_thread(NULL);
973 } else
974 atomic_add(&run_once_init, -1);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000975#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000976}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000977#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000978
979/**
William M. Brack7a821652003-08-15 07:27:40 +0000980 * DllMain:
981 * @hinstDLL: handle to DLL instance
982 * @fdwReason: Reason code for entry
983 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000984 *
985 * Entry point for Windows library. It is being used to free thread-specific
986 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000987 *
988 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000989 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000990#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
991#if defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000992BOOL XMLCALL
993xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000994#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000995BOOL WINAPI
996DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000997#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000998{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000999 switch (fdwReason) {
1000 case DLL_THREAD_DETACH:
1001 if (globalkey != TLS_OUT_OF_INDEXES) {
1002 xmlGlobalState *globalval = NULL;
1003 xmlGlobalStateCleanupHelperParams *p =
1004 (xmlGlobalStateCleanupHelperParams *)
1005 TlsGetValue(globalkey);
1006 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
1007 if (globalval) {
1008 xmlFreeGlobalState(globalval);
1009 TlsSetValue(globalkey, NULL);
1010 }
1011 if (p) {
1012 EnterCriticalSection(&cleanup_helpers_cs);
1013 if (p == cleanup_helpers_head)
1014 cleanup_helpers_head = p->next;
1015 else
1016 p->prev->next = p->next;
1017 if (p->next != NULL)
1018 p->next->prev = p->prev;
1019 LeaveCriticalSection(&cleanup_helpers_cs);
1020 free(p);
1021 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001022 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +00001023 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +00001024 }
1025 return TRUE;
1026}
1027#endif
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001028#define bottom_threads
1029#include "elfgcchack.h"