blob: d7bd783d1169c90567b9aee3e577e1b7c2046cba [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 Veillard01c3bd52004-10-22 13:16:10 +0000362#ifdef xmlLastError
363#undef xmlLastError
364#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000365/**
366 * xmlFreeGlobalState:
367 * @state: a thread global state
368 *
369 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
370 * global state. It is is used here to reclaim memory resources.
371 */
372static void
373xmlFreeGlobalState(void *state)
374{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000375 xmlGlobalState *gs = (xmlGlobalState *) state;
376
377 /* free any memory allocated in the thread's xmlLastError */
378 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000379 free(state);
380}
381
382/**
383 * xmlNewGlobalState:
384 *
385 * xmlNewGlobalState() allocates a global state. This structure is used to
386 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000387 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000388 *
389 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
390 */
391static xmlGlobalStatePtr
392xmlNewGlobalState(void)
393{
394 xmlGlobalState *gs;
395
396 gs = malloc(sizeof(xmlGlobalState));
397 if (gs == NULL)
398 return(NULL);
399
William M. Brack8b2c7f12002-11-22 05:07:29 +0000400 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000401 xmlInitializeGlobalState(gs);
402 return (gs);
403}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000404#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000405
406
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000407#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000408#if !defined(HAVE_COMPILER_TLS)
409#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000410typedef struct _xmlGlobalStateCleanupHelperParams
411{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000412 HANDLE thread;
413 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000414} xmlGlobalStateCleanupHelperParams;
415
Daniel Veillard01c13b52002-12-10 15:19:08 +0000416static void xmlGlobalStateCleanupHelper (void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000417{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000418 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
419 WaitForSingleObject(params->thread, INFINITE);
420 CloseHandle(params->thread);
421 xmlFreeGlobalState(params->memory);
422 free(params);
423 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000424}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000425#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
426
427typedef struct _xmlGlobalStateCleanupHelperParams
428{
429 void *memory;
430 struct _xmlGlobalStateCleanupHelperParams * prev;
431 struct _xmlGlobalStateCleanupHelperParams * next;
432} xmlGlobalStateCleanupHelperParams;
433
434static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL;
435static CRITICAL_SECTION cleanup_helpers_cs;
436
437#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
438#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000439#endif /* HAVE_WIN32_THREADS */
440
Daniel Veillard82cb3192003-10-29 13:39:15 +0000441#if defined HAVE_BEOS_THREADS
William M. Brackb1d53162003-11-18 06:54:40 +0000442/**
443 * xmlGlobalStateCleanup:
444 * @data: unused parameter
445 *
446 * Used for Beos only
447 */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000448void xmlGlobalStateCleanup(void *data)
449{
450 void *globalval = tls_get(globalkey);
451 if (globalval != NULL)
452 xmlFreeGlobalState(globalval);
453}
454#endif
455
Daniel Veillard01c13b52002-12-10 15:19:08 +0000456/**
457 * xmlGetGlobalState:
458 *
459 * xmlGetGlobalState() is called to retrieve the global state for a thread.
460 *
461 * Returns the thread global state or NULL in case of error
462 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000463xmlGlobalStatePtr
464xmlGetGlobalState(void)
465{
466#ifdef HAVE_PTHREAD_H
467 xmlGlobalState *globalval;
468
Daniel Veillarde28313b2001-12-06 14:08:31 +0000469 pthread_once(&once_control, xmlOnceInit);
470
Daniel Veillardb8478642001-10-12 17:29:10 +0000471 if ((globalval = (xmlGlobalState *)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000472 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000473 xmlGlobalState *tsd = xmlNewGlobalState();
474
475 pthread_setspecific(globalkey, tsd);
476 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000477 }
478 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000479#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000480#if defined(HAVE_COMPILER_TLS)
481 if (!tlstate_inited) {
482 tlstate_inited = 1;
483 xmlInitializeGlobalState(&tlstate);
484 }
485 return &tlstate;
486#else /* HAVE_COMPILER_TLS */
487 xmlGlobalState *globalval;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000488 xmlGlobalStateCleanupHelperParams * p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000489
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000490 if (run_once_init) {
491 run_once_init = 0;
492 xmlOnceInit();
493 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000494#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
495 globalval = (xmlGlobalState *)TlsGetValue(globalkey);
496#else
497 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
498 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
499#endif
500 if (globalval == NULL) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000501 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000502 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000503 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000504#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000505 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
506 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
507 TlsSetValue(globalkey, tsd);
508 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000509#else
510 EnterCriticalSection(&cleanup_helpers_cs);
511 if (cleanup_helpers_head != NULL) {
512 cleanup_helpers_head->prev = p;
513 }
514 p->next = cleanup_helpers_head;
515 p->prev = NULL;
516 cleanup_helpers_head = p;
517 TlsSetValue(globalkey, p);
518 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000519#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000520
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000521 return (tsd);
522 }
523 return (globalval);
524#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000525#elif defined HAVE_BEOS_THREADS
526 xmlGlobalState *globalval;
527
528 xmlOnceInit();
529
530 if ((globalval = (xmlGlobalState *)
531 tls_get(globalkey)) == NULL) {
532 xmlGlobalState *tsd = xmlNewGlobalState();
533
534 tls_set(globalkey, tsd);
535 on_exit_thread(xmlGlobalStateCleanup, NULL);
536 return (tsd);
537 }
538 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000539#else
540 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000541#endif
542}
543
Daniel Veillardb8478642001-10-12 17:29:10 +0000544/************************************************************************
545 * *
546 * Library wide thread interfaces *
547 * *
548 ************************************************************************/
549
550/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000551 * xmlGetThreadId:
552 *
553 * xmlGetThreadId() find the current thread ID number
554 *
555 * Returns the current thread ID number
556 */
557int
558xmlGetThreadId(void)
559{
560#ifdef HAVE_PTHREAD_H
561 return((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000562#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000563 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000564#elif defined HAVE_BEOS_THREADS
565 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000566#else
567 return((int) 0);
568#endif
569}
570
571/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000572 * xmlIsMainThread:
573 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000574 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000575 *
576 * Returns 1 if the current thread is the main thread, 0 otherwise
577 */
578int
579xmlIsMainThread(void)
580{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000581#ifdef HAVE_PTHREAD_H
582 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000583#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000584 if (run_once_init) {
585 run_once_init = 0;
586 xmlOnceInit ();
587 }
Daniel Veillard82cb3192003-10-29 13:39:15 +0000588#elif defined HAVE_BEOS_THREADS
589 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000590#endif
Daniel Veillard6f350292001-10-14 09:56:15 +0000591
592#ifdef DEBUG_THREADS
593 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
594#endif
595#ifdef HAVE_PTHREAD_H
596 return(mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000597#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000598 return(mainthread == GetCurrentThreadId ());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000599#elif defined HAVE_BEOS_THREADS
600 return(mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000601#else
602 return(1);
603#endif
604}
605
606/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000607 * xmlLockLibrary:
608 *
609 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
610 * library.
611 */
612void
613xmlLockLibrary(void)
614{
Daniel Veillard6f350292001-10-14 09:56:15 +0000615#ifdef DEBUG_THREADS
616 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
617#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000618 xmlRMutexLock(xmlLibraryLock);
619}
620
621/**
622 * xmlUnlockLibrary:
623 *
624 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
625 * library.
626 */
627void
628xmlUnlockLibrary(void)
629{
Daniel Veillard6f350292001-10-14 09:56:15 +0000630#ifdef DEBUG_THREADS
631 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
632#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000633 xmlRMutexUnlock(xmlLibraryLock);
634}
635
636/**
637 * xmlInitThreads:
638 *
639 * xmlInitThreads() is used to to initialize all the thread related
640 * data of the libxml2 library.
641 */
642void
643xmlInitThreads(void)
644{
Daniel Veillard6f350292001-10-14 09:56:15 +0000645#ifdef DEBUG_THREADS
646 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
647#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000648#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000649 InitializeCriticalSection(&cleanup_helpers_cs);
650#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000651}
652
653/**
654 * xmlCleanupThreads:
655 *
656 * xmlCleanupThreads() is used to to cleanup all the thread related
657 * data of the libxml2 library once processing has ended.
658 */
659void
660xmlCleanupThreads(void)
661{
Daniel Veillard6f350292001-10-14 09:56:15 +0000662#ifdef DEBUG_THREADS
663 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
664#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000665#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000666 if (globalkey != TLS_OUT_OF_INDEXES) {
667 xmlGlobalStateCleanupHelperParams * p;
668 EnterCriticalSection(&cleanup_helpers_cs);
669 p = cleanup_helpers_head;
670 while (p != NULL) {
671 xmlGlobalStateCleanupHelperParams * temp = p;
672 p = p->next;
673 xmlFreeGlobalState(temp->memory);
674 free(temp);
675 }
676 cleanup_helpers_head = 0;
677 LeaveCriticalSection(&cleanup_helpers_cs);
678 TlsFree(globalkey);
679 globalkey = TLS_OUT_OF_INDEXES;
680 }
681 DeleteCriticalSection(&cleanup_helpers_cs);
682#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000683}
Daniel Veillard6f350292001-10-14 09:56:15 +0000684
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000685#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000686/**
687 * xmlOnceInit
688 *
689 * xmlOnceInit() is used to initialize the value of mainthread for use
690 * in other routines. This function should only be called using
691 * pthread_once() in association with the once_control variable to ensure
692 * that the function is only called once. See man pthread_once for more
693 * details.
694 */
695static void
696xmlOnceInit(void) {
697#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000698 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000699 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000700#endif
701
702#if defined(HAVE_WIN32_THREADS)
703#if !defined(HAVE_COMPILER_TLS)
704 globalkey = TlsAlloc();
705#endif
706 mainthread = GetCurrentThreadId();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000707#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000708
709#ifdef HAVE_BEOS_THREADS
710 if (atomic_add(&run_once_init, 1) == 0) {
711 globalkey = tls_allocate();
712 tls_set(globalkey, NULL);
713 mainthread = find_thread(NULL);
714 } else
715 atomic_add(&run_once_init, -1);
716#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000717}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000718#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000719
720/**
William M. Brack7a821652003-08-15 07:27:40 +0000721 * DllMain:
722 * @hinstDLL: handle to DLL instance
723 * @fdwReason: Reason code for entry
724 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000725 *
726 * Entry point for Windows library. It is being used to free thread-specific
727 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000728 *
729 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000730 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000731#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
732#if defined(LIBXML_STATIC_FOR_DLL)
733BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
734#else
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000735BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000736#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000737{
738 switch(fdwReason) {
739 case DLL_THREAD_DETACH:
740 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000741 xmlGlobalState *globalval = NULL;
742 xmlGlobalStateCleanupHelperParams * p =
743 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
744 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
745 if (globalval) {
746 xmlFreeGlobalState(globalval);
747 TlsSetValue(globalkey,NULL);
748 }
749 if (p)
750 {
751 EnterCriticalSection(&cleanup_helpers_cs);
752 if (p == cleanup_helpers_head)
753 cleanup_helpers_head = p->next;
754 else
755 p->prev->next = p->next;
756 if (p->next != NULL)
757 p->next->prev = p->prev;
758 LeaveCriticalSection(&cleanup_helpers_cs);
759 free(p);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000760 }
761 }
762 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000763 }
764 return TRUE;
765}
766#endif