blob: 6481b403e69e136391911d6e3a21ac1d5bb2ae11 [file] [log] [blame]
Daniel Veillardb8478642001-10-12 17:29:10 +00001/**
2 * threads.c: set of generic threading related routines
3 *
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));
66extern int pthread_mutex_init ()
67 __attribute((weak));
68extern int pthread_mutex_destroy ()
69 __attribute((weak));
70extern int pthread_mutex_lock ()
71 __attribute((weak));
72extern int pthread_mutex_unlock ()
73 __attribute((weak));
74extern int pthread_cond_init ()
75 __attribute((weak));
76extern int pthread_equal ()
77 __attribute((weak));
78extern pthread_t pthread_self ()
79 __attribute((weak));
80extern int pthread_key_create ()
81 __attribute((weak));
82extern int pthread_cond_signal ()
83 __attribute((weak));
84#endif
85#endif /* linux */
86#endif /* __GNUC__ */
87#endif /* HAVE_PTHREAD_H */
88
Daniel Veillardb8478642001-10-12 17:29:10 +000089/*
90 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
91 * to avoid some crazyness since xmlMalloc/xmlFree may actually
92 * be hosted on allocated blocks needing them for the allocation ...
93 */
94
95/*
96 * xmlMutex are a simple mutual exception locks
97 */
98struct _xmlMutex {
99#ifdef HAVE_PTHREAD_H
100 pthread_mutex_t lock;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000101#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000102 HANDLE mutex;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000103#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000104 sem_id sem;
105 thread_id tid;
Daniel Veillardb8478642001-10-12 17:29:10 +0000106#else
107 int empty;
108#endif
109};
110
111/*
112 * xmlRMutex are reentrant mutual exception locks
113 */
114struct _xmlRMutex {
115#ifdef HAVE_PTHREAD_H
116 pthread_mutex_t lock;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000117 unsigned int held;
118 unsigned int waiters;
119 pthread_t tid;
120 pthread_cond_t cv;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000121#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000122 CRITICAL_SECTION cs;
123 unsigned int count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000124#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000125 xmlMutexPtr lock;
126 thread_id tid;
127 int32 count;
Daniel Veillardb8478642001-10-12 17:29:10 +0000128#else
129 int empty;
130#endif
131};
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000132
Daniel Veillardb8478642001-10-12 17:29:10 +0000133/*
134 * This module still has some internal static data.
135 * - xmlLibraryLock a global lock
136 * - globalkey used for per-thread data
Daniel Veillardb8478642001-10-12 17:29:10 +0000137 */
Daniel Veillard6f350292001-10-14 09:56:15 +0000138
Daniel Veillardb8478642001-10-12 17:29:10 +0000139#ifdef HAVE_PTHREAD_H
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000140static pthread_key_t globalkey;
141static pthread_t mainthread;
Daniel Veillarde28313b2001-12-06 14:08:31 +0000142static pthread_once_t once_control = PTHREAD_ONCE_INIT;
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000143static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000144#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000145#if defined(HAVE_COMPILER_TLS)
146static __declspec(thread) xmlGlobalState tlstate;
147static __declspec(thread) int tlstate_inited = 0;
148#else /* HAVE_COMPILER_TLS */
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000149static DWORD globalkey = TLS_OUT_OF_INDEXES;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000150#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000151static DWORD mainthread;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000152static struct {
Daniel Veillard36616dd2005-02-25 07:31:49 +0000153 DWORD done;
154 DWORD control;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000155} run_once = { 0, 0};
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000156static volatile LPCRITICAL_SECTION global_init_lock = NULL;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000157
Daniel Veillard82cb3192003-10-29 13:39:15 +0000158/* endif HAVE_WIN32_THREADS */
159#elif defined HAVE_BEOS_THREADS
160int32 globalkey = 0;
161thread_id mainthread = 0;
162int32 run_once_init = 0;
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000163static int32 global_init_lock = -1;
164static vint32 global_init_count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000165#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000166
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000167static xmlRMutexPtr xmlLibraryLock = NULL;
168
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000169#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000170static void xmlOnceInit(void);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000171#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000172
173/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000174 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000175 *
176 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
177 * synchronizing access to data.
178 *
179 * Returns a new simple mutex pointer or NULL in case of error
180 */
181xmlMutexPtr
182xmlNewMutex(void)
183{
184 xmlMutexPtr tok;
185
186 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
187 return (NULL);
188#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000189 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000190 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000191#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000192 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000193#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000194 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
195 free(tok);
196 return NULL;
197 }
198 tok->tid = -1;
Daniel Veillardb8478642001-10-12 17:29:10 +0000199#endif
200 return (tok);
201}
202
203/**
204 * xmlFreeMutex:
205 * @tok: the simple mutex
206 *
207 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
208 * struct.
209 */
210void
211xmlFreeMutex(xmlMutexPtr tok)
212{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000213 if (tok == NULL)
214 return;
Daniel Veillarddf101d82003-07-08 14:03:36 +0000215
Daniel Veillardb8478642001-10-12 17:29:10 +0000216#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000217 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000218 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000219#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000220 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000221#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000222 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000223#endif
224 free(tok);
225}
226
227/**
228 * xmlMutexLock:
229 * @tok: the simple mutex
230 *
231 * xmlMutexLock() is used to lock a libxml2 token.
232 */
233void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000234xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000235{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000236 if (tok == NULL)
237 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000238#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000239 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000240 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000241#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000242 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000243#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000244 if (acquire_sem(tok->sem) != B_NO_ERROR) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000245#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000246 xmlGenericError(xmlGenericErrorContext,
247 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
248 exit();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000249#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000250 }
251 tok->tid = find_thread(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000252#endif
253
254}
255
256/**
257 * xmlMutexUnlock:
258 * @tok: the simple mutex
259 *
260 * xmlMutexUnlock() is used to unlock a libxml2 token.
261 */
262void
Daniel Veillard5805be22003-08-28 08:03:23 +0000263xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000264{
Daniel Veillard5805be22003-08-28 08:03:23 +0000265 if (tok == NULL)
266 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000267#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000268 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000269 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000270#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000271 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000272#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000273 if (tok->tid == find_thread(NULL)) {
274 tok->tid = -1;
275 release_sem(tok->sem);
276 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000277#endif
278}
279
280/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000281 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000282 *
283 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
284 * synchronizing access to data. token_r is a re-entrant lock and thus useful
285 * for synchronizing access to data structures that may be manipulated in a
286 * recursive fashion.
287 *
288 * Returns the new reentrant mutex pointer or NULL in case of error
289 */
290xmlRMutexPtr
291xmlNewRMutex(void)
292{
293 xmlRMutexPtr tok;
294
295 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
296 return (NULL);
297#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000298 if (libxml_is_threaded != 0) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000299 pthread_mutex_init(&tok->lock, NULL);
300 tok->held = 0;
301 tok->waiters = 0;
302 pthread_cond_init(&tok->cv, NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000303 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000304#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000305 InitializeCriticalSection(&tok->cs);
306 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000307#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000308 if ((tok->lock = xmlNewMutex()) == NULL) {
309 free(tok);
310 return NULL;
311 }
312 tok->count = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000313#endif
314 return (tok);
315}
316
317/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000318 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000319 * @tok: the reentrant mutex
320 *
321 * xmlRFreeMutex() is used to reclaim resources associated with a
322 * reentrant mutex.
323 */
324void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000325xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000326{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000327 if (tok == NULL)
328 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000329#ifdef HAVE_PTHREAD_H
Daniel Veillarda8b54132006-06-29 11:50:18 +0000330 if (libxml_is_threaded != 0) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000331 pthread_mutex_destroy(&tok->lock);
332 pthread_cond_destroy(&tok->cv);
Daniel Veillarda8b54132006-06-29 11:50:18 +0000333 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000334#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000335 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000336#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000337 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000338#endif
339 free(tok);
340}
341
342/**
343 * xmlRMutexLock:
344 * @tok: the reentrant mutex
345 *
346 * xmlRMutexLock() is used to lock a libxml2 token_r.
347 */
348void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000349xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000350{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000351 if (tok == NULL)
352 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000353#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000354 if (libxml_is_threaded == 0)
355 return;
356
Daniel Veillardb8478642001-10-12 17:29:10 +0000357 pthread_mutex_lock(&tok->lock);
358 if (tok->held) {
359 if (pthread_equal(tok->tid, pthread_self())) {
360 tok->held++;
361 pthread_mutex_unlock(&tok->lock);
362 return;
363 } else {
364 tok->waiters++;
365 while (tok->held)
366 pthread_cond_wait(&tok->cv, &tok->lock);
367 tok->waiters--;
368 }
369 }
370 tok->tid = pthread_self();
371 tok->held = 1;
372 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000373#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000374 EnterCriticalSection(&tok->cs);
375 ++tok->count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000376#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000377 if (tok->lock->tid == find_thread(NULL)) {
378 tok->count++;
379 return;
380 } else {
381 xmlMutexLock(tok->lock);
382 tok->count = 1;
383 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000384#endif
385}
386
387/**
388 * xmlRMutexUnlock:
389 * @tok: the reentrant mutex
390 *
391 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
392 */
393void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000394xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000395{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000396 if (tok == NULL)
397 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000398#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000399 if (libxml_is_threaded == 0)
400 return;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000401
Daniel Veillardb8478642001-10-12 17:29:10 +0000402 pthread_mutex_lock(&tok->lock);
403 tok->held--;
404 if (tok->held == 0) {
405 if (tok->waiters)
406 pthread_cond_signal(&tok->cv);
407 tok->tid = 0;
408 }
409 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000410#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000411 if (!--tok->count)
412 LeaveCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000413#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000414 if (tok->lock->tid == find_thread(NULL)) {
415 tok->count--;
416 if (tok->count == 0) {
417 xmlMutexUnlock(tok->lock);
418 }
419 return;
420 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000421#endif
422}
423
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000424/**
425 * xmlGlobalInitMutexLock
426 *
427 * Makes sure that the global initialization mutex is initialized and
428 * locks it.
429 */
430void
431__xmlGlobalInitMutexLock(void)
432{
433 /* Make sure the global init lock is initialized and then lock it. */
434#ifdef HAVE_PTHREAD_H
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000435 /* The mutex is statically initialized, so we just lock it. */
436 pthread_mutex_lock(&global_init_lock);
437#elif defined HAVE_WIN32_THREADS
438 LPCRITICAL_SECTION cs;
439
440 /* Create a new critical section */
441 if (global_init_lock == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000442 cs = malloc(sizeof(CRITICAL_SECTION));
443 if (cs == NULL) {
444 xmlGenericError(xmlGenericErrorContext,
445 "xmlGlobalInitMutexLock: out of memory\n");
446 return;
447 }
448 InitializeCriticalSection(cs);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000449
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000450 /* Swap it into the global_init_lock */
Rob Richardse967f0b2007-06-08 19:36:04 +0000451#ifdef InterlockedCompareExchangePointer
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000452 InterlockedCompareExchangePointer(&global_init_lock, cs, NULL);
453#else /* Use older void* version */
454 InterlockedCompareExchange((void **) &global_init_lock,
455 (void *) cs, NULL);
Rob Richardse967f0b2007-06-08 19:36:04 +0000456#endif /* InterlockedCompareExchangePointer */
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000457
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000458 /* If another thread successfully recorded its critical
459 * section in the global_init_lock then discard the one
460 * allocated by this thread. */
461 if (global_init_lock != cs) {
462 DeleteCriticalSection(cs);
463 free(cs);
464 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000465 }
466
467 /* Lock the chosen critical section */
468 EnterCriticalSection(global_init_lock);
469#elif defined HAVE_BEOS_THREADS
470 int32 sem;
471
472 /* Allocate a new semaphore */
473 sem = create_sem(1, "xmlGlobalinitMutex");
474
475 while (global_init_lock == -1) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000476 if (atomic_add(&global_init_count, 1) == 0) {
477 global_init_lock = sem;
478 } else {
479 snooze(1);
480 atomic_add(&global_init_count, -1);
481 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000482 }
483
484 /* If another thread successfully recorded its critical
485 * section in the global_init_lock then discard the one
486 * allocated by this thread. */
487 if (global_init_lock != sem)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000488 delete_sem(sem);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000489
490 /* Acquire the chosen semaphore */
491 if (acquire_sem(global_init_lock) != B_NO_ERROR) {
492#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000493 xmlGenericError(xmlGenericErrorContext,
494 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
495 exit();
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000496#endif
497 }
498#endif
499}
500
501void
502__xmlGlobalInitMutexUnlock(void)
503{
504#ifdef HAVE_PTHREAD_H
505 pthread_mutex_unlock(&global_init_lock);
506#elif defined HAVE_WIN32_THREADS
Daniel Veillard14d465d2008-03-24 11:12:55 +0000507 if (global_init_lock != NULL) {
508 LeaveCriticalSection(global_init_lock);
509 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000510#elif defined HAVE_BEOS_THREADS
511 release_sem(global_init_lock);
512#endif
513}
514
Rob Richards91eb5602007-11-16 10:54:59 +0000515/**
516 * xmlGlobalInitMutexDestroy
517 *
518 * Makes sure that the global initialization mutex is destroyed before
519 * application termination.
520 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000521void
522__xmlGlobalInitMutexDestroy(void)
Rob Richards91eb5602007-11-16 10:54:59 +0000523{
524#if defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000525 if (global_init_lock != NULL) {
526 DeleteCriticalSection(global_init_lock);
527 free(global_init_lock);
528 global_init_lock = NULL;
Rob Richards91eb5602007-11-16 10:54:59 +0000529 }
530#endif
531}
532
Daniel Veillardb8478642001-10-12 17:29:10 +0000533/************************************************************************
534 * *
535 * Per thread global state handling *
536 * *
537 ************************************************************************/
538
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000539#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000540#ifdef xmlLastError
541#undef xmlLastError
542#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000543
Daniel Veillardb8478642001-10-12 17:29:10 +0000544/**
545 * xmlFreeGlobalState:
546 * @state: a thread global state
547 *
548 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
549 * global state. It is is used here to reclaim memory resources.
550 */
551static void
552xmlFreeGlobalState(void *state)
553{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000554 xmlGlobalState *gs = (xmlGlobalState *) state;
555
556 /* free any memory allocated in the thread's xmlLastError */
557 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000558 free(state);
559}
560
561/**
562 * xmlNewGlobalState:
563 *
564 * xmlNewGlobalState() allocates a global state. This structure is used to
565 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000566 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000567 *
568 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
569 */
570static xmlGlobalStatePtr
571xmlNewGlobalState(void)
572{
573 xmlGlobalState *gs;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000574
Daniel Veillardb8478642001-10-12 17:29:10 +0000575 gs = malloc(sizeof(xmlGlobalState));
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000576 if (gs == NULL) {
577 xmlGenericError(xmlGenericErrorContext,
578 "xmlGetGlobalState: out of memory\n");
579 return (NULL);
580 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000581
William M. Brack8b2c7f12002-11-22 05:07:29 +0000582 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000583 xmlInitializeGlobalState(gs);
584 return (gs);
585}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000586#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000587
588
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000589#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000590#if !defined(HAVE_COMPILER_TLS)
591#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000592typedef struct _xmlGlobalStateCleanupHelperParams {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000593 HANDLE thread;
594 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000595} xmlGlobalStateCleanupHelperParams;
596
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000597static void XMLCDECL
598xmlGlobalStateCleanupHelper(void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000599{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000600 xmlGlobalStateCleanupHelperParams *params =
601 (xmlGlobalStateCleanupHelperParams *) p;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000602 WaitForSingleObject(params->thread, INFINITE);
603 CloseHandle(params->thread);
604 xmlFreeGlobalState(params->memory);
605 free(params);
606 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000607}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000608#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
609
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000610typedef struct _xmlGlobalStateCleanupHelperParams {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000611 void *memory;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000612 struct _xmlGlobalStateCleanupHelperParams *prev;
613 struct _xmlGlobalStateCleanupHelperParams *next;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000614} xmlGlobalStateCleanupHelperParams;
615
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000616static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000617static CRITICAL_SECTION cleanup_helpers_cs;
618
619#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
620#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000621#endif /* HAVE_WIN32_THREADS */
622
Daniel Veillard82cb3192003-10-29 13:39:15 +0000623#if defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000624
William M. Brackb1d53162003-11-18 06:54:40 +0000625/**
626 * xmlGlobalStateCleanup:
627 * @data: unused parameter
628 *
629 * Used for Beos only
630 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000631void
632xmlGlobalStateCleanup(void *data)
Daniel Veillard82cb3192003-10-29 13:39:15 +0000633{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000634 void *globalval = tls_get(globalkey);
635
636 if (globalval != NULL)
637 xmlFreeGlobalState(globalval);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000638}
639#endif
640
Daniel Veillard01c13b52002-12-10 15:19:08 +0000641/**
642 * xmlGetGlobalState:
643 *
644 * xmlGetGlobalState() is called to retrieve the global state for a thread.
645 *
646 * Returns the thread global state or NULL in case of error
647 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000648xmlGlobalStatePtr
649xmlGetGlobalState(void)
650{
651#ifdef HAVE_PTHREAD_H
652 xmlGlobalState *globalval;
653
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000654 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000655 return (NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000656
Daniel Veillarde28313b2001-12-06 14:08:31 +0000657 pthread_once(&once_control, xmlOnceInit);
658
Daniel Veillardb8478642001-10-12 17:29:10 +0000659 if ((globalval = (xmlGlobalState *)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000660 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000661 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000662 if (tsd == NULL)
663 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000664
665 pthread_setspecific(globalkey, tsd);
666 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000667 }
668 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000669#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000670#if defined(HAVE_COMPILER_TLS)
671 if (!tlstate_inited) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000672 tlstate_inited = 1;
673 xmlInitializeGlobalState(&tlstate);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000674 }
675 return &tlstate;
676#else /* HAVE_COMPILER_TLS */
677 xmlGlobalState *globalval;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000678 xmlGlobalStateCleanupHelperParams *p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000679
Daniel Veillard62121e22005-02-24 15:38:52 +0000680 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000681#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000682 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000683#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000684 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
685 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000686#endif
687 if (globalval == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000688 xmlGlobalState *tsd = xmlNewGlobalState();
689
690 if (tsd == NULL)
691 return(NULL);
692 p = (xmlGlobalStateCleanupHelperParams *)
693 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
694 if (p == NULL) {
695 xmlGenericError(xmlGenericErrorContext,
696 "xmlGetGlobalState: out of memory\n");
697 return(NULL);
698 }
699 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000700#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000701 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
702 GetCurrentProcess(), &p->thread, 0, TRUE,
703 DUPLICATE_SAME_ACCESS);
704 TlsSetValue(globalkey, tsd);
705 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000706#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000707 EnterCriticalSection(&cleanup_helpers_cs);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000708 if (cleanup_helpers_head != NULL) {
709 cleanup_helpers_head->prev = p;
710 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000711 p->next = cleanup_helpers_head;
712 p->prev = NULL;
713 cleanup_helpers_head = p;
714 TlsSetValue(globalkey, p);
715 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000716#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000717
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000718 return (tsd);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000719 }
720 return (globalval);
721#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000722#elif defined HAVE_BEOS_THREADS
723 xmlGlobalState *globalval;
724
725 xmlOnceInit();
726
Daniel Veillard14d465d2008-03-24 11:12:55 +0000727 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000728 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000729 if (tsd == NULL)
730 return (NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000731
732 tls_set(globalkey, tsd);
733 on_exit_thread(xmlGlobalStateCleanup, NULL);
734 return (tsd);
735 }
736 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000737#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000738 return (NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000739#endif
740}
741
Daniel Veillardb8478642001-10-12 17:29:10 +0000742/************************************************************************
743 * *
744 * Library wide thread interfaces *
745 * *
746 ************************************************************************/
747
748/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000749 * xmlGetThreadId:
750 *
751 * xmlGetThreadId() find the current thread ID number
752 *
753 * Returns the current thread ID number
754 */
755int
756xmlGetThreadId(void)
757{
758#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000759 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000760 return (0);
761 return ((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000762#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000763 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000764#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000765 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000766#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000767 return ((int) 0);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000768#endif
769}
770
771/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000772 * xmlIsMainThread:
773 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000774 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000775 *
776 * Returns 1 if the current thread is the main thread, 0 otherwise
777 */
778int
779xmlIsMainThread(void)
780{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000781#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000782 if (libxml_is_threaded == -1)
783 xmlInitThreads();
784 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000785 return (1);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000786 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000787#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000788 xmlOnceInit();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000789#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000790 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000791#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000792
Daniel Veillard6f350292001-10-14 09:56:15 +0000793#ifdef DEBUG_THREADS
794 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
795#endif
796#ifdef HAVE_PTHREAD_H
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000797 return (mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000798#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000799 return (mainthread == GetCurrentThreadId());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000800#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000801 return (mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000802#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000803 return (1);
Daniel Veillard6f350292001-10-14 09:56:15 +0000804#endif
805}
806
807/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000808 * xmlLockLibrary:
809 *
810 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
811 * library.
812 */
813void
814xmlLockLibrary(void)
815{
Daniel Veillard6f350292001-10-14 09:56:15 +0000816#ifdef DEBUG_THREADS
817 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
818#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000819 xmlRMutexLock(xmlLibraryLock);
820}
821
822/**
823 * xmlUnlockLibrary:
824 *
825 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
826 * library.
827 */
828void
829xmlUnlockLibrary(void)
830{
Daniel Veillard6f350292001-10-14 09:56:15 +0000831#ifdef DEBUG_THREADS
832 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
833#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000834 xmlRMutexUnlock(xmlLibraryLock);
835}
836
837/**
838 * xmlInitThreads:
839 *
840 * xmlInitThreads() is used to to initialize all the thread related
841 * data of the libxml2 library.
842 */
843void
844xmlInitThreads(void)
845{
Daniel Veillard6f350292001-10-14 09:56:15 +0000846#ifdef DEBUG_THREADS
847 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
848#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000849#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000850 InitializeCriticalSection(&cleanup_helpers_cs);
851#endif
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000852#ifdef HAVE_PTHREAD_H
853 if (libxml_is_threaded == -1) {
854 if ((pthread_once != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000855 (pthread_getspecific != NULL) &&
856 (pthread_setspecific != NULL) &&
857 (pthread_key_create != NULL) &&
858 (pthread_mutex_init != NULL) &&
859 (pthread_mutex_destroy != NULL) &&
860 (pthread_mutex_lock != NULL) &&
861 (pthread_mutex_unlock != NULL) &&
862 (pthread_cond_init != NULL) &&
863 (pthread_equal != NULL) &&
864 (pthread_self != NULL) &&
865 (pthread_cond_signal != NULL)) {
866 libxml_is_threaded = 1;
867
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000868/* fprintf(stderr, "Running multithreaded\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000869 } else {
870
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000871/* fprintf(stderr, "Running without multithread\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000872 libxml_is_threaded = 0;
873 }
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000874 }
875#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000876}
877
878/**
879 * xmlCleanupThreads:
880 *
881 * xmlCleanupThreads() is used to to cleanup all the thread related
882 * data of the libxml2 library once processing has ended.
883 */
884void
885xmlCleanupThreads(void)
886{
Daniel Veillard6f350292001-10-14 09:56:15 +0000887#ifdef DEBUG_THREADS
888 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
889#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000890#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000891 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000892 xmlGlobalStateCleanupHelperParams *p;
893
894 EnterCriticalSection(&cleanup_helpers_cs);
895 p = cleanup_helpers_head;
896 while (p != NULL) {
897 xmlGlobalStateCleanupHelperParams *temp = p;
898
899 p = p->next;
900 xmlFreeGlobalState(temp->memory);
901 free(temp);
902 }
903 cleanup_helpers_head = 0;
904 LeaveCriticalSection(&cleanup_helpers_cs);
905 TlsFree(globalkey);
906 globalkey = TLS_OUT_OF_INDEXES;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000907 }
908 DeleteCriticalSection(&cleanup_helpers_cs);
909#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000910}
Daniel Veillard6f350292001-10-14 09:56:15 +0000911
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000912#ifdef LIBXML_THREAD_ENABLED
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000913
Daniel Veillarde28313b2001-12-06 14:08:31 +0000914/**
915 * xmlOnceInit
916 *
917 * xmlOnceInit() is used to initialize the value of mainthread for use
918 * in other routines. This function should only be called using
919 * pthread_once() in association with the once_control variable to ensure
920 * that the function is only called once. See man pthread_once for more
921 * details.
922 */
923static void
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000924xmlOnceInit(void)
925{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000926#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000927 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000928 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000929#endif
930
931#if defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000932 if (!run_once.done) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000933 if (InterlockedIncrement(&run_once.control) == 1) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000934#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000935 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000936#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000937 mainthread = GetCurrentThreadId();
938 run_once.done = 1;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000939 } else {
Daniel Veillard62121e22005-02-24 15:38:52 +0000940 /* Another thread is working; give up our slice and
941 * wait until they're done. */
942 while (!run_once.done)
943 Sleep(0);
944 }
945 }
Daniel Veillarde28313b2001-12-06 14:08:31 +0000946#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000947
948#ifdef HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000949 if (atomic_add(&run_once_init, 1) == 0) {
950 globalkey = tls_allocate();
951 tls_set(globalkey, NULL);
952 mainthread = find_thread(NULL);
953 } else
954 atomic_add(&run_once_init, -1);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000955#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000956}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000957#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000958
959/**
William M. Brack7a821652003-08-15 07:27:40 +0000960 * DllMain:
961 * @hinstDLL: handle to DLL instance
962 * @fdwReason: Reason code for entry
963 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000964 *
965 * Entry point for Windows library. It is being used to free thread-specific
966 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000967 *
968 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000969 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000970#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
971#if defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000972BOOL XMLCALL
973xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000974#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000975BOOL WINAPI
976DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000977#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000978{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000979 switch (fdwReason) {
980 case DLL_THREAD_DETACH:
981 if (globalkey != TLS_OUT_OF_INDEXES) {
982 xmlGlobalState *globalval = NULL;
983 xmlGlobalStateCleanupHelperParams *p =
984 (xmlGlobalStateCleanupHelperParams *)
985 TlsGetValue(globalkey);
986 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
987 if (globalval) {
988 xmlFreeGlobalState(globalval);
989 TlsSetValue(globalkey, NULL);
990 }
991 if (p) {
992 EnterCriticalSection(&cleanup_helpers_cs);
993 if (p == cleanup_helpers_head)
994 cleanup_helpers_head = p->next;
995 else
996 p->prev->next = p->next;
997 if (p->next != NULL)
998 p->next->prev = p->prev;
999 LeaveCriticalSection(&cleanup_helpers_cs);
1000 free(p);
1001 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001002 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +00001003 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +00001004 }
1005 return TRUE;
1006}
1007#endif
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001008#define bottom_threads
1009#include "elfgcchack.h"