blob: 30a88ed891cd9703ba9e34df4020901333c69c3e [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;
110static int run_once_init = 1;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000111/* endif HAVE_WIN32_THREADS */
112#elif defined HAVE_BEOS_THREADS
113int32 globalkey = 0;
114thread_id mainthread = 0;
115int32 run_once_init = 0;
116#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000117
Daniel Veillardb8478642001-10-12 17:29:10 +0000118static xmlRMutexPtr xmlLibraryLock = NULL;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000119#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000120static void xmlOnceInit(void);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000121#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000122
123/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000124 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000125 *
126 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
127 * synchronizing access to data.
128 *
129 * Returns a new simple mutex pointer or NULL in case of error
130 */
131xmlMutexPtr
132xmlNewMutex(void)
133{
134 xmlMutexPtr tok;
135
136 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
137 return (NULL);
138#ifdef HAVE_PTHREAD_H
139 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000140#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000141 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000142#elif defined HAVE_BEOS_THREADS
143 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
144 free(tok);
145 return NULL;
146 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000147 tok->tid = -1;
Daniel Veillardb8478642001-10-12 17:29:10 +0000148#endif
149 return (tok);
150}
151
152/**
153 * xmlFreeMutex:
154 * @tok: the simple mutex
155 *
156 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
157 * struct.
158 */
159void
160xmlFreeMutex(xmlMutexPtr tok)
161{
Daniel Veillarddf101d82003-07-08 14:03:36 +0000162 if (tok == NULL) return;
163
Daniel Veillardb8478642001-10-12 17:29:10 +0000164#ifdef HAVE_PTHREAD_H
165 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000166#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000167 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000168#elif defined HAVE_BEOS_THREADS
169 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000170#endif
171 free(tok);
172}
173
174/**
175 * xmlMutexLock:
176 * @tok: the simple mutex
177 *
178 * xmlMutexLock() is used to lock a libxml2 token.
179 */
180void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000181xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000182{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000183 if (tok == NULL)
184 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000185#ifdef HAVE_PTHREAD_H
186 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000187#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000188 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000189#elif defined HAVE_BEOS_THREADS
190 if (acquire_sem(tok->sem) != B_NO_ERROR) {
191#ifdef DEBUG_THREADS
192 xmlGenericError(xmlGenericErrorContext, "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
193 exit();
194#endif
195 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000196 tok->tid = find_thread(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000197#endif
198
199}
200
201/**
202 * xmlMutexUnlock:
203 * @tok: the simple mutex
204 *
205 * xmlMutexUnlock() is used to unlock a libxml2 token.
206 */
207void
Daniel Veillard5805be22003-08-28 08:03:23 +0000208xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000209{
Daniel Veillard5805be22003-08-28 08:03:23 +0000210 if (tok == NULL)
211 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000212#ifdef HAVE_PTHREAD_H
213 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000214#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000215 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000216#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000217 if (tok->tid == find_thread(NULL)) {
218 tok->tid = -1;
219 release_sem(tok->sem);
220 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000221#endif
222}
223
224/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000225 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000226 *
227 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
228 * synchronizing access to data. token_r is a re-entrant lock and thus useful
229 * for synchronizing access to data structures that may be manipulated in a
230 * recursive fashion.
231 *
232 * Returns the new reentrant mutex pointer or NULL in case of error
233 */
234xmlRMutexPtr
235xmlNewRMutex(void)
236{
237 xmlRMutexPtr tok;
238
239 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
240 return (NULL);
241#ifdef HAVE_PTHREAD_H
242 pthread_mutex_init(&tok->lock, NULL);
243 tok->held = 0;
244 tok->waiters = 0;
William M. Brack59002e72003-07-04 17:01:59 +0000245 pthread_cond_init(&tok->cv, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000246#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000247 InitializeCriticalSection(&tok->cs);
248 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000249#elif defined HAVE_BEOS_THREADS
250 if ((tok->lock = xmlNewMutex()) == NULL) {
251 free(tok);
252 return NULL;
253 }
254 tok->count = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000255#endif
256 return (tok);
257}
258
259/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000260 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000261 * @tok: the reentrant mutex
262 *
263 * xmlRFreeMutex() is used to reclaim resources associated with a
264 * reentrant mutex.
265 */
266void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000267xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000268{
269#ifdef HAVE_PTHREAD_H
270 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000271#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000272 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000273#elif defined HAVE_BEOS_THREADS
274 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000275#endif
276 free(tok);
277}
278
279/**
280 * xmlRMutexLock:
281 * @tok: the reentrant mutex
282 *
283 * xmlRMutexLock() is used to lock a libxml2 token_r.
284 */
285void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000286xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000287{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000288 if (tok == NULL)
289 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000290#ifdef HAVE_PTHREAD_H
291 pthread_mutex_lock(&tok->lock);
292 if (tok->held) {
293 if (pthread_equal(tok->tid, pthread_self())) {
294 tok->held++;
295 pthread_mutex_unlock(&tok->lock);
296 return;
297 } else {
298 tok->waiters++;
299 while (tok->held)
300 pthread_cond_wait(&tok->cv, &tok->lock);
301 tok->waiters--;
302 }
303 }
304 tok->tid = pthread_self();
305 tok->held = 1;
306 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000307#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000308 EnterCriticalSection(&tok->cs);
309 ++tok->count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000310#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000311 if (tok->lock->tid == find_thread(NULL)) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000312 tok->count++;
313 return;
314 } else {
315 xmlMutexLock(tok->lock);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000316 tok->count = 1;
317 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000318#endif
319}
320
321/**
322 * xmlRMutexUnlock:
323 * @tok: the reentrant mutex
324 *
325 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
326 */
327void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000328xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000329{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000330 if (tok == NULL)
331 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000332#ifdef HAVE_PTHREAD_H
333 pthread_mutex_lock(&tok->lock);
334 tok->held--;
335 if (tok->held == 0) {
336 if (tok->waiters)
337 pthread_cond_signal(&tok->cv);
338 tok->tid = 0;
339 }
340 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000341#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000342 if (!--tok->count)
343 LeaveCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000344#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000345 if (tok->lock->tid == find_thread(NULL)) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000346 tok->count--;
347 if (tok->count == 0) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000348 xmlMutexUnlock(tok->lock);
349 }
350 return;
351 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000352#endif
353}
354
355/************************************************************************
356 * *
357 * Per thread global state handling *
358 * *
359 ************************************************************************/
360
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000361#ifdef LIBXML_THREAD_ENABLED
Daniel Veillardb8478642001-10-12 17:29:10 +0000362/**
363 * xmlFreeGlobalState:
364 * @state: a thread global state
365 *
366 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
367 * global state. It is is used here to reclaim memory resources.
368 */
369static void
370xmlFreeGlobalState(void *state)
371{
372 free(state);
373}
374
375/**
376 * xmlNewGlobalState:
377 *
378 * xmlNewGlobalState() allocates a global state. This structure is used to
379 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000380 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000381 *
382 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
383 */
384static xmlGlobalStatePtr
385xmlNewGlobalState(void)
386{
387 xmlGlobalState *gs;
388
389 gs = malloc(sizeof(xmlGlobalState));
390 if (gs == NULL)
391 return(NULL);
392
William M. Brack8b2c7f12002-11-22 05:07:29 +0000393 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000394 xmlInitializeGlobalState(gs);
395 return (gs);
396}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000397#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000398
399
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000400#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000401#if !defined(HAVE_COMPILER_TLS)
402#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000403typedef struct _xmlGlobalStateCleanupHelperParams
404{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000405 HANDLE thread;
406 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000407} xmlGlobalStateCleanupHelperParams;
408
Daniel Veillard01c13b52002-12-10 15:19:08 +0000409static void xmlGlobalStateCleanupHelper (void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000410{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000411 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
412 WaitForSingleObject(params->thread, INFINITE);
413 CloseHandle(params->thread);
414 xmlFreeGlobalState(params->memory);
415 free(params);
416 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000417}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000418#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
419
420typedef struct _xmlGlobalStateCleanupHelperParams
421{
422 void *memory;
423 struct _xmlGlobalStateCleanupHelperParams * prev;
424 struct _xmlGlobalStateCleanupHelperParams * next;
425} xmlGlobalStateCleanupHelperParams;
426
427static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL;
428static CRITICAL_SECTION cleanup_helpers_cs;
429
430#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
431#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000432#endif /* HAVE_WIN32_THREADS */
433
Daniel Veillard82cb3192003-10-29 13:39:15 +0000434#if defined HAVE_BEOS_THREADS
435void xmlGlobalStateCleanup(void *data)
436{
437 void *globalval = tls_get(globalkey);
438 if (globalval != NULL)
439 xmlFreeGlobalState(globalval);
440}
441#endif
442
Daniel Veillard01c13b52002-12-10 15:19:08 +0000443/**
444 * xmlGetGlobalState:
445 *
446 * xmlGetGlobalState() is called to retrieve the global state for a thread.
447 *
448 * Returns the thread global state or NULL in case of error
449 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000450xmlGlobalStatePtr
451xmlGetGlobalState(void)
452{
453#ifdef HAVE_PTHREAD_H
454 xmlGlobalState *globalval;
455
Daniel Veillarde28313b2001-12-06 14:08:31 +0000456 pthread_once(&once_control, xmlOnceInit);
457
Daniel Veillardb8478642001-10-12 17:29:10 +0000458 if ((globalval = (xmlGlobalState *)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000459 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000460 xmlGlobalState *tsd = xmlNewGlobalState();
461
462 pthread_setspecific(globalkey, tsd);
463 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000464 }
465 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000466#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000467#if defined(HAVE_COMPILER_TLS)
468 if (!tlstate_inited) {
469 tlstate_inited = 1;
470 xmlInitializeGlobalState(&tlstate);
471 }
472 return &tlstate;
473#else /* HAVE_COMPILER_TLS */
474 xmlGlobalState *globalval;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000475 xmlGlobalStateCleanupHelperParams * p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000476
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000477 if (run_once_init) {
478 run_once_init = 0;
479 xmlOnceInit();
480 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000481#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
482 globalval = (xmlGlobalState *)TlsGetValue(globalkey);
483#else
484 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
485 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
486#endif
487 if (globalval == NULL) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000488 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000489 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000490 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000491#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000492 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
493 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
494 TlsSetValue(globalkey, tsd);
495 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000496#else
497 EnterCriticalSection(&cleanup_helpers_cs);
498 if (cleanup_helpers_head != NULL) {
499 cleanup_helpers_head->prev = p;
500 }
501 p->next = cleanup_helpers_head;
502 p->prev = NULL;
503 cleanup_helpers_head = p;
504 TlsSetValue(globalkey, p);
505 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000506#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000507
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000508 return (tsd);
509 }
510 return (globalval);
511#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000512#elif defined HAVE_BEOS_THREADS
513 xmlGlobalState *globalval;
514
515 xmlOnceInit();
516
517 if ((globalval = (xmlGlobalState *)
518 tls_get(globalkey)) == NULL) {
519 xmlGlobalState *tsd = xmlNewGlobalState();
520
521 tls_set(globalkey, tsd);
522 on_exit_thread(xmlGlobalStateCleanup, NULL);
523 return (tsd);
524 }
525 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000526#else
527 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000528#endif
529}
530
Daniel Veillardb8478642001-10-12 17:29:10 +0000531/************************************************************************
532 * *
533 * Library wide thread interfaces *
534 * *
535 ************************************************************************/
536
537/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000538 * xmlGetThreadId:
539 *
540 * xmlGetThreadId() find the current thread ID number
541 *
542 * Returns the current thread ID number
543 */
544int
545xmlGetThreadId(void)
546{
547#ifdef HAVE_PTHREAD_H
548 return((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000549#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000550 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000551#elif defined HAVE_BEOS_THREADS
552 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000553#else
554 return((int) 0);
555#endif
556}
557
558/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000559 * xmlIsMainThread:
560 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000561 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000562 *
563 * Returns 1 if the current thread is the main thread, 0 otherwise
564 */
565int
566xmlIsMainThread(void)
567{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000568#ifdef HAVE_PTHREAD_H
569 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000570#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000571 if (run_once_init) {
572 run_once_init = 0;
573 xmlOnceInit ();
574 }
Daniel Veillard82cb3192003-10-29 13:39:15 +0000575#elif defined HAVE_BEOS_THREADS
576 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000577#endif
Daniel Veillard6f350292001-10-14 09:56:15 +0000578
579#ifdef DEBUG_THREADS
580 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
581#endif
582#ifdef HAVE_PTHREAD_H
583 return(mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000584#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000585 return(mainthread == GetCurrentThreadId ());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000586#elif defined HAVE_BEOS_THREADS
587 return(mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000588#else
589 return(1);
590#endif
591}
592
593/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000594 * xmlLockLibrary:
595 *
596 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
597 * library.
598 */
599void
600xmlLockLibrary(void)
601{
Daniel Veillard6f350292001-10-14 09:56:15 +0000602#ifdef DEBUG_THREADS
603 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
604#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000605 xmlRMutexLock(xmlLibraryLock);
606}
607
608/**
609 * xmlUnlockLibrary:
610 *
611 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
612 * library.
613 */
614void
615xmlUnlockLibrary(void)
616{
Daniel Veillard6f350292001-10-14 09:56:15 +0000617#ifdef DEBUG_THREADS
618 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
619#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000620 xmlRMutexUnlock(xmlLibraryLock);
621}
622
623/**
624 * xmlInitThreads:
625 *
626 * xmlInitThreads() is used to to initialize all the thread related
627 * data of the libxml2 library.
628 */
629void
630xmlInitThreads(void)
631{
Daniel Veillard6f350292001-10-14 09:56:15 +0000632#ifdef DEBUG_THREADS
633 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
634#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000635#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000636 InitializeCriticalSection(&cleanup_helpers_cs);
637#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000638}
639
640/**
641 * xmlCleanupThreads:
642 *
643 * xmlCleanupThreads() is used to to cleanup all the thread related
644 * data of the libxml2 library once processing has ended.
645 */
646void
647xmlCleanupThreads(void)
648{
Daniel Veillard6f350292001-10-14 09:56:15 +0000649#ifdef DEBUG_THREADS
650 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
651#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000652#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000653 if (globalkey != TLS_OUT_OF_INDEXES) {
654 xmlGlobalStateCleanupHelperParams * p;
655 EnterCriticalSection(&cleanup_helpers_cs);
656 p = cleanup_helpers_head;
657 while (p != NULL) {
658 xmlGlobalStateCleanupHelperParams * temp = p;
659 p = p->next;
660 xmlFreeGlobalState(temp->memory);
661 free(temp);
662 }
663 cleanup_helpers_head = 0;
664 LeaveCriticalSection(&cleanup_helpers_cs);
665 TlsFree(globalkey);
666 globalkey = TLS_OUT_OF_INDEXES;
667 }
668 DeleteCriticalSection(&cleanup_helpers_cs);
669#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000670}
Daniel Veillard6f350292001-10-14 09:56:15 +0000671
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000672#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000673/**
674 * xmlOnceInit
675 *
676 * xmlOnceInit() is used to initialize the value of mainthread for use
677 * in other routines. This function should only be called using
678 * pthread_once() in association with the once_control variable to ensure
679 * that the function is only called once. See man pthread_once for more
680 * details.
681 */
682static void
683xmlOnceInit(void) {
684#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000685 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000686 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000687#endif
688
689#if defined(HAVE_WIN32_THREADS)
690#if !defined(HAVE_COMPILER_TLS)
691 globalkey = TlsAlloc();
692#endif
693 mainthread = GetCurrentThreadId();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000694#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000695
696#ifdef HAVE_BEOS_THREADS
697 if (atomic_add(&run_once_init, 1) == 0) {
698 globalkey = tls_allocate();
699 tls_set(globalkey, NULL);
700 mainthread = find_thread(NULL);
701 } else
702 atomic_add(&run_once_init, -1);
703#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000704}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000705#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000706
707/**
William M. Brack7a821652003-08-15 07:27:40 +0000708 * DllMain:
709 * @hinstDLL: handle to DLL instance
710 * @fdwReason: Reason code for entry
711 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000712 *
713 * Entry point for Windows library. It is being used to free thread-specific
714 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000715 *
716 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000717 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000718#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
719#if defined(LIBXML_STATIC_FOR_DLL)
720BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
721#else
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000722BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000723#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000724{
725 switch(fdwReason) {
726 case DLL_THREAD_DETACH:
727 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000728 xmlGlobalState *globalval = NULL;
729 xmlGlobalStateCleanupHelperParams * p =
730 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
731 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
732 if (globalval) {
733 xmlFreeGlobalState(globalval);
734 TlsSetValue(globalkey,NULL);
735 }
736 if (p)
737 {
738 EnterCriticalSection(&cleanup_helpers_cs);
739 if (p == cleanup_helpers_head)
740 cleanup_helpers_head = p->next;
741 else
742 p->prev->next = p->next;
743 if (p->next != NULL)
744 p->next->prev = p->prev;
745 LeaveCriticalSection(&cleanup_helpers_cs);
746 free(p);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000747 }
748 }
749 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000750 }
751 return TRUE;
752}
753#endif