blob: 2f174e2b65dd09534b7cff12cf4bd1b1c8f46468 [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 Veillardb8478642001-10-12 17:29:10 +000065#else
66 int empty;
67#endif
68};
69
70/*
71 * xmlRMutex are reentrant mutual exception locks
72 */
73struct _xmlRMutex {
74#ifdef HAVE_PTHREAD_H
75 pthread_mutex_t lock;
76 unsigned int held;
77 unsigned int waiters;
78 pthread_t tid;
79 pthread_cond_t cv;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000080#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +000081 CRITICAL_SECTION cs;
82 unsigned int count;
Daniel Veillard82cb3192003-10-29 13:39:15 +000083#elif defined HAVE_BEOS_THREADS
84 xmlMutexPtr lock;
85 thread_id tid;
86 int32 count;
Daniel Veillardb8478642001-10-12 17:29:10 +000087#else
88 int empty;
89#endif
90};
91/*
92 * This module still has some internal static data.
93 * - xmlLibraryLock a global lock
94 * - globalkey used for per-thread data
Daniel Veillardb8478642001-10-12 17:29:10 +000095 */
Daniel Veillard6f350292001-10-14 09:56:15 +000096
Daniel Veillardb8478642001-10-12 17:29:10 +000097#ifdef HAVE_PTHREAD_H
Daniel Veillardb8478642001-10-12 17:29:10 +000098static pthread_key_t globalkey;
Daniel Veillard6f350292001-10-14 09:56:15 +000099static pthread_t mainthread;
Daniel Veillarde28313b2001-12-06 14:08:31 +0000100static pthread_once_t once_control = PTHREAD_ONCE_INIT;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000101#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000102#if defined(HAVE_COMPILER_TLS)
103static __declspec(thread) xmlGlobalState tlstate;
104static __declspec(thread) int tlstate_inited = 0;
105#else /* HAVE_COMPILER_TLS */
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000106static DWORD globalkey = TLS_OUT_OF_INDEXES;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000107#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000108static DWORD mainthread;
109static int run_once_init = 1;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000110/* endif HAVE_WIN32_THREADS */
111#elif defined HAVE_BEOS_THREADS
112int32 globalkey = 0;
113thread_id mainthread = 0;
114int32 run_once_init = 0;
115#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000116
Daniel Veillardb8478642001-10-12 17:29:10 +0000117static xmlRMutexPtr xmlLibraryLock = NULL;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000118#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000119static void xmlOnceInit(void);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000120#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000121
122/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000123 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000124 *
125 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
126 * synchronizing access to data.
127 *
128 * Returns a new simple mutex pointer or NULL in case of error
129 */
130xmlMutexPtr
131xmlNewMutex(void)
132{
133 xmlMutexPtr tok;
134
135 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
136 return (NULL);
137#ifdef HAVE_PTHREAD_H
138 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000139#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000140 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000141#elif defined HAVE_BEOS_THREADS
142 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
143 free(tok);
144 return NULL;
145 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000146#endif
147 return (tok);
148}
149
150/**
151 * xmlFreeMutex:
152 * @tok: the simple mutex
153 *
154 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
155 * struct.
156 */
157void
158xmlFreeMutex(xmlMutexPtr tok)
159{
Daniel Veillarddf101d82003-07-08 14:03:36 +0000160 if (tok == NULL) return;
161
Daniel Veillardb8478642001-10-12 17:29:10 +0000162#ifdef HAVE_PTHREAD_H
163 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000164#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000165 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000166#elif defined HAVE_BEOS_THREADS
167 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000168#endif
169 free(tok);
170}
171
172/**
173 * xmlMutexLock:
174 * @tok: the simple mutex
175 *
176 * xmlMutexLock() is used to lock a libxml2 token.
177 */
178void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000179xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000180{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000181 if (tok == NULL)
182 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000183#ifdef HAVE_PTHREAD_H
184 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000185#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000186 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000187#elif defined HAVE_BEOS_THREADS
188 if (acquire_sem(tok->sem) != B_NO_ERROR) {
189#ifdef DEBUG_THREADS
190 xmlGenericError(xmlGenericErrorContext, "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
191 exit();
192#endif
193 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000194#endif
195
196}
197
198/**
199 * xmlMutexUnlock:
200 * @tok: the simple mutex
201 *
202 * xmlMutexUnlock() is used to unlock a libxml2 token.
203 */
204void
Daniel Veillard5805be22003-08-28 08:03:23 +0000205xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000206{
Daniel Veillard5805be22003-08-28 08:03:23 +0000207 if (tok == NULL)
208 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000209#ifdef HAVE_PTHREAD_H
210 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000211#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000212 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000213#elif defined HAVE_BEOS_THREADS
214 release_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000215#endif
216}
217
218/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000219 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000220 *
221 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
222 * synchronizing access to data. token_r is a re-entrant lock and thus useful
223 * for synchronizing access to data structures that may be manipulated in a
224 * recursive fashion.
225 *
226 * Returns the new reentrant mutex pointer or NULL in case of error
227 */
228xmlRMutexPtr
229xmlNewRMutex(void)
230{
231 xmlRMutexPtr tok;
232
233 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
234 return (NULL);
235#ifdef HAVE_PTHREAD_H
236 pthread_mutex_init(&tok->lock, NULL);
237 tok->held = 0;
238 tok->waiters = 0;
William M. Brack59002e72003-07-04 17:01:59 +0000239 pthread_cond_init(&tok->cv, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000240#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000241 InitializeCriticalSection(&tok->cs);
242 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000243#elif defined HAVE_BEOS_THREADS
244 if ((tok->lock = xmlNewMutex()) == NULL) {
245 free(tok);
246 return NULL;
247 }
248 tok->count = 0;
249 tok->tid = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000250#endif
251 return (tok);
252}
253
254/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000255 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000256 * @tok: the reentrant mutex
257 *
258 * xmlRFreeMutex() is used to reclaim resources associated with a
259 * reentrant mutex.
260 */
261void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000262xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000263{
264#ifdef HAVE_PTHREAD_H
265 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000266#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000267 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000268#elif defined HAVE_BEOS_THREADS
269 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000270#endif
271 free(tok);
272}
273
274/**
275 * xmlRMutexLock:
276 * @tok: the reentrant mutex
277 *
278 * xmlRMutexLock() is used to lock a libxml2 token_r.
279 */
280void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000281xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000282{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000283 if (tok == NULL)
284 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000285#ifdef HAVE_PTHREAD_H
286 pthread_mutex_lock(&tok->lock);
287 if (tok->held) {
288 if (pthread_equal(tok->tid, pthread_self())) {
289 tok->held++;
290 pthread_mutex_unlock(&tok->lock);
291 return;
292 } else {
293 tok->waiters++;
294 while (tok->held)
295 pthread_cond_wait(&tok->cv, &tok->lock);
296 tok->waiters--;
297 }
298 }
299 tok->tid = pthread_self();
300 tok->held = 1;
301 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000302#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000303 EnterCriticalSection(&tok->cs);
304 ++tok->count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000305#elif defined HAVE_BEOS_THREADS
306 if (tok->tid == find_thread(NULL)) {
307 tok->count++;
308 return;
309 } else {
310 xmlMutexLock(tok->lock);
311 tok->tid = find_thread(NULL);
312 tok->count = 1;
313 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000314#endif
315}
316
317/**
318 * xmlRMutexUnlock:
319 * @tok: the reentrant mutex
320 *
321 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
322 */
323void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000324xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000325{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000326 if (tok == NULL)
327 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000328#ifdef HAVE_PTHREAD_H
329 pthread_mutex_lock(&tok->lock);
330 tok->held--;
331 if (tok->held == 0) {
332 if (tok->waiters)
333 pthread_cond_signal(&tok->cv);
334 tok->tid = 0;
335 }
336 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000337#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000338 if (!--tok->count)
339 LeaveCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000340#elif defined HAVE_BEOS_THREADS
341 if (tok->tid == find_thread(NULL)) {
342 tok->count--;
343 if (tok->count == 0) {
344 tok->tid = 0;
345 xmlMutexUnlock(tok->lock);
346 }
347 return;
348 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000349#endif
350}
351
352/************************************************************************
353 * *
354 * Per thread global state handling *
355 * *
356 ************************************************************************/
357
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000358#ifdef LIBXML_THREAD_ENABLED
Daniel Veillardb8478642001-10-12 17:29:10 +0000359/**
360 * xmlFreeGlobalState:
361 * @state: a thread global state
362 *
363 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
364 * global state. It is is used here to reclaim memory resources.
365 */
366static void
367xmlFreeGlobalState(void *state)
368{
369 free(state);
370}
371
372/**
373 * xmlNewGlobalState:
374 *
375 * xmlNewGlobalState() allocates a global state. This structure is used to
376 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000377 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000378 *
379 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
380 */
381static xmlGlobalStatePtr
382xmlNewGlobalState(void)
383{
384 xmlGlobalState *gs;
385
386 gs = malloc(sizeof(xmlGlobalState));
387 if (gs == NULL)
388 return(NULL);
389
William M. Brack8b2c7f12002-11-22 05:07:29 +0000390 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000391 xmlInitializeGlobalState(gs);
392 return (gs);
393}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000394#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000395
396
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000397#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000398#if !defined(HAVE_COMPILER_TLS)
399#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000400typedef struct _xmlGlobalStateCleanupHelperParams
401{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000402 HANDLE thread;
403 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000404} xmlGlobalStateCleanupHelperParams;
405
Daniel Veillard01c13b52002-12-10 15:19:08 +0000406static void xmlGlobalStateCleanupHelper (void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000407{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000408 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
409 WaitForSingleObject(params->thread, INFINITE);
410 CloseHandle(params->thread);
411 xmlFreeGlobalState(params->memory);
412 free(params);
413 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000414}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000415#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
416
417typedef struct _xmlGlobalStateCleanupHelperParams
418{
419 void *memory;
420 struct _xmlGlobalStateCleanupHelperParams * prev;
421 struct _xmlGlobalStateCleanupHelperParams * next;
422} xmlGlobalStateCleanupHelperParams;
423
424static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL;
425static CRITICAL_SECTION cleanup_helpers_cs;
426
427#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
428#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000429#endif /* HAVE_WIN32_THREADS */
430
Daniel Veillard82cb3192003-10-29 13:39:15 +0000431#if defined HAVE_BEOS_THREADS
432void xmlGlobalStateCleanup(void *data)
433{
434 void *globalval = tls_get(globalkey);
435 if (globalval != NULL)
436 xmlFreeGlobalState(globalval);
437}
438#endif
439
Daniel Veillard01c13b52002-12-10 15:19:08 +0000440/**
441 * xmlGetGlobalState:
442 *
443 * xmlGetGlobalState() is called to retrieve the global state for a thread.
444 *
445 * Returns the thread global state or NULL in case of error
446 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000447xmlGlobalStatePtr
448xmlGetGlobalState(void)
449{
450#ifdef HAVE_PTHREAD_H
451 xmlGlobalState *globalval;
452
Daniel Veillarde28313b2001-12-06 14:08:31 +0000453 pthread_once(&once_control, xmlOnceInit);
454
Daniel Veillardb8478642001-10-12 17:29:10 +0000455 if ((globalval = (xmlGlobalState *)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000456 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000457 xmlGlobalState *tsd = xmlNewGlobalState();
458
459 pthread_setspecific(globalkey, tsd);
460 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000461 }
462 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000463#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000464#if defined(HAVE_COMPILER_TLS)
465 if (!tlstate_inited) {
466 tlstate_inited = 1;
467 xmlInitializeGlobalState(&tlstate);
468 }
469 return &tlstate;
470#else /* HAVE_COMPILER_TLS */
471 xmlGlobalState *globalval;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000472 xmlGlobalStateCleanupHelperParams * p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000473
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000474 if (run_once_init) {
475 run_once_init = 0;
476 xmlOnceInit();
477 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000478#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
479 globalval = (xmlGlobalState *)TlsGetValue(globalkey);
480#else
481 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
482 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
483#endif
484 if (globalval == NULL) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000485 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000486 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000487 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000488#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000489 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
490 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
491 TlsSetValue(globalkey, tsd);
492 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000493#else
494 EnterCriticalSection(&cleanup_helpers_cs);
495 if (cleanup_helpers_head != NULL) {
496 cleanup_helpers_head->prev = p;
497 }
498 p->next = cleanup_helpers_head;
499 p->prev = NULL;
500 cleanup_helpers_head = p;
501 TlsSetValue(globalkey, p);
502 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000503#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000504
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000505 return (tsd);
506 }
507 return (globalval);
508#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000509#elif defined HAVE_BEOS_THREADS
510 xmlGlobalState *globalval;
511
512 xmlOnceInit();
513
514 if ((globalval = (xmlGlobalState *)
515 tls_get(globalkey)) == NULL) {
516 xmlGlobalState *tsd = xmlNewGlobalState();
517
518 tls_set(globalkey, tsd);
519 on_exit_thread(xmlGlobalStateCleanup, NULL);
520 return (tsd);
521 }
522 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000523#else
524 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000525#endif
526}
527
Daniel Veillardb8478642001-10-12 17:29:10 +0000528/************************************************************************
529 * *
530 * Library wide thread interfaces *
531 * *
532 ************************************************************************/
533
534/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000535 * xmlGetThreadId:
536 *
537 * xmlGetThreadId() find the current thread ID number
538 *
539 * Returns the current thread ID number
540 */
541int
542xmlGetThreadId(void)
543{
544#ifdef HAVE_PTHREAD_H
545 return((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000546#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000547 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000548#elif defined HAVE_BEOS_THREADS
549 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000550#else
551 return((int) 0);
552#endif
553}
554
555/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000556 * xmlIsMainThread:
557 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000558 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000559 *
560 * Returns 1 if the current thread is the main thread, 0 otherwise
561 */
562int
563xmlIsMainThread(void)
564{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000565#ifdef HAVE_PTHREAD_H
566 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000567#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000568 if (run_once_init) {
569 run_once_init = 0;
570 xmlOnceInit ();
571 }
Daniel Veillard82cb3192003-10-29 13:39:15 +0000572#elif defined HAVE_BEOS_THREADS
573 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000574#endif
Daniel Veillard6f350292001-10-14 09:56:15 +0000575
576#ifdef DEBUG_THREADS
577 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
578#endif
579#ifdef HAVE_PTHREAD_H
580 return(mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000581#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000582 return(mainthread == GetCurrentThreadId ());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000583#elif defined HAVE_BEOS_THREADS
584 return(mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000585#else
586 return(1);
587#endif
588}
589
590/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000591 * xmlLockLibrary:
592 *
593 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
594 * library.
595 */
596void
597xmlLockLibrary(void)
598{
Daniel Veillard6f350292001-10-14 09:56:15 +0000599#ifdef DEBUG_THREADS
600 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
601#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000602 xmlRMutexLock(xmlLibraryLock);
603}
604
605/**
606 * xmlUnlockLibrary:
607 *
608 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
609 * library.
610 */
611void
612xmlUnlockLibrary(void)
613{
Daniel Veillard6f350292001-10-14 09:56:15 +0000614#ifdef DEBUG_THREADS
615 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
616#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000617 xmlRMutexUnlock(xmlLibraryLock);
618}
619
620/**
621 * xmlInitThreads:
622 *
623 * xmlInitThreads() is used to to initialize all the thread related
624 * data of the libxml2 library.
625 */
626void
627xmlInitThreads(void)
628{
Daniel Veillard6f350292001-10-14 09:56:15 +0000629#ifdef DEBUG_THREADS
630 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
631#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000632#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000633 InitializeCriticalSection(&cleanup_helpers_cs);
634#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000635}
636
637/**
638 * xmlCleanupThreads:
639 *
640 * xmlCleanupThreads() is used to to cleanup all the thread related
641 * data of the libxml2 library once processing has ended.
642 */
643void
644xmlCleanupThreads(void)
645{
Daniel Veillard6f350292001-10-14 09:56:15 +0000646#ifdef DEBUG_THREADS
647 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
648#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000649#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000650 if (globalkey != TLS_OUT_OF_INDEXES) {
651 xmlGlobalStateCleanupHelperParams * p;
652 EnterCriticalSection(&cleanup_helpers_cs);
653 p = cleanup_helpers_head;
654 while (p != NULL) {
655 xmlGlobalStateCleanupHelperParams * temp = p;
656 p = p->next;
657 xmlFreeGlobalState(temp->memory);
658 free(temp);
659 }
660 cleanup_helpers_head = 0;
661 LeaveCriticalSection(&cleanup_helpers_cs);
662 TlsFree(globalkey);
663 globalkey = TLS_OUT_OF_INDEXES;
664 }
665 DeleteCriticalSection(&cleanup_helpers_cs);
666#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000667}
Daniel Veillard6f350292001-10-14 09:56:15 +0000668
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000669#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000670/**
671 * xmlOnceInit
672 *
673 * xmlOnceInit() is used to initialize the value of mainthread for use
674 * in other routines. This function should only be called using
675 * pthread_once() in association with the once_control variable to ensure
676 * that the function is only called once. See man pthread_once for more
677 * details.
678 */
679static void
680xmlOnceInit(void) {
681#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000682 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000683 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000684#endif
685
686#if defined(HAVE_WIN32_THREADS)
687#if !defined(HAVE_COMPILER_TLS)
688 globalkey = TlsAlloc();
689#endif
690 mainthread = GetCurrentThreadId();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000691#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000692
693#ifdef HAVE_BEOS_THREADS
694 if (atomic_add(&run_once_init, 1) == 0) {
695 globalkey = tls_allocate();
696 tls_set(globalkey, NULL);
697 mainthread = find_thread(NULL);
698 } else
699 atomic_add(&run_once_init, -1);
700#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000701}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000702#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000703
704/**
William M. Brack7a821652003-08-15 07:27:40 +0000705 * DllMain:
706 * @hinstDLL: handle to DLL instance
707 * @fdwReason: Reason code for entry
708 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000709 *
710 * Entry point for Windows library. It is being used to free thread-specific
711 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000712 *
713 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000714 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000715#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
716#if defined(LIBXML_STATIC_FOR_DLL)
717BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
718#else
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000719BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000720#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000721{
722 switch(fdwReason) {
723 case DLL_THREAD_DETACH:
724 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000725 xmlGlobalState *globalval = NULL;
726 xmlGlobalStateCleanupHelperParams * p =
727 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
728 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
729 if (globalval) {
730 xmlFreeGlobalState(globalval);
731 TlsSetValue(globalkey,NULL);
732 }
733 if (p)
734 {
735 EnterCriticalSection(&cleanup_helpers_cs);
736 if (p == cleanup_helpers_head)
737 cleanup_helpers_head = p->next;
738 else
739 p->prev->next = p->next;
740 if (p->next != NULL)
741 p->next->prev = p->prev;
742 LeaveCriticalSection(&cleanup_helpers_cs);
743 free(p);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000744 }
745 }
746 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000747 }
748 return TRUE;
749}
750#endif