blob: f1a5314a597b98077f0c3eb52f319b7b78a21d90 [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
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000049#ifdef HAVE_PTHREAD_H
50
51static int libxml_is_threaded = -1;
52#ifdef __GNUC__
53#ifdef linux
54#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
55extern int pthread_once (pthread_once_t *__once_control,
56 void (*__init_routine) (void))
57 __attribute((weak));
58extern void *pthread_getspecific (pthread_key_t __key)
59 __attribute((weak));
60extern int pthread_setspecific (pthread_key_t __key,
61 __const void *__pointer)
62 __attribute((weak));
63extern int pthread_key_create (pthread_key_t *__key,
64 void (*__destr_function) (void *))
65 __attribute((weak));
66extern int pthread_mutex_init ()
67 __attribute((weak));
68extern int pthread_mutex_destroy ()
69 __attribute((weak));
70extern int pthread_mutex_lock ()
71 __attribute((weak));
72extern int pthread_mutex_unlock ()
73 __attribute((weak));
74extern int pthread_cond_init ()
75 __attribute((weak));
76extern int pthread_equal ()
77 __attribute((weak));
78extern pthread_t pthread_self ()
79 __attribute((weak));
80extern int pthread_key_create ()
81 __attribute((weak));
82extern int pthread_cond_signal ()
83 __attribute((weak));
84#endif
85#endif /* linux */
86#endif /* __GNUC__ */
87#endif /* HAVE_PTHREAD_H */
88
Daniel Veillardb8478642001-10-12 17:29:10 +000089/*
90 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
91 * to avoid some crazyness since xmlMalloc/xmlFree may actually
92 * be hosted on allocated blocks needing them for the allocation ...
93 */
94
95/*
96 * xmlMutex are a simple mutual exception locks
97 */
98struct _xmlMutex {
99#ifdef HAVE_PTHREAD_H
100 pthread_mutex_t lock;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000101#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000102 HANDLE mutex;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000103#elif defined HAVE_BEOS_THREADS
104 sem_id sem;
Daniel Veillard254b1262003-11-01 17:04:58 +0000105 thread_id tid;
Daniel Veillardb8478642001-10-12 17:29:10 +0000106#else
107 int empty;
108#endif
109};
110
111/*
112 * xmlRMutex are reentrant mutual exception locks
113 */
114struct _xmlRMutex {
115#ifdef HAVE_PTHREAD_H
116 pthread_mutex_t lock;
117 unsigned int held;
118 unsigned int waiters;
119 pthread_t tid;
120 pthread_cond_t cv;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000121#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000122 CRITICAL_SECTION cs;
123 unsigned int count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000124#elif defined HAVE_BEOS_THREADS
125 xmlMutexPtr lock;
126 thread_id tid;
127 int32 count;
Daniel Veillardb8478642001-10-12 17:29:10 +0000128#else
129 int empty;
130#endif
131};
132/*
133 * This module still has some internal static data.
134 * - xmlLibraryLock a global lock
135 * - globalkey used for per-thread data
Daniel Veillardb8478642001-10-12 17:29:10 +0000136 */
Daniel Veillard6f350292001-10-14 09:56:15 +0000137
Daniel Veillardb8478642001-10-12 17:29:10 +0000138#ifdef HAVE_PTHREAD_H
Daniel Veillardb8478642001-10-12 17:29:10 +0000139static pthread_key_t globalkey;
Daniel Veillard6f350292001-10-14 09:56:15 +0000140static pthread_t mainthread;
Daniel Veillarde28313b2001-12-06 14:08:31 +0000141static pthread_once_t once_control = PTHREAD_ONCE_INIT;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000142#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000143#if defined(HAVE_COMPILER_TLS)
144static __declspec(thread) xmlGlobalState tlstate;
145static __declspec(thread) int tlstate_inited = 0;
146#else /* HAVE_COMPILER_TLS */
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000147static DWORD globalkey = TLS_OUT_OF_INDEXES;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000148#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000149static DWORD mainthread;
Daniel Veillard62121e22005-02-24 15:38:52 +0000150static struct
151{
Daniel Veillard36616dd2005-02-25 07:31:49 +0000152 DWORD done;
153 DWORD control;
Daniel Veillard62121e22005-02-24 15:38:52 +0000154} run_once = { 0, 0 };
Daniel Veillard82cb3192003-10-29 13:39:15 +0000155/* endif HAVE_WIN32_THREADS */
156#elif defined HAVE_BEOS_THREADS
157int32 globalkey = 0;
158thread_id mainthread = 0;
159int32 run_once_init = 0;
160#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000161
Daniel Veillardb8478642001-10-12 17:29:10 +0000162static xmlRMutexPtr xmlLibraryLock = NULL;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000163#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000164static void xmlOnceInit(void);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000165#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000166
167/**
Daniel Veillard2e7598c2005-09-02 12:28:34 +0000168 * xmlIsThreadsEnabled:
169 *
170 * Run-time information about whether multithread support is compiled in
171 *
172 * Returns 1 (true) if library was compiled with multithread support
173 * enabled or 0 (false) otherwise.
174 */
175int
176xmlIsThreadsEnabled(void)
177{
178#ifdef LIBXML_THREAD_ENABLED
179 return 1;
180#else
181 return 0;
182#endif
183}
184
185/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000186 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000187 *
188 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
189 * synchronizing access to data.
190 *
191 * Returns a new simple mutex pointer or NULL in case of error
192 */
193xmlMutexPtr
194xmlNewMutex(void)
195{
196 xmlMutexPtr tok;
197
198 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
199 return (NULL);
200#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000201 if (libxml_is_threaded != 0)
202 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000203#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000204 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000205#elif defined HAVE_BEOS_THREADS
206 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
207 free(tok);
208 return NULL;
209 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000210 tok->tid = -1;
Daniel Veillardb8478642001-10-12 17:29:10 +0000211#endif
212 return (tok);
213}
214
215/**
216 * xmlFreeMutex:
217 * @tok: the simple mutex
218 *
219 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
220 * struct.
221 */
222void
223xmlFreeMutex(xmlMutexPtr tok)
224{
Daniel Veillarddf101d82003-07-08 14:03:36 +0000225 if (tok == NULL) return;
226
Daniel Veillardb8478642001-10-12 17:29:10 +0000227#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000228 if (libxml_is_threaded != 0)
229 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000230#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000231 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000232#elif defined HAVE_BEOS_THREADS
233 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000234#endif
235 free(tok);
236}
237
238/**
239 * xmlMutexLock:
240 * @tok: the simple mutex
241 *
242 * xmlMutexLock() is used to lock a libxml2 token.
243 */
244void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000245xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000246{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000247 if (tok == NULL)
248 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000249#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000250 if (libxml_is_threaded != 0)
251 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000252#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000253 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000254#elif defined HAVE_BEOS_THREADS
255 if (acquire_sem(tok->sem) != B_NO_ERROR) {
256#ifdef DEBUG_THREADS
257 xmlGenericError(xmlGenericErrorContext, "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
258 exit();
259#endif
260 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000261 tok->tid = find_thread(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000262#endif
263
264}
265
266/**
267 * xmlMutexUnlock:
268 * @tok: the simple mutex
269 *
270 * xmlMutexUnlock() is used to unlock a libxml2 token.
271 */
272void
Daniel Veillard5805be22003-08-28 08:03:23 +0000273xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000274{
Daniel Veillard5805be22003-08-28 08:03:23 +0000275 if (tok == NULL)
276 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000277#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000278 if (libxml_is_threaded != 0)
279 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000280#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000281 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000282#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000283 if (tok->tid == find_thread(NULL)) {
284 tok->tid = -1;
285 release_sem(tok->sem);
286 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000287#endif
288}
289
290/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000291 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000292 *
293 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
294 * synchronizing access to data. token_r is a re-entrant lock and thus useful
295 * for synchronizing access to data structures that may be manipulated in a
296 * recursive fashion.
297 *
298 * Returns the new reentrant mutex pointer or NULL in case of error
299 */
300xmlRMutexPtr
301xmlNewRMutex(void)
302{
303 xmlRMutexPtr tok;
304
305 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
306 return (NULL);
307#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000308 if (libxml_is_threaded != 0) {
309 pthread_mutex_init(&tok->lock, NULL);
310 tok->held = 0;
311 tok->waiters = 0;
312 pthread_cond_init(&tok->cv, NULL);
313 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000314#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000315 InitializeCriticalSection(&tok->cs);
316 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000317#elif defined HAVE_BEOS_THREADS
318 if ((tok->lock = xmlNewMutex()) == NULL) {
319 free(tok);
320 return NULL;
321 }
322 tok->count = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000323#endif
324 return (tok);
325}
326
327/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000328 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000329 * @tok: the reentrant mutex
330 *
331 * xmlRFreeMutex() is used to reclaim resources associated with a
332 * reentrant mutex.
333 */
334void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000335xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000336{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000337 if (tok == NULL)
338 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000339#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000340 if (libxml_is_threaded != 0)
341 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000342#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000343 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000344#elif defined HAVE_BEOS_THREADS
345 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000346#endif
347 free(tok);
348}
349
350/**
351 * xmlRMutexLock:
352 * @tok: the reentrant mutex
353 *
354 * xmlRMutexLock() is used to lock a libxml2 token_r.
355 */
356void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000357xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000358{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000359 if (tok == NULL)
360 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000361#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000362 if (libxml_is_threaded == 0)
363 return;
364
Daniel Veillardb8478642001-10-12 17:29:10 +0000365 pthread_mutex_lock(&tok->lock);
366 if (tok->held) {
367 if (pthread_equal(tok->tid, pthread_self())) {
368 tok->held++;
369 pthread_mutex_unlock(&tok->lock);
370 return;
371 } else {
372 tok->waiters++;
373 while (tok->held)
374 pthread_cond_wait(&tok->cv, &tok->lock);
375 tok->waiters--;
376 }
377 }
378 tok->tid = pthread_self();
379 tok->held = 1;
380 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000381#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000382 EnterCriticalSection(&tok->cs);
383 ++tok->count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000384#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000385 if (tok->lock->tid == find_thread(NULL)) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000386 tok->count++;
387 return;
388 } else {
389 xmlMutexLock(tok->lock);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000390 tok->count = 1;
391 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000392#endif
393}
394
395/**
396 * xmlRMutexUnlock:
397 * @tok: the reentrant mutex
398 *
399 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
400 */
401void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000402xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000403{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000404 if (tok == NULL)
405 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000406#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000407 if (libxml_is_threaded == 0)
408 return;
409
Daniel Veillardb8478642001-10-12 17:29:10 +0000410 pthread_mutex_lock(&tok->lock);
411 tok->held--;
412 if (tok->held == 0) {
413 if (tok->waiters)
414 pthread_cond_signal(&tok->cv);
415 tok->tid = 0;
416 }
417 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000418#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000419 if (!--tok->count)
420 LeaveCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000421#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000422 if (tok->lock->tid == find_thread(NULL)) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000423 tok->count--;
424 if (tok->count == 0) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000425 xmlMutexUnlock(tok->lock);
426 }
427 return;
428 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000429#endif
430}
431
432/************************************************************************
433 * *
434 * Per thread global state handling *
435 * *
436 ************************************************************************/
437
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000438#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000439#ifdef xmlLastError
440#undef xmlLastError
441#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000442/**
443 * xmlFreeGlobalState:
444 * @state: a thread global state
445 *
446 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
447 * global state. It is is used here to reclaim memory resources.
448 */
449static void
450xmlFreeGlobalState(void *state)
451{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000452 xmlGlobalState *gs = (xmlGlobalState *) state;
453
454 /* free any memory allocated in the thread's xmlLastError */
455 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000456 free(state);
457}
458
459/**
460 * xmlNewGlobalState:
461 *
462 * xmlNewGlobalState() allocates a global state. This structure is used to
463 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000464 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000465 *
466 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
467 */
468static xmlGlobalStatePtr
469xmlNewGlobalState(void)
470{
471 xmlGlobalState *gs;
472
473 gs = malloc(sizeof(xmlGlobalState));
474 if (gs == NULL)
475 return(NULL);
476
William M. Brack8b2c7f12002-11-22 05:07:29 +0000477 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000478 xmlInitializeGlobalState(gs);
479 return (gs);
480}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000481#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000482
483
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000484#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000485#if !defined(HAVE_COMPILER_TLS)
486#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000487typedef struct _xmlGlobalStateCleanupHelperParams
488{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000489 HANDLE thread;
490 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000491} xmlGlobalStateCleanupHelperParams;
492
Daniel Veillardffa3c742005-07-21 13:24:09 +0000493static void XMLCDECL xmlGlobalStateCleanupHelper (void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000494{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000495 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
496 WaitForSingleObject(params->thread, INFINITE);
497 CloseHandle(params->thread);
498 xmlFreeGlobalState(params->memory);
499 free(params);
500 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000501}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000502#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
503
504typedef struct _xmlGlobalStateCleanupHelperParams
505{
506 void *memory;
507 struct _xmlGlobalStateCleanupHelperParams * prev;
508 struct _xmlGlobalStateCleanupHelperParams * next;
509} xmlGlobalStateCleanupHelperParams;
510
511static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL;
512static CRITICAL_SECTION cleanup_helpers_cs;
513
514#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
515#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000516#endif /* HAVE_WIN32_THREADS */
517
Daniel Veillard82cb3192003-10-29 13:39:15 +0000518#if defined HAVE_BEOS_THREADS
William M. Brackb1d53162003-11-18 06:54:40 +0000519/**
520 * xmlGlobalStateCleanup:
521 * @data: unused parameter
522 *
523 * Used for Beos only
524 */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000525void xmlGlobalStateCleanup(void *data)
526{
527 void *globalval = tls_get(globalkey);
528 if (globalval != NULL)
529 xmlFreeGlobalState(globalval);
530}
531#endif
532
Daniel Veillard01c13b52002-12-10 15:19:08 +0000533/**
534 * xmlGetGlobalState:
535 *
536 * xmlGetGlobalState() is called to retrieve the global state for a thread.
537 *
538 * Returns the thread global state or NULL in case of error
539 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000540xmlGlobalStatePtr
541xmlGetGlobalState(void)
542{
543#ifdef HAVE_PTHREAD_H
544 xmlGlobalState *globalval;
545
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000546 if (libxml_is_threaded == 0)
547 return(NULL);
548
Daniel Veillarde28313b2001-12-06 14:08:31 +0000549 pthread_once(&once_control, xmlOnceInit);
550
Daniel Veillardb8478642001-10-12 17:29:10 +0000551 if ((globalval = (xmlGlobalState *)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000552 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000553 xmlGlobalState *tsd = xmlNewGlobalState();
554
555 pthread_setspecific(globalkey, tsd);
556 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000557 }
558 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000559#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000560#if defined(HAVE_COMPILER_TLS)
561 if (!tlstate_inited) {
562 tlstate_inited = 1;
563 xmlInitializeGlobalState(&tlstate);
564 }
565 return &tlstate;
566#else /* HAVE_COMPILER_TLS */
567 xmlGlobalState *globalval;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000568 xmlGlobalStateCleanupHelperParams * p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000569
Daniel Veillard62121e22005-02-24 15:38:52 +0000570 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000571#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
572 globalval = (xmlGlobalState *)TlsGetValue(globalkey);
573#else
574 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
575 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
576#endif
577 if (globalval == NULL) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000578 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000579 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000580 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000581#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000582 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
583 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
584 TlsSetValue(globalkey, tsd);
585 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000586#else
587 EnterCriticalSection(&cleanup_helpers_cs);
588 if (cleanup_helpers_head != NULL) {
589 cleanup_helpers_head->prev = p;
590 }
591 p->next = cleanup_helpers_head;
592 p->prev = NULL;
593 cleanup_helpers_head = p;
594 TlsSetValue(globalkey, p);
595 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000596#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000597
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000598 return (tsd);
599 }
600 return (globalval);
601#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000602#elif defined HAVE_BEOS_THREADS
603 xmlGlobalState *globalval;
604
605 xmlOnceInit();
606
607 if ((globalval = (xmlGlobalState *)
608 tls_get(globalkey)) == NULL) {
609 xmlGlobalState *tsd = xmlNewGlobalState();
610
611 tls_set(globalkey, tsd);
612 on_exit_thread(xmlGlobalStateCleanup, NULL);
613 return (tsd);
614 }
615 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000616#else
617 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000618#endif
619}
620
Daniel Veillardb8478642001-10-12 17:29:10 +0000621/************************************************************************
622 * *
623 * Library wide thread interfaces *
624 * *
625 ************************************************************************/
626
627/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000628 * xmlGetThreadId:
629 *
630 * xmlGetThreadId() find the current thread ID number
631 *
632 * Returns the current thread ID number
633 */
634int
635xmlGetThreadId(void)
636{
637#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000638 if (libxml_is_threaded == 0)
639 return(0);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000640 return((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000641#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000642 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000643#elif defined HAVE_BEOS_THREADS
644 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000645#else
646 return((int) 0);
647#endif
648}
649
650/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000651 * xmlIsMainThread:
652 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000653 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000654 *
655 * Returns 1 if the current thread is the main thread, 0 otherwise
656 */
657int
658xmlIsMainThread(void)
659{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000660#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000661 if (libxml_is_threaded == -1)
662 xmlInitThreads();
663 if (libxml_is_threaded == 0)
664 return(1);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000665 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000666#elif defined HAVE_WIN32_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000667 xmlOnceInit ();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000668#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000669 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000670#endif
Daniel Veillard6f350292001-10-14 09:56:15 +0000671
672#ifdef DEBUG_THREADS
673 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
674#endif
675#ifdef HAVE_PTHREAD_H
676 return(mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000677#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000678 return(mainthread == GetCurrentThreadId ());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000679#elif defined HAVE_BEOS_THREADS
680 return(mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000681#else
682 return(1);
683#endif
684}
685
686/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000687 * xmlLockLibrary:
688 *
689 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
690 * library.
691 */
692void
693xmlLockLibrary(void)
694{
Daniel Veillard6f350292001-10-14 09:56:15 +0000695#ifdef DEBUG_THREADS
696 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
697#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000698 xmlRMutexLock(xmlLibraryLock);
699}
700
701/**
702 * xmlUnlockLibrary:
703 *
704 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
705 * library.
706 */
707void
708xmlUnlockLibrary(void)
709{
Daniel Veillard6f350292001-10-14 09:56:15 +0000710#ifdef DEBUG_THREADS
711 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
712#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000713 xmlRMutexUnlock(xmlLibraryLock);
714}
715
716/**
717 * xmlInitThreads:
718 *
719 * xmlInitThreads() is used to to initialize all the thread related
720 * data of the libxml2 library.
721 */
722void
723xmlInitThreads(void)
724{
Daniel Veillard6f350292001-10-14 09:56:15 +0000725#ifdef DEBUG_THREADS
726 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
727#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000728#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000729 InitializeCriticalSection(&cleanup_helpers_cs);
730#endif
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000731#ifdef HAVE_PTHREAD_H
732 if (libxml_is_threaded == -1) {
733 if ((pthread_once != NULL) &&
734 (pthread_getspecific != NULL) &&
735 (pthread_setspecific != NULL) &&
736 (pthread_key_create != NULL) &&
737 (pthread_mutex_init != NULL) &&
738 (pthread_mutex_destroy != NULL) &&
739 (pthread_mutex_lock != NULL) &&
740 (pthread_mutex_unlock != NULL) &&
741 (pthread_cond_init != NULL) &&
742 (pthread_equal != NULL) &&
743 (pthread_self != NULL) &&
744 (pthread_key_create != NULL) &&
745 (pthread_cond_signal != NULL)) {
746 libxml_is_threaded = 1;
747/* fprintf(stderr, "Running multithreaded\n"); */
748 } else {
749/* fprintf(stderr, "Running without multithread\n"); */
750 libxml_is_threaded = 0;
751 }
752 }
753#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000754}
755
756/**
757 * xmlCleanupThreads:
758 *
759 * xmlCleanupThreads() is used to to cleanup all the thread related
760 * data of the libxml2 library once processing has ended.
761 */
762void
763xmlCleanupThreads(void)
764{
Daniel Veillard6f350292001-10-14 09:56:15 +0000765#ifdef DEBUG_THREADS
766 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
767#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000768#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000769 if (globalkey != TLS_OUT_OF_INDEXES) {
770 xmlGlobalStateCleanupHelperParams * p;
771 EnterCriticalSection(&cleanup_helpers_cs);
772 p = cleanup_helpers_head;
773 while (p != NULL) {
774 xmlGlobalStateCleanupHelperParams * temp = p;
775 p = p->next;
776 xmlFreeGlobalState(temp->memory);
777 free(temp);
778 }
779 cleanup_helpers_head = 0;
780 LeaveCriticalSection(&cleanup_helpers_cs);
781 TlsFree(globalkey);
782 globalkey = TLS_OUT_OF_INDEXES;
783 }
784 DeleteCriticalSection(&cleanup_helpers_cs);
785#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000786}
Daniel Veillard6f350292001-10-14 09:56:15 +0000787
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000788#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000789/**
790 * xmlOnceInit
791 *
792 * xmlOnceInit() is used to initialize the value of mainthread for use
793 * in other routines. This function should only be called using
794 * pthread_once() in association with the once_control variable to ensure
795 * that the function is only called once. See man pthread_once for more
796 * details.
797 */
798static void
799xmlOnceInit(void) {
800#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000801 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000802 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000803#endif
804
805#if defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000806 if (!run_once.done) {
Daniel Veillard36616dd2005-02-25 07:31:49 +0000807 if (InterlockedIncrement(&run_once.control) == 1)
Daniel Veillard62121e22005-02-24 15:38:52 +0000808 {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000809#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000810 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000811#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000812 mainthread = GetCurrentThreadId();
813 run_once.done = 1;
814 }
815 else {
816 /* Another thread is working; give up our slice and
817 * wait until they're done. */
818 while (!run_once.done)
819 Sleep(0);
820 }
821 }
Daniel Veillarde28313b2001-12-06 14:08:31 +0000822#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000823
824#ifdef HAVE_BEOS_THREADS
825 if (atomic_add(&run_once_init, 1) == 0) {
826 globalkey = tls_allocate();
827 tls_set(globalkey, NULL);
828 mainthread = find_thread(NULL);
829 } else
830 atomic_add(&run_once_init, -1);
831#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000832}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000833#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000834
835/**
William M. Brack7a821652003-08-15 07:27:40 +0000836 * DllMain:
837 * @hinstDLL: handle to DLL instance
838 * @fdwReason: Reason code for entry
839 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000840 *
841 * Entry point for Windows library. It is being used to free thread-specific
842 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000843 *
844 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000845 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000846#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
847#if defined(LIBXML_STATIC_FOR_DLL)
848BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
849#else
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000850BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000851#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000852{
853 switch(fdwReason) {
854 case DLL_THREAD_DETACH:
855 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000856 xmlGlobalState *globalval = NULL;
857 xmlGlobalStateCleanupHelperParams * p =
858 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
859 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
860 if (globalval) {
861 xmlFreeGlobalState(globalval);
862 TlsSetValue(globalkey,NULL);
863 }
864 if (p)
865 {
866 EnterCriticalSection(&cleanup_helpers_cs);
867 if (p == cleanup_helpers_head)
868 cleanup_helpers_head = p->next;
869 else
870 p->prev->next = p->next;
871 if (p->next != NULL)
872 p->next->prev = p->prev;
873 LeaveCriticalSection(&cleanup_helpers_cs);
874 free(p);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000875 }
876 }
877 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000878 }
879 return TRUE;
880}
881#endif
Daniel Veillard5d4644e2005-04-01 13:11:58 +0000882#define bottom_threads
883#include "elfgcchack.h"