blob: 97ea5d4f607fa368a63a599bf07472cb026c0c4a [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
507 LeaveCriticalSection(global_init_lock);
508#elif defined HAVE_BEOS_THREADS
509 release_sem(global_init_lock);
510#endif
511}
512
Rob Richards91eb5602007-11-16 10:54:59 +0000513/**
514 * xmlGlobalInitMutexDestroy
515 *
516 * Makes sure that the global initialization mutex is destroyed before
517 * application termination.
518 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000519void
520__xmlGlobalInitMutexDestroy(void)
Rob Richards91eb5602007-11-16 10:54:59 +0000521{
522#if defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000523 if (global_init_lock != NULL) {
524 DeleteCriticalSection(global_init_lock);
525 free(global_init_lock);
526 global_init_lock = NULL;
Rob Richards91eb5602007-11-16 10:54:59 +0000527 }
528#endif
529}
530
Daniel Veillardb8478642001-10-12 17:29:10 +0000531/************************************************************************
532 * *
533 * Per thread global state handling *
534 * *
535 ************************************************************************/
536
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000537#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000538#ifdef xmlLastError
539#undef xmlLastError
540#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000541
Daniel Veillardb8478642001-10-12 17:29:10 +0000542/**
543 * xmlFreeGlobalState:
544 * @state: a thread global state
545 *
546 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
547 * global state. It is is used here to reclaim memory resources.
548 */
549static void
550xmlFreeGlobalState(void *state)
551{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000552 xmlGlobalState *gs = (xmlGlobalState *) state;
553
554 /* free any memory allocated in the thread's xmlLastError */
555 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000556 free(state);
557}
558
559/**
560 * xmlNewGlobalState:
561 *
562 * xmlNewGlobalState() allocates a global state. This structure is used to
563 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000564 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000565 *
566 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
567 */
568static xmlGlobalStatePtr
569xmlNewGlobalState(void)
570{
571 xmlGlobalState *gs;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000572
Daniel Veillardb8478642001-10-12 17:29:10 +0000573 gs = malloc(sizeof(xmlGlobalState));
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000574 if (gs == NULL) {
575 xmlGenericError(xmlGenericErrorContext,
576 "xmlGetGlobalState: out of memory\n");
577 return (NULL);
578 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000579
William M. Brack8b2c7f12002-11-22 05:07:29 +0000580 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000581 xmlInitializeGlobalState(gs);
582 return (gs);
583}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000584#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000585
586
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000587#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000588#if !defined(HAVE_COMPILER_TLS)
589#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000590typedef struct _xmlGlobalStateCleanupHelperParams {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000591 HANDLE thread;
592 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000593} xmlGlobalStateCleanupHelperParams;
594
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000595static void XMLCDECL
596xmlGlobalStateCleanupHelper(void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000597{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000598 xmlGlobalStateCleanupHelperParams *params =
599 (xmlGlobalStateCleanupHelperParams *) p;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000600 WaitForSingleObject(params->thread, INFINITE);
601 CloseHandle(params->thread);
602 xmlFreeGlobalState(params->memory);
603 free(params);
604 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000605}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000606#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
607
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000608typedef struct _xmlGlobalStateCleanupHelperParams {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000609 void *memory;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000610 struct _xmlGlobalStateCleanupHelperParams *prev;
611 struct _xmlGlobalStateCleanupHelperParams *next;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000612} xmlGlobalStateCleanupHelperParams;
613
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000614static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000615static CRITICAL_SECTION cleanup_helpers_cs;
616
617#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
618#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000619#endif /* HAVE_WIN32_THREADS */
620
Daniel Veillard82cb3192003-10-29 13:39:15 +0000621#if defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000622
William M. Brackb1d53162003-11-18 06:54:40 +0000623/**
624 * xmlGlobalStateCleanup:
625 * @data: unused parameter
626 *
627 * Used for Beos only
628 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000629void
630xmlGlobalStateCleanup(void *data)
Daniel Veillard82cb3192003-10-29 13:39:15 +0000631{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000632 void *globalval = tls_get(globalkey);
633
634 if (globalval != NULL)
635 xmlFreeGlobalState(globalval);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000636}
637#endif
638
Daniel Veillard01c13b52002-12-10 15:19:08 +0000639/**
640 * xmlGetGlobalState:
641 *
642 * xmlGetGlobalState() is called to retrieve the global state for a thread.
643 *
644 * Returns the thread global state or NULL in case of error
645 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000646xmlGlobalStatePtr
647xmlGetGlobalState(void)
648{
649#ifdef HAVE_PTHREAD_H
650 xmlGlobalState *globalval;
651
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000652 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000653 return (NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000654
Daniel Veillarde28313b2001-12-06 14:08:31 +0000655 pthread_once(&once_control, xmlOnceInit);
656
Daniel Veillardb8478642001-10-12 17:29:10 +0000657 if ((globalval = (xmlGlobalState *)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000658 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000659 xmlGlobalState *tsd = xmlNewGlobalState();
660
661 pthread_setspecific(globalkey, tsd);
662 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000663 }
664 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000665#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000666#if defined(HAVE_COMPILER_TLS)
667 if (!tlstate_inited) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000668 tlstate_inited = 1;
669 xmlInitializeGlobalState(&tlstate);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000670 }
671 return &tlstate;
672#else /* HAVE_COMPILER_TLS */
673 xmlGlobalState *globalval;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000674 xmlGlobalStateCleanupHelperParams *p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000675
Daniel Veillard62121e22005-02-24 15:38:52 +0000676 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000677#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000678 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000679#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000680 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
681 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000682#endif
683 if (globalval == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000684 xmlGlobalState *tsd = xmlNewGlobalState();
685
686 if (tsd == NULL)
687 return(NULL);
688 p = (xmlGlobalStateCleanupHelperParams *)
689 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
690 if (p == NULL) {
691 xmlGenericError(xmlGenericErrorContext,
692 "xmlGetGlobalState: out of memory\n");
693 return(NULL);
694 }
695 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000696#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000697 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
698 GetCurrentProcess(), &p->thread, 0, TRUE,
699 DUPLICATE_SAME_ACCESS);
700 TlsSetValue(globalkey, tsd);
701 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000702#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000703 EnterCriticalSection(&cleanup_helpers_cs);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000704 if (cleanup_helpers_head != NULL) {
705 cleanup_helpers_head->prev = p;
706 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000707 p->next = cleanup_helpers_head;
708 p->prev = NULL;
709 cleanup_helpers_head = p;
710 TlsSetValue(globalkey, p);
711 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000712#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000713
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000714 return (tsd);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000715 }
716 return (globalval);
717#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000718#elif defined HAVE_BEOS_THREADS
719 xmlGlobalState *globalval;
720
721 xmlOnceInit();
722
723 if ((globalval = (xmlGlobalState *)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000724 tls_get(globalkey)) == NULL) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000725 xmlGlobalState *tsd = xmlNewGlobalState();
726
727 tls_set(globalkey, tsd);
728 on_exit_thread(xmlGlobalStateCleanup, NULL);
729 return (tsd);
730 }
731 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000732#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000733 return (NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000734#endif
735}
736
Daniel Veillardb8478642001-10-12 17:29:10 +0000737/************************************************************************
738 * *
739 * Library wide thread interfaces *
740 * *
741 ************************************************************************/
742
743/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000744 * xmlGetThreadId:
745 *
746 * xmlGetThreadId() find the current thread ID number
747 *
748 * Returns the current thread ID number
749 */
750int
751xmlGetThreadId(void)
752{
753#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000754 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000755 return (0);
756 return ((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000757#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000758 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000759#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000760 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000761#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000762 return ((int) 0);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000763#endif
764}
765
766/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000767 * xmlIsMainThread:
768 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000769 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000770 *
771 * Returns 1 if the current thread is the main thread, 0 otherwise
772 */
773int
774xmlIsMainThread(void)
775{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000776#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000777 if (libxml_is_threaded == -1)
778 xmlInitThreads();
779 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000780 return (1);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000781 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000782#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000783 xmlOnceInit();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000784#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000785 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000786#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000787
Daniel Veillard6f350292001-10-14 09:56:15 +0000788#ifdef DEBUG_THREADS
789 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
790#endif
791#ifdef HAVE_PTHREAD_H
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000792 return (mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000793#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000794 return (mainthread == GetCurrentThreadId());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000795#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000796 return (mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000797#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000798 return (1);
Daniel Veillard6f350292001-10-14 09:56:15 +0000799#endif
800}
801
802/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000803 * xmlLockLibrary:
804 *
805 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
806 * library.
807 */
808void
809xmlLockLibrary(void)
810{
Daniel Veillard6f350292001-10-14 09:56:15 +0000811#ifdef DEBUG_THREADS
812 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
813#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000814 xmlRMutexLock(xmlLibraryLock);
815}
816
817/**
818 * xmlUnlockLibrary:
819 *
820 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
821 * library.
822 */
823void
824xmlUnlockLibrary(void)
825{
Daniel Veillard6f350292001-10-14 09:56:15 +0000826#ifdef DEBUG_THREADS
827 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
828#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000829 xmlRMutexUnlock(xmlLibraryLock);
830}
831
832/**
833 * xmlInitThreads:
834 *
835 * xmlInitThreads() is used to to initialize all the thread related
836 * data of the libxml2 library.
837 */
838void
839xmlInitThreads(void)
840{
Daniel Veillard6f350292001-10-14 09:56:15 +0000841#ifdef DEBUG_THREADS
842 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
843#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000844#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000845 InitializeCriticalSection(&cleanup_helpers_cs);
846#endif
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000847#ifdef HAVE_PTHREAD_H
848 if (libxml_is_threaded == -1) {
849 if ((pthread_once != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000850 (pthread_getspecific != NULL) &&
851 (pthread_setspecific != NULL) &&
852 (pthread_key_create != NULL) &&
853 (pthread_mutex_init != NULL) &&
854 (pthread_mutex_destroy != NULL) &&
855 (pthread_mutex_lock != NULL) &&
856 (pthread_mutex_unlock != NULL) &&
857 (pthread_cond_init != NULL) &&
858 (pthread_equal != NULL) &&
859 (pthread_self != NULL) &&
860 (pthread_cond_signal != NULL)) {
861 libxml_is_threaded = 1;
862
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000863/* fprintf(stderr, "Running multithreaded\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000864 } else {
865
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000866/* fprintf(stderr, "Running without multithread\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000867 libxml_is_threaded = 0;
868 }
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000869 }
870#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000871}
872
873/**
874 * xmlCleanupThreads:
875 *
876 * xmlCleanupThreads() is used to to cleanup all the thread related
877 * data of the libxml2 library once processing has ended.
878 */
879void
880xmlCleanupThreads(void)
881{
Daniel Veillard6f350292001-10-14 09:56:15 +0000882#ifdef DEBUG_THREADS
883 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
884#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000885#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000886 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000887 xmlGlobalStateCleanupHelperParams *p;
888
889 EnterCriticalSection(&cleanup_helpers_cs);
890 p = cleanup_helpers_head;
891 while (p != NULL) {
892 xmlGlobalStateCleanupHelperParams *temp = p;
893
894 p = p->next;
895 xmlFreeGlobalState(temp->memory);
896 free(temp);
897 }
898 cleanup_helpers_head = 0;
899 LeaveCriticalSection(&cleanup_helpers_cs);
900 TlsFree(globalkey);
901 globalkey = TLS_OUT_OF_INDEXES;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000902 }
903 DeleteCriticalSection(&cleanup_helpers_cs);
904#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000905}
Daniel Veillard6f350292001-10-14 09:56:15 +0000906
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000907#ifdef LIBXML_THREAD_ENABLED
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000908
Daniel Veillarde28313b2001-12-06 14:08:31 +0000909/**
910 * xmlOnceInit
911 *
912 * xmlOnceInit() is used to initialize the value of mainthread for use
913 * in other routines. This function should only be called using
914 * pthread_once() in association with the once_control variable to ensure
915 * that the function is only called once. See man pthread_once for more
916 * details.
917 */
918static void
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000919xmlOnceInit(void)
920{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000921#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000922 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000923 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000924#endif
925
926#if defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000927 if (!run_once.done) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000928 if (InterlockedIncrement(&run_once.control) == 1) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000929#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000930 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000931#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000932 mainthread = GetCurrentThreadId();
933 run_once.done = 1;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000934 } else {
Daniel Veillard62121e22005-02-24 15:38:52 +0000935 /* Another thread is working; give up our slice and
936 * wait until they're done. */
937 while (!run_once.done)
938 Sleep(0);
939 }
940 }
Daniel Veillarde28313b2001-12-06 14:08:31 +0000941#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000942
943#ifdef HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000944 if (atomic_add(&run_once_init, 1) == 0) {
945 globalkey = tls_allocate();
946 tls_set(globalkey, NULL);
947 mainthread = find_thread(NULL);
948 } else
949 atomic_add(&run_once_init, -1);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000950#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000951}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000952#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000953
954/**
William M. Brack7a821652003-08-15 07:27:40 +0000955 * DllMain:
956 * @hinstDLL: handle to DLL instance
957 * @fdwReason: Reason code for entry
958 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000959 *
960 * Entry point for Windows library. It is being used to free thread-specific
961 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000962 *
963 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000964 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000965#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
966#if defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000967BOOL XMLCALL
968xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000969#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000970BOOL WINAPI
971DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000972#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000973{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000974 switch (fdwReason) {
975 case DLL_THREAD_DETACH:
976 if (globalkey != TLS_OUT_OF_INDEXES) {
977 xmlGlobalState *globalval = NULL;
978 xmlGlobalStateCleanupHelperParams *p =
979 (xmlGlobalStateCleanupHelperParams *)
980 TlsGetValue(globalkey);
981 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
982 if (globalval) {
983 xmlFreeGlobalState(globalval);
984 TlsSetValue(globalkey, NULL);
985 }
986 if (p) {
987 EnterCriticalSection(&cleanup_helpers_cs);
988 if (p == cleanup_helpers_head)
989 cleanup_helpers_head = p->next;
990 else
991 p->prev->next = p->next;
992 if (p->next != NULL)
993 p->next->prev = p->prev;
994 LeaveCriticalSection(&cleanup_helpers_cs);
995 free(p);
996 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000997 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000998 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000999 }
1000 return TRUE;
1001}
1002#endif
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001003#define bottom_threads
1004#include "elfgcchack.h"