blob: 8b42345828ffd21feaf84ee0a3f575cb0f1824ac [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 Veillard01c13b52002-12-10 15:19:08 +0000168 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000169 *
170 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
171 * synchronizing access to data.
172 *
173 * Returns a new simple mutex pointer or NULL in case of error
174 */
175xmlMutexPtr
176xmlNewMutex(void)
177{
178 xmlMutexPtr tok;
179
180 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
181 return (NULL);
182#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000183 if (libxml_is_threaded != 0)
184 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000185#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000186 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000187#elif defined HAVE_BEOS_THREADS
188 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
189 free(tok);
190 return NULL;
191 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000192 tok->tid = -1;
Daniel Veillardb8478642001-10-12 17:29:10 +0000193#endif
194 return (tok);
195}
196
197/**
198 * xmlFreeMutex:
199 * @tok: the simple mutex
200 *
201 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
202 * struct.
203 */
204void
205xmlFreeMutex(xmlMutexPtr tok)
206{
Daniel Veillarddf101d82003-07-08 14:03:36 +0000207 if (tok == NULL) return;
208
Daniel Veillardb8478642001-10-12 17:29:10 +0000209#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000210 if (libxml_is_threaded != 0)
211 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000212#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000213 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000214#elif defined HAVE_BEOS_THREADS
215 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000216#endif
217 free(tok);
218}
219
220/**
221 * xmlMutexLock:
222 * @tok: the simple mutex
223 *
224 * xmlMutexLock() is used to lock a libxml2 token.
225 */
226void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000227xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000228{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000229 if (tok == NULL)
230 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000231#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000232 if (libxml_is_threaded != 0)
233 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000234#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000235 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000236#elif defined HAVE_BEOS_THREADS
237 if (acquire_sem(tok->sem) != B_NO_ERROR) {
238#ifdef DEBUG_THREADS
239 xmlGenericError(xmlGenericErrorContext, "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
240 exit();
241#endif
242 }
Daniel Veillard254b1262003-11-01 17:04:58 +0000243 tok->tid = find_thread(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000244#endif
245
246}
247
248/**
249 * xmlMutexUnlock:
250 * @tok: the simple mutex
251 *
252 * xmlMutexUnlock() is used to unlock a libxml2 token.
253 */
254void
Daniel Veillard5805be22003-08-28 08:03:23 +0000255xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000256{
Daniel Veillard5805be22003-08-28 08:03:23 +0000257 if (tok == NULL)
258 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000259#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000260 if (libxml_is_threaded != 0)
261 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000262#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000263 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000264#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000265 if (tok->tid == find_thread(NULL)) {
266 tok->tid = -1;
267 release_sem(tok->sem);
268 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000269#endif
270}
271
272/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000273 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000274 *
275 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
276 * synchronizing access to data. token_r is a re-entrant lock and thus useful
277 * for synchronizing access to data structures that may be manipulated in a
278 * recursive fashion.
279 *
280 * Returns the new reentrant mutex pointer or NULL in case of error
281 */
282xmlRMutexPtr
283xmlNewRMutex(void)
284{
285 xmlRMutexPtr tok;
286
287 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
288 return (NULL);
289#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000290 if (libxml_is_threaded != 0) {
291 pthread_mutex_init(&tok->lock, NULL);
292 tok->held = 0;
293 tok->waiters = 0;
294 pthread_cond_init(&tok->cv, NULL);
295 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000296#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000297 InitializeCriticalSection(&tok->cs);
298 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000299#elif defined HAVE_BEOS_THREADS
300 if ((tok->lock = xmlNewMutex()) == NULL) {
301 free(tok);
302 return NULL;
303 }
304 tok->count = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000305#endif
306 return (tok);
307}
308
309/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000310 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000311 * @tok: the reentrant mutex
312 *
313 * xmlRFreeMutex() is used to reclaim resources associated with a
314 * reentrant mutex.
315 */
316void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000317xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000318{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000319 if (tok == NULL)
320 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000321#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000322 if (libxml_is_threaded != 0)
323 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000324#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000325 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000326#elif defined HAVE_BEOS_THREADS
327 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000328#endif
329 free(tok);
330}
331
332/**
333 * xmlRMutexLock:
334 * @tok: the reentrant mutex
335 *
336 * xmlRMutexLock() is used to lock a libxml2 token_r.
337 */
338void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000339xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000340{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000341 if (tok == NULL)
342 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000343#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000344 if (libxml_is_threaded == 0)
345 return;
346
Daniel Veillardb8478642001-10-12 17:29:10 +0000347 pthread_mutex_lock(&tok->lock);
348 if (tok->held) {
349 if (pthread_equal(tok->tid, pthread_self())) {
350 tok->held++;
351 pthread_mutex_unlock(&tok->lock);
352 return;
353 } else {
354 tok->waiters++;
355 while (tok->held)
356 pthread_cond_wait(&tok->cv, &tok->lock);
357 tok->waiters--;
358 }
359 }
360 tok->tid = pthread_self();
361 tok->held = 1;
362 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000363#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000364 EnterCriticalSection(&tok->cs);
365 ++tok->count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000366#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000367 if (tok->lock->tid == find_thread(NULL)) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000368 tok->count++;
369 return;
370 } else {
371 xmlMutexLock(tok->lock);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000372 tok->count = 1;
373 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000374#endif
375}
376
377/**
378 * xmlRMutexUnlock:
379 * @tok: the reentrant mutex
380 *
381 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
382 */
383void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000384xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000385{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000386 if (tok == NULL)
387 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000388#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000389 if (libxml_is_threaded == 0)
390 return;
391
Daniel Veillardb8478642001-10-12 17:29:10 +0000392 pthread_mutex_lock(&tok->lock);
393 tok->held--;
394 if (tok->held == 0) {
395 if (tok->waiters)
396 pthread_cond_signal(&tok->cv);
397 tok->tid = 0;
398 }
399 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000400#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000401 if (!--tok->count)
402 LeaveCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000403#elif defined HAVE_BEOS_THREADS
Daniel Veillard254b1262003-11-01 17:04:58 +0000404 if (tok->lock->tid == find_thread(NULL)) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000405 tok->count--;
406 if (tok->count == 0) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000407 xmlMutexUnlock(tok->lock);
408 }
409 return;
410 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000411#endif
412}
413
414/************************************************************************
415 * *
416 * Per thread global state handling *
417 * *
418 ************************************************************************/
419
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000420#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000421#ifdef xmlLastError
422#undef xmlLastError
423#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000424/**
425 * xmlFreeGlobalState:
426 * @state: a thread global state
427 *
428 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
429 * global state. It is is used here to reclaim memory resources.
430 */
431static void
432xmlFreeGlobalState(void *state)
433{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000434 xmlGlobalState *gs = (xmlGlobalState *) state;
435
436 /* free any memory allocated in the thread's xmlLastError */
437 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000438 free(state);
439}
440
441/**
442 * xmlNewGlobalState:
443 *
444 * xmlNewGlobalState() allocates a global state. This structure is used to
445 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000446 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000447 *
448 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
449 */
450static xmlGlobalStatePtr
451xmlNewGlobalState(void)
452{
453 xmlGlobalState *gs;
454
455 gs = malloc(sizeof(xmlGlobalState));
456 if (gs == NULL)
457 return(NULL);
458
William M. Brack8b2c7f12002-11-22 05:07:29 +0000459 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000460 xmlInitializeGlobalState(gs);
461 return (gs);
462}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000463#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000464
465
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000466#ifdef HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000467#if !defined(HAVE_COMPILER_TLS)
468#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000469typedef struct _xmlGlobalStateCleanupHelperParams
470{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000471 HANDLE thread;
472 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000473} xmlGlobalStateCleanupHelperParams;
474
Daniel Veillard01c13b52002-12-10 15:19:08 +0000475static void xmlGlobalStateCleanupHelper (void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000476{
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000477 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
478 WaitForSingleObject(params->thread, INFINITE);
479 CloseHandle(params->thread);
480 xmlFreeGlobalState(params->memory);
481 free(params);
482 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000483}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000484#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
485
486typedef struct _xmlGlobalStateCleanupHelperParams
487{
488 void *memory;
489 struct _xmlGlobalStateCleanupHelperParams * prev;
490 struct _xmlGlobalStateCleanupHelperParams * next;
491} xmlGlobalStateCleanupHelperParams;
492
493static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL;
494static CRITICAL_SECTION cleanup_helpers_cs;
495
496#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
497#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000498#endif /* HAVE_WIN32_THREADS */
499
Daniel Veillard82cb3192003-10-29 13:39:15 +0000500#if defined HAVE_BEOS_THREADS
William M. Brackb1d53162003-11-18 06:54:40 +0000501/**
502 * xmlGlobalStateCleanup:
503 * @data: unused parameter
504 *
505 * Used for Beos only
506 */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000507void xmlGlobalStateCleanup(void *data)
508{
509 void *globalval = tls_get(globalkey);
510 if (globalval != NULL)
511 xmlFreeGlobalState(globalval);
512}
513#endif
514
Daniel Veillard01c13b52002-12-10 15:19:08 +0000515/**
516 * xmlGetGlobalState:
517 *
518 * xmlGetGlobalState() is called to retrieve the global state for a thread.
519 *
520 * Returns the thread global state or NULL in case of error
521 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000522xmlGlobalStatePtr
523xmlGetGlobalState(void)
524{
525#ifdef HAVE_PTHREAD_H
526 xmlGlobalState *globalval;
527
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000528 if (libxml_is_threaded == 0)
529 return(NULL);
530
Daniel Veillarde28313b2001-12-06 14:08:31 +0000531 pthread_once(&once_control, xmlOnceInit);
532
Daniel Veillardb8478642001-10-12 17:29:10 +0000533 if ((globalval = (xmlGlobalState *)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000534 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000535 xmlGlobalState *tsd = xmlNewGlobalState();
536
537 pthread_setspecific(globalkey, tsd);
538 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000539 }
540 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000541#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000542#if defined(HAVE_COMPILER_TLS)
543 if (!tlstate_inited) {
544 tlstate_inited = 1;
545 xmlInitializeGlobalState(&tlstate);
546 }
547 return &tlstate;
548#else /* HAVE_COMPILER_TLS */
549 xmlGlobalState *globalval;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000550 xmlGlobalStateCleanupHelperParams * p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000551
Daniel Veillard62121e22005-02-24 15:38:52 +0000552 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000553#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
554 globalval = (xmlGlobalState *)TlsGetValue(globalkey);
555#else
556 p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
557 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
558#endif
559 if (globalval == NULL) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000560 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000561 p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000562 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000563#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000564 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
565 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
566 TlsSetValue(globalkey, tsd);
567 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000568#else
569 EnterCriticalSection(&cleanup_helpers_cs);
570 if (cleanup_helpers_head != NULL) {
571 cleanup_helpers_head->prev = p;
572 }
573 p->next = cleanup_helpers_head;
574 p->prev = NULL;
575 cleanup_helpers_head = p;
576 TlsSetValue(globalkey, p);
577 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000578#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000579
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000580 return (tsd);
581 }
582 return (globalval);
583#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000584#elif defined HAVE_BEOS_THREADS
585 xmlGlobalState *globalval;
586
587 xmlOnceInit();
588
589 if ((globalval = (xmlGlobalState *)
590 tls_get(globalkey)) == NULL) {
591 xmlGlobalState *tsd = xmlNewGlobalState();
592
593 tls_set(globalkey, tsd);
594 on_exit_thread(xmlGlobalStateCleanup, NULL);
595 return (tsd);
596 }
597 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000598#else
599 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000600#endif
601}
602
Daniel Veillardb8478642001-10-12 17:29:10 +0000603/************************************************************************
604 * *
605 * Library wide thread interfaces *
606 * *
607 ************************************************************************/
608
609/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000610 * xmlGetThreadId:
611 *
612 * xmlGetThreadId() find the current thread ID number
613 *
614 * Returns the current thread ID number
615 */
616int
617xmlGetThreadId(void)
618{
619#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000620 if (libxml_is_threaded == 0)
621 return(0);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000622 return((int) pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000623#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000624 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000625#elif defined HAVE_BEOS_THREADS
626 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000627#else
628 return((int) 0);
629#endif
630}
631
632/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000633 * xmlIsMainThread:
634 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000635 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000636 *
637 * Returns 1 if the current thread is the main thread, 0 otherwise
638 */
639int
640xmlIsMainThread(void)
641{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000642#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000643 if (libxml_is_threaded == -1)
644 xmlInitThreads();
645 if (libxml_is_threaded == 0)
646 return(1);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000647 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000648#elif defined HAVE_WIN32_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000649 xmlOnceInit ();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000650#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000651 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000652#endif
Daniel Veillard6f350292001-10-14 09:56:15 +0000653
654#ifdef DEBUG_THREADS
655 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
656#endif
657#ifdef HAVE_PTHREAD_H
658 return(mainthread == pthread_self());
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000659#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000660 return(mainthread == GetCurrentThreadId ());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000661#elif defined HAVE_BEOS_THREADS
662 return(mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000663#else
664 return(1);
665#endif
666}
667
668/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000669 * xmlLockLibrary:
670 *
671 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
672 * library.
673 */
674void
675xmlLockLibrary(void)
676{
Daniel Veillard6f350292001-10-14 09:56:15 +0000677#ifdef DEBUG_THREADS
678 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
679#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000680 xmlRMutexLock(xmlLibraryLock);
681}
682
683/**
684 * xmlUnlockLibrary:
685 *
686 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
687 * library.
688 */
689void
690xmlUnlockLibrary(void)
691{
Daniel Veillard6f350292001-10-14 09:56:15 +0000692#ifdef DEBUG_THREADS
693 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
694#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000695 xmlRMutexUnlock(xmlLibraryLock);
696}
697
698/**
699 * xmlInitThreads:
700 *
701 * xmlInitThreads() is used to to initialize all the thread related
702 * data of the libxml2 library.
703 */
704void
705xmlInitThreads(void)
706{
Daniel Veillard6f350292001-10-14 09:56:15 +0000707#ifdef DEBUG_THREADS
708 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
709#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000710#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000711 InitializeCriticalSection(&cleanup_helpers_cs);
712#endif
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000713#ifdef HAVE_PTHREAD_H
714 if (libxml_is_threaded == -1) {
715 if ((pthread_once != NULL) &&
716 (pthread_getspecific != NULL) &&
717 (pthread_setspecific != NULL) &&
718 (pthread_key_create != NULL) &&
719 (pthread_mutex_init != NULL) &&
720 (pthread_mutex_destroy != NULL) &&
721 (pthread_mutex_lock != NULL) &&
722 (pthread_mutex_unlock != NULL) &&
723 (pthread_cond_init != NULL) &&
724 (pthread_equal != NULL) &&
725 (pthread_self != NULL) &&
726 (pthread_key_create != NULL) &&
727 (pthread_cond_signal != NULL)) {
728 libxml_is_threaded = 1;
729/* fprintf(stderr, "Running multithreaded\n"); */
730 } else {
731/* fprintf(stderr, "Running without multithread\n"); */
732 libxml_is_threaded = 0;
733 }
734 }
735#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000736}
737
738/**
739 * xmlCleanupThreads:
740 *
741 * xmlCleanupThreads() is used to to cleanup all the thread related
742 * data of the libxml2 library once processing has ended.
743 */
744void
745xmlCleanupThreads(void)
746{
Daniel Veillard6f350292001-10-14 09:56:15 +0000747#ifdef DEBUG_THREADS
748 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
749#endif
Daniel Veillardc790bf42003-10-11 10:50:10 +0000750#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000751 if (globalkey != TLS_OUT_OF_INDEXES) {
752 xmlGlobalStateCleanupHelperParams * p;
753 EnterCriticalSection(&cleanup_helpers_cs);
754 p = cleanup_helpers_head;
755 while (p != NULL) {
756 xmlGlobalStateCleanupHelperParams * temp = p;
757 p = p->next;
758 xmlFreeGlobalState(temp->memory);
759 free(temp);
760 }
761 cleanup_helpers_head = 0;
762 LeaveCriticalSection(&cleanup_helpers_cs);
763 TlsFree(globalkey);
764 globalkey = TLS_OUT_OF_INDEXES;
765 }
766 DeleteCriticalSection(&cleanup_helpers_cs);
767#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000768}
Daniel Veillard6f350292001-10-14 09:56:15 +0000769
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000770#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000771/**
772 * xmlOnceInit
773 *
774 * xmlOnceInit() is used to initialize the value of mainthread for use
775 * in other routines. This function should only be called using
776 * pthread_once() in association with the once_control variable to ensure
777 * that the function is only called once. See man pthread_once for more
778 * details.
779 */
780static void
781xmlOnceInit(void) {
782#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000783 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000784 mainthread = pthread_self();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000785#endif
786
787#if defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000788 if (!run_once.done) {
Daniel Veillard36616dd2005-02-25 07:31:49 +0000789 if (InterlockedIncrement(&run_once.control) == 1)
Daniel Veillard62121e22005-02-24 15:38:52 +0000790 {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000791#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000792 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000793#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000794 mainthread = GetCurrentThreadId();
795 run_once.done = 1;
796 }
797 else {
798 /* Another thread is working; give up our slice and
799 * wait until they're done. */
800 while (!run_once.done)
801 Sleep(0);
802 }
803 }
Daniel Veillarde28313b2001-12-06 14:08:31 +0000804#endif
Daniel Veillard82cb3192003-10-29 13:39:15 +0000805
806#ifdef HAVE_BEOS_THREADS
807 if (atomic_add(&run_once_init, 1) == 0) {
808 globalkey = tls_allocate();
809 tls_set(globalkey, NULL);
810 mainthread = find_thread(NULL);
811 } else
812 atomic_add(&run_once_init, -1);
813#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000814}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000815#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000816
817/**
William M. Brack7a821652003-08-15 07:27:40 +0000818 * DllMain:
819 * @hinstDLL: handle to DLL instance
820 * @fdwReason: Reason code for entry
821 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000822 *
823 * Entry point for Windows library. It is being used to free thread-specific
824 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000825 *
826 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000827 */
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000828#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
829#if defined(LIBXML_STATIC_FOR_DLL)
830BOOL WINAPI xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
831#else
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000832BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000833#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000834{
835 switch(fdwReason) {
836 case DLL_THREAD_DETACH:
837 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000838 xmlGlobalState *globalval = NULL;
839 xmlGlobalStateCleanupHelperParams * p =
840 (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
841 globalval = (xmlGlobalState *)(p ? p->memory : NULL);
842 if (globalval) {
843 xmlFreeGlobalState(globalval);
844 TlsSetValue(globalkey,NULL);
845 }
846 if (p)
847 {
848 EnterCriticalSection(&cleanup_helpers_cs);
849 if (p == cleanup_helpers_head)
850 cleanup_helpers_head = p->next;
851 else
852 p->prev->next = p->next;
853 if (p->next != NULL)
854 p->next->prev = p->prev;
855 LeaveCriticalSection(&cleanup_helpers_cs);
856 free(p);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000857 }
858 }
859 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000860 }
861 return TRUE;
862}
863#endif
Daniel Veillard5d4644e2005-04-01 13:11:58 +0000864#define bottom_threads
865#include "elfgcchack.h"