blob: 678977dffba10b071684e1f555ea6df85c1b289c [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
49/*
50 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
51 * to avoid some crazyness since xmlMalloc/xmlFree may actually
52 * be hosted on allocated blocks needing them for the allocation ...
53 */
54
55/*
56 * xmlMutex are a simple mutual exception locks
57 */
58struct _xmlMutex {
59#ifdef HAVE_PTHREAD_H
60 pthread_mutex_t lock;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000061#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +000062 HANDLE mutex;
Daniel Veillard82cb3192003-10-29 13:39:15 +000063#elif defined HAVE_BEOS_THREADS
64 sem_id sem;
Daniel Veillard254b1262003-11-01 17:04:58 +000065 thread_id tid;
Daniel Veillardb8478642001-10-12 17:29:10 +000066#else
67 int empty;
68#endif
69};
70
71/*
72 * xmlRMutex are reentrant mutual exception locks
73 */
74struct _xmlRMutex {
75#ifdef HAVE_PTHREAD_H
76 pthread_mutex_t lock;
77 unsigned int held;
78 unsigned int waiters;
79 pthread_t tid;
80 pthread_cond_t cv;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000081#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +000082 CRITICAL_SECTION cs;
83 unsigned int count;
Daniel Veillard82cb3192003-10-29 13:39:15 +000084#elif defined HAVE_BEOS_THREADS
85 xmlMutexPtr lock;
86 thread_id tid;
87 int32 count;
Daniel Veillardb8478642001-10-12 17:29:10 +000088#else
89 int empty;
90#endif
91};
92/*
93 * This module still has some internal static data.
94 * - xmlLibraryLock a global lock
95 * - globalkey used for per-thread data
Daniel Veillardb8478642001-10-12 17:29:10 +000096 */
Daniel Veillard6f350292001-10-14 09:56:15 +000097
Daniel Veillardb8478642001-10-12 17:29:10 +000098#ifdef HAVE_PTHREAD_H
Daniel Veillardb8478642001-10-12 17:29:10 +000099static pthread_key_t globalkey;
Daniel Veillard6f350292001-10-14 09:56:15 +0000100static pthread_t mainthread;
Daniel Veillarde28313b2001-12-06 14:08:31 +0000101static pthread_once_t once_control = PTHREAD_ONCE_INIT;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000102#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000103#if defined(HAVE_COMPILER_TLS)
104static __declspec(thread) xmlGlobalState tlstate;
105static __declspec(thread) int tlstate_inited = 0;
106#else /* HAVE_COMPILER_TLS */
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000107static DWORD globalkey = TLS_OUT_OF_INDEXES;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000108#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000109static DWORD mainthread;
Daniel Veillard62121e22005-02-24 15:38:52 +0000110static struct
111{
112 int32 done;
113 int32; control;
114} run_once = { 0, 0 };
Daniel Veillard82cb3192003-10-29 13:39:15 +0000115/* endif HAVE_WIN32_THREADS */
116#elif defined HAVE_BEOS_THREADS
117int32 globalkey = 0;
118thread_id mainthread = 0;
119int32 run_once_init = 0;
120#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000121
Daniel Veillardb8478642001-10-12 17:29:10 +0000122static xmlRMutexPtr xmlLibraryLock = NULL;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000123#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000124static void xmlOnceInit(void);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000125#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000126
127/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000128 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000129 *
130 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
131 * synchronizing access to data.
132 *
133 * Returns a new simple mutex pointer or NULL in case of error
134 */
135xmlMutexPtr
136xmlNewMutex(void)
137{
138 xmlMutexPtr tok;
139
140 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
141 return (NULL);
142#ifdef HAVE_PTHREAD_H
143 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000144#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000145 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000146#elif defined HAVE_BEOS_THREADS
147 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
148 free(tok);
149 return NULL;
150 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000151 tok->tid = -1;
Daniel Veillardb8478642001-10-12 17:29:10 +0000152#endif
153 return (tok);
154}
155
156/**
157 * xmlFreeMutex:
158 * @tok: the simple mutex
159 *
160 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
161 * struct.
162 */
163void
164xmlFreeMutex(xmlMutexPtr tok)
165{
Daniel Veillarddf101d82003-07-08 14:03:36 +0000166 if (tok == NULL) return;
167
Daniel Veillardb8478642001-10-12 17:29:10 +0000168#ifdef HAVE_PTHREAD_H
169 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000170#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000171 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000172#elif defined HAVE_BEOS_THREADS
173 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000174#endif
175 free(tok);
176}
177
178/**
179 * xmlMutexLock:
180 * @tok: the simple mutex
181 *
182 * xmlMutexLock() is used to lock a libxml2 token.
183 */
184void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000185xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000186{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000187 if (tok == NULL)
188 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000189#ifdef HAVE_PTHREAD_H
190 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000191#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000192 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000193#elif defined HAVE_BEOS_THREADS
194 if (acquire_sem(tok->sem) != B_NO_ERROR) {
195#ifdef DEBUG_THREADS
196 xmlGenericError(xmlGenericErrorContext, "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
197 exit();
198#endif
199 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000200 tok->tid = find_thread(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000201#endif
202
203}
204
205/**
206 * xmlMutexUnlock:
207 * @tok: the simple mutex
208 *
209 * xmlMutexUnlock() is used to unlock a libxml2 token.
210 */
211void
Daniel Veillard5805be22003-08-28 08:03:23 +0000212xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000213{
Daniel Veillard5805be22003-08-28 08:03:23 +0000214 if (tok == NULL)
215 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000216#ifdef HAVE_PTHREAD_H
217 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000218#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000219 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000220#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000221 if (tok->tid == find_thread(NULL)) {
222 tok->tid = -1;
223 release_sem(tok->sem);
224 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000225#endif
226}
227
228/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000229 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000230 *
231 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
232 * synchronizing access to data. token_r is a re-entrant lock and thus useful
233 * for synchronizing access to data structures that may be manipulated in a
234 * recursive fashion.
235 *
236 * Returns the new reentrant mutex pointer or NULL in case of error
237 */
238xmlRMutexPtr
239xmlNewRMutex(void)
240{
241 xmlRMutexPtr tok;
242
243 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
244 return (NULL);
245#ifdef HAVE_PTHREAD_H
246 pthread_mutex_init(&tok->lock, NULL);
247 tok->held = 0;
248 tok->waiters = 0;
William M. Brack59002e72003-07-04 17:01:59 +0000249 pthread_cond_init(&tok->cv, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000250#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000251 InitializeCriticalSection(&tok->cs);
252 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000253#elif defined HAVE_BEOS_THREADS
254 if ((tok->lock = xmlNewMutex()) == NULL) {
255 free(tok);
256 return NULL;
257 }
258 tok->count = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000259#endif
260 return (tok);
261}
262
263/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000264 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000265 * @tok: the reentrant mutex
266 *
267 * xmlRFreeMutex() is used to reclaim resources associated with a
268 * reentrant mutex.
269 */
270void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000271xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000272{
273#ifdef HAVE_PTHREAD_H
274 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000275#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000276 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000277#elif defined HAVE_BEOS_THREADS
278 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000279#endif
280 free(tok);
281}
282
283/**
284 * xmlRMutexLock:
285 * @tok: the reentrant mutex
286 *
287 * xmlRMutexLock() is used to lock a libxml2 token_r.
288 */
289void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000290xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000291{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000292 if (tok == NULL)
293 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000294#ifdef HAVE_PTHREAD_H
295 pthread_mutex_lock(&tok->lock);
296 if (tok->held) {
297 if (pthread_equal(tok->tid, pthread_self())) {
298 tok->held++;
299 pthread_mutex_unlock(&tok->lock);
300 return;
301 } else {
302 tok->waiters++;
303 while (tok->held)
304 pthread_cond_wait(&tok->cv, &tok->lock);
305 tok->waiters--;
306 }
307 }
308 tok->tid = pthread_self();
309 tok->held = 1;
310 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000311#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000312 EnterCriticalSection(&tok->cs);
313 ++tok->count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000314#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000315 if (tok->lock->tid == find_thread(NULL)) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000316 tok->count++;
317 return;
318 } else {
319 xmlMutexLock(tok->lock);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000320 tok->count = 1;
321 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000322#endif
323}
324
325/**
326 * xmlRMutexUnlock:
327 * @tok: the reentrant mutex
328 *
329 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
330 */
331void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000332xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000333{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000334 if (tok == NULL)
335 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000336#ifdef HAVE_PTHREAD_H
337 pthread_mutex_lock(&tok->lock);
338 tok->held--;
339 if (tok->held == 0) {
340 if (tok->waiters)
341 pthread_cond_signal(&tok->cv);
342 tok->tid = 0;
343 }
344 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000345#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000346 if (!--tok->count)
347 LeaveCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000348#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000349 if (tok->lock->tid == find_thread(NULL)) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000350 tok->count--;
351 if (tok->count == 0) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000352 xmlMutexUnlock(tok->lock);
353 }
354 return;
355 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000356#endif
357}
358
359/************************************************************************
360 * *
361 * Per thread global state handling *
362 * *
363 ************************************************************************/
364
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000365#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000366#ifdef xmlLastError
367#undef xmlLastError
368#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000369/**
370 * xmlFreeGlobalState:
371 * @state: a thread global state
372 *
373 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
374 * global state. It is is used here to reclaim memory resources.
375 */
376static void
377xmlFreeGlobalState(void *state)
378{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000379 xmlGlobalState *gs = (xmlGlobalState *) state;
380
381 /* free any memory allocated in the thread's xmlLastError */
382 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000383 free(state);
384}
385
386/**
387 * xmlNewGlobalState:
388 *
389 * xmlNewGlobalState() allocates a global state. This structure is used to
390 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000391 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000392 *
393 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
394 */
395static xmlGlobalStatePtr
396xmlNewGlobalState(void)
397{
398 xmlGlobalState *gs;
399
400 gs = malloc(sizeof(xmlGlobalState));
401 if (gs == NULL)
402 return(NULL);
403
William M. Brack8b2c7f12002-11-22 05:07:29 +0000404 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000405 xmlInitializeGlobalState(gs);
406 return (gs);
407}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000408#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000409
410
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000411#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000412#if !defined(HAVE_COMPILER_TLS)
413#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000414typedef struct _xmlGlobalStateCleanupHelperParams
415{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000416 HANDLE thread;
417 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000418} xmlGlobalStateCleanupHelperParams;
419
Daniel Veillard01c13b52002-12-10 15:19:08 +0000420static void xmlGlobalStateCleanupHelper (void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000421{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000422 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
423 WaitForSingleObject(params->thread, INFINITE);
424 CloseHandle(params->thread);
425 xmlFreeGlobalState(params->memory);
426 free(params);
427 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000428}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000429#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
430
431typedef struct _xmlGlobalStateCleanupHelperParams
432{
433 void *memory;
434 struct _xmlGlobalStateCleanupHelperParams * prev;
435 struct _xmlGlobalStateCleanupHelperParams * next;
436} xmlGlobalStateCleanupHelperParams;
437
438static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL;
439static CRITICAL_SECTION cleanup_helpers_cs;
440
441#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
442#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000443#endif /* HAVE_WIN32_THREADS */
444
Daniel Veillard82cb3192003-10-29 13:39:15 +0000445#if defined HAVE_BEOS_THREADS
William M. Brackb1d53162003-11-18 06:54:40 +0000446/**
447 * xmlGlobalStateCleanup:
448 * @data: unused parameter
449 *
450 * Used for Beos only
451 */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000452void xmlGlobalStateCleanup(void *data)
453{
454 void *globalval = tls_get(globalkey);
455 if (globalval != NULL)
456 xmlFreeGlobalState(globalval);
457}
458#endif
459
Daniel Veillard01c13b52002-12-10 15:19:08 +0000460/**
461 * xmlGetGlobalState:
462 *
463 * xmlGetGlobalState() is called to retrieve the global state for a thread.
464 *
465 * Returns the thread global state or NULL in case of error
466 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000467xmlGlobalStatePtr
468xmlGetGlobalState(void)
469{
470#ifdef HAVE_PTHREAD_H
471 xmlGlobalState *globalval;
472
Daniel Veillarde28313b2001-12-06 14:08:31 +0000473 pthread_once(&once_control, xmlOnceInit);
474
Daniel Veillardb8478642001-10-12 17:29:10 +0000475 if ((globalval = (xmlGlobalState *)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000476 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000477 xmlGlobalState *tsd = xmlNewGlobalState();
478
479 pthread_setspecific(globalkey, tsd);
480 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000481 }
482 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000483#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000484#if defined(HAVE_COMPILER_TLS)
485 if (!tlstate_inited) {
486 tlstate_inited = 1;
487 xmlInitializeGlobalState(&tlstate);
488 }
489 return &tlstate;
490#else /* HAVE_COMPILER_TLS */
491 xmlGlobalState *globalval;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000492 xmlGlobalStateCleanupHelperParams * p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000493
Daniel Veillard62121e22005-02-24 15:38:52 +0000494 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000495#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
496 globalval = (xmlGlobalState *)TlsGetValue(globalkey);
497#else
498 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
499 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
500#endif
501 if (globalval == NULL) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000502 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000503 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000504 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000505#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000506 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
507 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
508 TlsSetValue(globalkey, tsd);
509 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000510#else
511 EnterCriticalSection(&cleanup_helpers_cs);
512 if (cleanup_helpers_head != NULL) {
513 cleanup_helpers_head->prev = p;
514 }
515 p->next = cleanup_helpers_head;
516 p->prev = NULL;
517 cleanup_helpers_head = p;
518 TlsSetValue(globalkey, p);
519 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000520#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000521
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000522 return (tsd);
523 }
524 return (globalval);
525#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000526#elif defined HAVE_BEOS_THREADS
527 xmlGlobalState *globalval;
528
529 xmlOnceInit();
530
531 if ((globalval = (xmlGlobalState *)
532 tls_get(globalkey)) == NULL) {
533 xmlGlobalState *tsd = xmlNewGlobalState();
534
535 tls_set(globalkey, tsd);
536 on_exit_thread(xmlGlobalStateCleanup, NULL);
537 return (tsd);
538 }
539 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000540#else
541 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000542#endif
543}
544
Daniel Veillardb8478642001-10-12 17:29:10 +0000545/************************************************************************
546 * *
547 * Library wide thread interfaces *
548 * *
549 ************************************************************************/
550
551/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000552 * xmlGetThreadId:
553 *
554 * xmlGetThreadId() find the current thread ID number
555 *
556 * Returns the current thread ID number
557 */
558int
559xmlGetThreadId(void)
560{
561#ifdef HAVE_PTHREAD_H
562 return((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000563#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000564 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000565#elif defined HAVE_BEOS_THREADS
566 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000567#else
568 return((int) 0);
569#endif
570}
571
572/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000573 * xmlIsMainThread:
574 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000575 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000576 *
577 * Returns 1 if the current thread is the main thread, 0 otherwise
578 */
579int
580xmlIsMainThread(void)
581{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000582#ifdef HAVE_PTHREAD_H
583 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000584#elif defined HAVE_WIN32_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000585 xmlOnceInit ();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000586#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000587 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000588#endif
Daniel Veillard6f350292001-10-14 09:56:15 +0000589
590#ifdef DEBUG_THREADS
591 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
592#endif
593#ifdef HAVE_PTHREAD_H
594 return(mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000595#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000596 return(mainthread == GetCurrentThreadId ());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000597#elif defined HAVE_BEOS_THREADS
598 return(mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000599#else
600 return(1);
601#endif
602}
603
604/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000605 * xmlLockLibrary:
606 *
607 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
608 * library.
609 */
610void
611xmlLockLibrary(void)
612{
Daniel Veillard6f350292001-10-14 09:56:15 +0000613#ifdef DEBUG_THREADS
614 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
615#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000616 xmlRMutexLock(xmlLibraryLock);
617}
618
619/**
620 * xmlUnlockLibrary:
621 *
622 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
623 * library.
624 */
625void
626xmlUnlockLibrary(void)
627{
Daniel Veillard6f350292001-10-14 09:56:15 +0000628#ifdef DEBUG_THREADS
629 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
630#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000631 xmlRMutexUnlock(xmlLibraryLock);
632}
633
634/**
635 * xmlInitThreads:
636 *
637 * xmlInitThreads() is used to to initialize all the thread related
638 * data of the libxml2 library.
639 */
640void
641xmlInitThreads(void)
642{
Daniel Veillard6f350292001-10-14 09:56:15 +0000643#ifdef DEBUG_THREADS
644 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
645#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000646#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000647 InitializeCriticalSection(&cleanup_helpers_cs);
648#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000649}
650
651/**
652 * xmlCleanupThreads:
653 *
654 * xmlCleanupThreads() is used to to cleanup all the thread related
655 * data of the libxml2 library once processing has ended.
656 */
657void
658xmlCleanupThreads(void)
659{
Daniel Veillard6f350292001-10-14 09:56:15 +0000660#ifdef DEBUG_THREADS
661 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
662#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000663#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000664 if (globalkey != TLS_OUT_OF_INDEXES) {
665 xmlGlobalStateCleanupHelperParams * p;
666 EnterCriticalSection(&cleanup_helpers_cs);
667 p = cleanup_helpers_head;
668 while (p != NULL) {
669 xmlGlobalStateCleanupHelperParams * temp = p;
670 p = p->next;
671 xmlFreeGlobalState(temp->memory);
672 free(temp);
673 }
674 cleanup_helpers_head = 0;
675 LeaveCriticalSection(&cleanup_helpers_cs);
676 TlsFree(globalkey);
677 globalkey = TLS_OUT_OF_INDEXES;
678 }
679 DeleteCriticalSection(&cleanup_helpers_cs);
680#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000681}
Daniel Veillard6f350292001-10-14 09:56:15 +0000682
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000683#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000684/**
685 * xmlOnceInit
686 *
687 * xmlOnceInit() is used to initialize the value of mainthread for use
688 * in other routines. This function should only be called using
689 * pthread_once() in association with the once_control variable to ensure
690 * that the function is only called once. See man pthread_once for more
691 * details.
692 */
693static void
694xmlOnceInit(void) {
695#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000696 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000697 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000698#endif
699
700#if defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000701 if (!run_once.done) {
702 if (InterlockedIncrement(&run_once.control) == 0)
703 {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000704#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000705 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000706#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000707 mainthread = GetCurrentThreadId();
708 run_once.done = 1;
709 }
710 else {
711 /* Another thread is working; give up our slice and
712 * wait until they're done. */
713 while (!run_once.done)
714 Sleep(0);
715 }
716 }
Daniel Veillarde28313b2001-12-06 14:08:31 +0000717#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000718
719#ifdef HAVE_BEOS_THREADS
720 if (atomic_add(&run_once_init, 1) == 0) {
721 globalkey = tls_allocate();
722 tls_set(globalkey, NULL);
723 mainthread = find_thread(NULL);
724 } else
725 atomic_add(&run_once_init, -1);
726#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000727}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000728#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000729
730/**
William M. Brack7a821652003-08-15 07:27:40 +0000731 * DllMain:
732 * @hinstDLL: handle to DLL instance
733 * @fdwReason: Reason code for entry
734 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000735 *
736 * Entry point for Windows library. It is being used to free thread-specific
737 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000738 *
739 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000740 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000741#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
742#if defined(LIBXML_STATIC_FOR_DLL)
743BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
744#else
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000745BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000746#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000747{
748 switch(fdwReason) {
749 case DLL_THREAD_DETACH:
750 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000751 xmlGlobalState *globalval = NULL;
752 xmlGlobalStateCleanupHelperParams * p =
753 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
754 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
755 if (globalval) {
756 xmlFreeGlobalState(globalval);
757 TlsSetValue(globalkey,NULL);
758 }
759 if (p)
760 {
761 EnterCriticalSection(&cleanup_helpers_cs);
762 if (p == cleanup_helpers_head)
763 cleanup_helpers_head = p->next;
764 else
765 p->prev->next = p->next;
766 if (p->next != NULL)
767 p->next->prev = p->prev;
768 LeaveCriticalSection(&cleanup_helpers_cs);
769 free(p);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000770 }
771 }
772 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000773 }
774 return TRUE;
775}
776#endif