blob: b4a4cdc127acdc37c05c26dad231b8f621e66c78 [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{
Daniel Veillard8399ff32004-09-22 21:57:53 +0000372 /* free any memory allocated in the thread's xmlLastError */
373 xmlResetLastError();
Daniel Veillardb8478642001-10-12 17:29:10 +0000374 free(state);
375}
376
377/**
378 * xmlNewGlobalState:
379 *
380 * xmlNewGlobalState() allocates a global state. This structure is used to
381 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000382 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000383 *
384 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
385 */
386static xmlGlobalStatePtr
387xmlNewGlobalState(void)
388{
389 xmlGlobalState *gs;
390
391 gs = malloc(sizeof(xmlGlobalState));
392 if (gs == NULL)
393 return(NULL);
394
William M. Brack8b2c7f12002-11-22 05:07:29 +0000395 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000396 xmlInitializeGlobalState(gs);
397 return (gs);
398}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000399#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000400
401
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000402#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000403#if !defined(HAVE_COMPILER_TLS)
404#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000405typedef struct _xmlGlobalStateCleanupHelperParams
406{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000407 HANDLE thread;
408 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000409} xmlGlobalStateCleanupHelperParams;
410
Daniel Veillard01c13b52002-12-10 15:19:08 +0000411static void xmlGlobalStateCleanupHelper (void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000412{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000413 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
414 WaitForSingleObject(params->thread, INFINITE);
415 CloseHandle(params->thread);
416 xmlFreeGlobalState(params->memory);
417 free(params);
418 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000419}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000420#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
421
422typedef struct _xmlGlobalStateCleanupHelperParams
423{
424 void *memory;
425 struct _xmlGlobalStateCleanupHelperParams * prev;
426 struct _xmlGlobalStateCleanupHelperParams * next;
427} xmlGlobalStateCleanupHelperParams;
428
429static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL;
430static CRITICAL_SECTION cleanup_helpers_cs;
431
432#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
433#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000434#endif /* HAVE_WIN32_THREADS */
435
Daniel Veillard82cb3192003-10-29 13:39:15 +0000436#if defined HAVE_BEOS_THREADS
William M. Brackb1d53162003-11-18 06:54:40 +0000437/**
438 * xmlGlobalStateCleanup:
439 * @data: unused parameter
440 *
441 * Used for Beos only
442 */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000443void xmlGlobalStateCleanup(void *data)
444{
445 void *globalval = tls_get(globalkey);
446 if (globalval != NULL)
447 xmlFreeGlobalState(globalval);
448}
449#endif
450
Daniel Veillard01c13b52002-12-10 15:19:08 +0000451/**
452 * xmlGetGlobalState:
453 *
454 * xmlGetGlobalState() is called to retrieve the global state for a thread.
455 *
456 * Returns the thread global state or NULL in case of error
457 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000458xmlGlobalStatePtr
459xmlGetGlobalState(void)
460{
461#ifdef HAVE_PTHREAD_H
462 xmlGlobalState *globalval;
463
Daniel Veillarde28313b2001-12-06 14:08:31 +0000464 pthread_once(&once_control, xmlOnceInit);
465
Daniel Veillardb8478642001-10-12 17:29:10 +0000466 if ((globalval = (xmlGlobalState *)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000467 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000468 xmlGlobalState *tsd = xmlNewGlobalState();
469
470 pthread_setspecific(globalkey, tsd);
471 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000472 }
473 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000474#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000475#if defined(HAVE_COMPILER_TLS)
476 if (!tlstate_inited) {
477 tlstate_inited = 1;
478 xmlInitializeGlobalState(&tlstate);
479 }
480 return &tlstate;
481#else /* HAVE_COMPILER_TLS */
482 xmlGlobalState *globalval;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000483 xmlGlobalStateCleanupHelperParams * p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000484
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000485 if (run_once_init) {
486 run_once_init = 0;
487 xmlOnceInit();
488 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000489#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
490 globalval = (xmlGlobalState *)TlsGetValue(globalkey);
491#else
492 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
493 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
494#endif
495 if (globalval == NULL) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000496 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000497 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000498 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000499#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000500 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
501 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
502 TlsSetValue(globalkey, tsd);
503 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000504#else
505 EnterCriticalSection(&cleanup_helpers_cs);
506 if (cleanup_helpers_head != NULL) {
507 cleanup_helpers_head->prev = p;
508 }
509 p->next = cleanup_helpers_head;
510 p->prev = NULL;
511 cleanup_helpers_head = p;
512 TlsSetValue(globalkey, p);
513 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000514#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000515
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000516 return (tsd);
517 }
518 return (globalval);
519#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000520#elif defined HAVE_BEOS_THREADS
521 xmlGlobalState *globalval;
522
523 xmlOnceInit();
524
525 if ((globalval = (xmlGlobalState *)
526 tls_get(globalkey)) == NULL) {
527 xmlGlobalState *tsd = xmlNewGlobalState();
528
529 tls_set(globalkey, tsd);
530 on_exit_thread(xmlGlobalStateCleanup, NULL);
531 return (tsd);
532 }
533 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000534#else
535 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000536#endif
537}
538
Daniel Veillardb8478642001-10-12 17:29:10 +0000539/************************************************************************
540 * *
541 * Library wide thread interfaces *
542 * *
543 ************************************************************************/
544
545/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000546 * xmlGetThreadId:
547 *
548 * xmlGetThreadId() find the current thread ID number
549 *
550 * Returns the current thread ID number
551 */
552int
553xmlGetThreadId(void)
554{
555#ifdef HAVE_PTHREAD_H
556 return((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000557#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000558 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000559#elif defined HAVE_BEOS_THREADS
560 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000561#else
562 return((int) 0);
563#endif
564}
565
566/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000567 * xmlIsMainThread:
568 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000569 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000570 *
571 * Returns 1 if the current thread is the main thread, 0 otherwise
572 */
573int
574xmlIsMainThread(void)
575{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000576#ifdef HAVE_PTHREAD_H
577 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000578#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000579 if (run_once_init) {
580 run_once_init = 0;
581 xmlOnceInit ();
582 }
Daniel Veillard82cb3192003-10-29 13:39:15 +0000583#elif defined HAVE_BEOS_THREADS
584 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000585#endif
Daniel Veillard6f350292001-10-14 09:56:15 +0000586
587#ifdef DEBUG_THREADS
588 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
589#endif
590#ifdef HAVE_PTHREAD_H
591 return(mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000592#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000593 return(mainthread == GetCurrentThreadId ());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000594#elif defined HAVE_BEOS_THREADS
595 return(mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000596#else
597 return(1);
598#endif
599}
600
601/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000602 * xmlLockLibrary:
603 *
604 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
605 * library.
606 */
607void
608xmlLockLibrary(void)
609{
Daniel Veillard6f350292001-10-14 09:56:15 +0000610#ifdef DEBUG_THREADS
611 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
612#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000613 xmlRMutexLock(xmlLibraryLock);
614}
615
616/**
617 * xmlUnlockLibrary:
618 *
619 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
620 * library.
621 */
622void
623xmlUnlockLibrary(void)
624{
Daniel Veillard6f350292001-10-14 09:56:15 +0000625#ifdef DEBUG_THREADS
626 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
627#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000628 xmlRMutexUnlock(xmlLibraryLock);
629}
630
631/**
632 * xmlInitThreads:
633 *
634 * xmlInitThreads() is used to to initialize all the thread related
635 * data of the libxml2 library.
636 */
637void
638xmlInitThreads(void)
639{
Daniel Veillard6f350292001-10-14 09:56:15 +0000640#ifdef DEBUG_THREADS
641 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
642#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000643#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000644 InitializeCriticalSection(&cleanup_helpers_cs);
645#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000646}
647
648/**
649 * xmlCleanupThreads:
650 *
651 * xmlCleanupThreads() is used to to cleanup all the thread related
652 * data of the libxml2 library once processing has ended.
653 */
654void
655xmlCleanupThreads(void)
656{
Daniel Veillard6f350292001-10-14 09:56:15 +0000657#ifdef DEBUG_THREADS
658 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
659#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000660#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000661 if (globalkey != TLS_OUT_OF_INDEXES) {
662 xmlGlobalStateCleanupHelperParams * p;
663 EnterCriticalSection(&cleanup_helpers_cs);
664 p = cleanup_helpers_head;
665 while (p != NULL) {
666 xmlGlobalStateCleanupHelperParams * temp = p;
667 p = p->next;
668 xmlFreeGlobalState(temp->memory);
669 free(temp);
670 }
671 cleanup_helpers_head = 0;
672 LeaveCriticalSection(&cleanup_helpers_cs);
673 TlsFree(globalkey);
674 globalkey = TLS_OUT_OF_INDEXES;
675 }
676 DeleteCriticalSection(&cleanup_helpers_cs);
677#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000678}
Daniel Veillard6f350292001-10-14 09:56:15 +0000679
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000680#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000681/**
682 * xmlOnceInit
683 *
684 * xmlOnceInit() is used to initialize the value of mainthread for use
685 * in other routines. This function should only be called using
686 * pthread_once() in association with the once_control variable to ensure
687 * that the function is only called once. See man pthread_once for more
688 * details.
689 */
690static void
691xmlOnceInit(void) {
692#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000693 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000694 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000695#endif
696
697#if defined(HAVE_WIN32_THREADS)
698#if !defined(HAVE_COMPILER_TLS)
699 globalkey = TlsAlloc();
700#endif
701 mainthread = GetCurrentThreadId();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000702#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000703
704#ifdef HAVE_BEOS_THREADS
705 if (atomic_add(&run_once_init, 1) == 0) {
706 globalkey = tls_allocate();
707 tls_set(globalkey, NULL);
708 mainthread = find_thread(NULL);
709 } else
710 atomic_add(&run_once_init, -1);
711#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000712}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000713#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000714
715/**
William M. Brack7a821652003-08-15 07:27:40 +0000716 * DllMain:
717 * @hinstDLL: handle to DLL instance
718 * @fdwReason: Reason code for entry
719 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000720 *
721 * Entry point for Windows library. It is being used to free thread-specific
722 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000723 *
724 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000725 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000726#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
727#if defined(LIBXML_STATIC_FOR_DLL)
728BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
729#else
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000730BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000731#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000732{
733 switch(fdwReason) {
734 case DLL_THREAD_DETACH:
735 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000736 xmlGlobalState *globalval = NULL;
737 xmlGlobalStateCleanupHelperParams * p =
738 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
739 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
740 if (globalval) {
741 xmlFreeGlobalState(globalval);
742 TlsSetValue(globalkey,NULL);
743 }
744 if (p)
745 {
746 EnterCriticalSection(&cleanup_helpers_cs);
747 if (p == cleanup_helpers_head)
748 cleanup_helpers_head = p->next;
749 else
750 p->prev->next = p->next;
751 if (p->next != NULL)
752 p->next->prev = p->prev;
753 LeaveCriticalSection(&cleanup_helpers_cs);
754 free(p);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000755 }
756 }
757 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000758 }
759 return TRUE;
760}
761#endif