blob: ac6c8d62ff743b8569b1446bc886bc0b249febe0 [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
William M. Brackb1d53162003-11-18 06:54:40 +0000435/**
436 * xmlGlobalStateCleanup:
437 * @data: unused parameter
438 *
439 * Used for Beos only
440 */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000441void xmlGlobalStateCleanup(void *data)
442{
443 void *globalval = tls_get(globalkey);
444 if (globalval != NULL)
445 xmlFreeGlobalState(globalval);
446}
447#endif
448
Daniel Veillard01c13b52002-12-10 15:19:08 +0000449/**
450 * xmlGetGlobalState:
451 *
452 * xmlGetGlobalState() is called to retrieve the global state for a thread.
453 *
454 * Returns the thread global state or NULL in case of error
455 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000456xmlGlobalStatePtr
457xmlGetGlobalState(void)
458{
459#ifdef HAVE_PTHREAD_H
460 xmlGlobalState *globalval;
461
Daniel Veillarde28313b2001-12-06 14:08:31 +0000462 pthread_once(&once_control, xmlOnceInit);
463
Daniel Veillardb8478642001-10-12 17:29:10 +0000464 if ((globalval = (xmlGlobalState *)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000465 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000466 xmlGlobalState *tsd = xmlNewGlobalState();
467
468 pthread_setspecific(globalkey, tsd);
469 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000470 }
471 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000472#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000473#if defined(HAVE_COMPILER_TLS)
474 if (!tlstate_inited) {
475 tlstate_inited = 1;
476 xmlInitializeGlobalState(&tlstate);
477 }
478 return &tlstate;
479#else /* HAVE_COMPILER_TLS */
480 xmlGlobalState *globalval;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000481 xmlGlobalStateCleanupHelperParams * p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000482
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000483 if (run_once_init) {
484 run_once_init = 0;
485 xmlOnceInit();
486 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000487#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
488 globalval = (xmlGlobalState *)TlsGetValue(globalkey);
489#else
490 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
491 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
492#endif
493 if (globalval == NULL) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000494 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000495 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000496 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000497#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000498 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
499 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
500 TlsSetValue(globalkey, tsd);
501 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000502#else
503 EnterCriticalSection(&cleanup_helpers_cs);
504 if (cleanup_helpers_head != NULL) {
505 cleanup_helpers_head->prev = p;
506 }
507 p->next = cleanup_helpers_head;
508 p->prev = NULL;
509 cleanup_helpers_head = p;
510 TlsSetValue(globalkey, p);
511 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000512#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000513
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000514 return (tsd);
515 }
516 return (globalval);
517#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000518#elif defined HAVE_BEOS_THREADS
519 xmlGlobalState *globalval;
520
521 xmlOnceInit();
522
523 if ((globalval = (xmlGlobalState *)
524 tls_get(globalkey)) == NULL) {
525 xmlGlobalState *tsd = xmlNewGlobalState();
526
527 tls_set(globalkey, tsd);
528 on_exit_thread(xmlGlobalStateCleanup, NULL);
529 return (tsd);
530 }
531 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000532#else
533 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000534#endif
535}
536
Daniel Veillardb8478642001-10-12 17:29:10 +0000537/************************************************************************
538 * *
539 * Library wide thread interfaces *
540 * *
541 ************************************************************************/
542
543/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000544 * xmlGetThreadId:
545 *
546 * xmlGetThreadId() find the current thread ID number
547 *
548 * Returns the current thread ID number
549 */
550int
551xmlGetThreadId(void)
552{
553#ifdef HAVE_PTHREAD_H
554 return((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000555#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000556 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000557#elif defined HAVE_BEOS_THREADS
558 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000559#else
560 return((int) 0);
561#endif
562}
563
564/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000565 * xmlIsMainThread:
566 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000567 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000568 *
569 * Returns 1 if the current thread is the main thread, 0 otherwise
570 */
571int
572xmlIsMainThread(void)
573{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000574#ifdef HAVE_PTHREAD_H
575 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000576#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000577 if (run_once_init) {
578 run_once_init = 0;
579 xmlOnceInit ();
580 }
Daniel Veillard82cb3192003-10-29 13:39:15 +0000581#elif defined HAVE_BEOS_THREADS
582 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000583#endif
Daniel Veillard6f350292001-10-14 09:56:15 +0000584
585#ifdef DEBUG_THREADS
586 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
587#endif
588#ifdef HAVE_PTHREAD_H
589 return(mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000590#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000591 return(mainthread == GetCurrentThreadId ());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000592#elif defined HAVE_BEOS_THREADS
593 return(mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000594#else
595 return(1);
596#endif
597}
598
599/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000600 * xmlLockLibrary:
601 *
602 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
603 * library.
604 */
605void
606xmlLockLibrary(void)
607{
Daniel Veillard6f350292001-10-14 09:56:15 +0000608#ifdef DEBUG_THREADS
609 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
610#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000611 xmlRMutexLock(xmlLibraryLock);
612}
613
614/**
615 * xmlUnlockLibrary:
616 *
617 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
618 * library.
619 */
620void
621xmlUnlockLibrary(void)
622{
Daniel Veillard6f350292001-10-14 09:56:15 +0000623#ifdef DEBUG_THREADS
624 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
625#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000626 xmlRMutexUnlock(xmlLibraryLock);
627}
628
629/**
630 * xmlInitThreads:
631 *
632 * xmlInitThreads() is used to to initialize all the thread related
633 * data of the libxml2 library.
634 */
635void
636xmlInitThreads(void)
637{
Daniel Veillard6f350292001-10-14 09:56:15 +0000638#ifdef DEBUG_THREADS
639 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
640#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000641#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000642 InitializeCriticalSection(&cleanup_helpers_cs);
643#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000644}
645
646/**
647 * xmlCleanupThreads:
648 *
649 * xmlCleanupThreads() is used to to cleanup all the thread related
650 * data of the libxml2 library once processing has ended.
651 */
652void
653xmlCleanupThreads(void)
654{
Daniel Veillard6f350292001-10-14 09:56:15 +0000655#ifdef DEBUG_THREADS
656 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
657#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000658#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000659 if (globalkey != TLS_OUT_OF_INDEXES) {
660 xmlGlobalStateCleanupHelperParams * p;
661 EnterCriticalSection(&cleanup_helpers_cs);
662 p = cleanup_helpers_head;
663 while (p != NULL) {
664 xmlGlobalStateCleanupHelperParams * temp = p;
665 p = p->next;
666 xmlFreeGlobalState(temp->memory);
667 free(temp);
668 }
669 cleanup_helpers_head = 0;
670 LeaveCriticalSection(&cleanup_helpers_cs);
671 TlsFree(globalkey);
672 globalkey = TLS_OUT_OF_INDEXES;
673 }
674 DeleteCriticalSection(&cleanup_helpers_cs);
675#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000676}
Daniel Veillard6f350292001-10-14 09:56:15 +0000677
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000678#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000679/**
680 * xmlOnceInit
681 *
682 * xmlOnceInit() is used to initialize the value of mainthread for use
683 * in other routines. This function should only be called using
684 * pthread_once() in association with the once_control variable to ensure
685 * that the function is only called once. See man pthread_once for more
686 * details.
687 */
688static void
689xmlOnceInit(void) {
690#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000691 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000692 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000693#endif
694
695#if defined(HAVE_WIN32_THREADS)
696#if !defined(HAVE_COMPILER_TLS)
697 globalkey = TlsAlloc();
698#endif
699 mainthread = GetCurrentThreadId();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000700#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000701
702#ifdef HAVE_BEOS_THREADS
703 if (atomic_add(&run_once_init, 1) == 0) {
704 globalkey = tls_allocate();
705 tls_set(globalkey, NULL);
706 mainthread = find_thread(NULL);
707 } else
708 atomic_add(&run_once_init, -1);
709#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000710}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000711#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000712
713/**
William M. Brack7a821652003-08-15 07:27:40 +0000714 * DllMain:
715 * @hinstDLL: handle to DLL instance
716 * @fdwReason: Reason code for entry
717 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000718 *
719 * Entry point for Windows library. It is being used to free thread-specific
720 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000721 *
722 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000723 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000724#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
725#if defined(LIBXML_STATIC_FOR_DLL)
726BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
727#else
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000728BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000729#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000730{
731 switch(fdwReason) {
732 case DLL_THREAD_DETACH:
733 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000734 xmlGlobalState *globalval = NULL;
735 xmlGlobalStateCleanupHelperParams * p =
736 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
737 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
738 if (globalval) {
739 xmlFreeGlobalState(globalval);
740 TlsSetValue(globalkey,NULL);
741 }
742 if (p)
743 {
744 EnterCriticalSection(&cleanup_helpers_cs);
745 if (p == cleanup_helpers_head)
746 cleanup_helpers_head = p->next;
747 else
748 p->prev->next = p->next;
749 if (p->next != NULL)
750 p->next->prev = p->prev;
751 LeaveCriticalSection(&cleanup_helpers_cs);
752 free(p);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000753 }
754 }
755 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000756 }
757 return TRUE;
758}
759#endif