blob: 8860697450e7464ff988cb6004d4eb1c32ae349d [file] [log] [blame]
Daniel Veillardb8478642001-10-12 17:29:10 +00001/**
Daniel Veillarddee23482008-04-11 12:58:43 +00002 * threads.c: set of generic threading related routines
Daniel Veillardb8478642001-10-12 17:29:10 +00003 *
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>
Eric Zurcher243b0342009-10-01 00:13:07 +020029#elif defined HAVE_WIN32_THREADS
Nick Wellnhofere3890542017-10-09 00:20:01 +020030#define WIN32_LEAN_AND_MEAN
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000031#include <windows.h>
Igor Zlatkovicf2160a02002-10-31 15:58:42 +000032#ifndef HAVE_COMPILER_TLS
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000033#include <process.h>
34#endif
35#endif
Daniel Veillardb8478642001-10-12 17:29:10 +000036
Daniel Veillard82cb3192003-10-29 13:39:15 +000037#ifdef HAVE_BEOS_THREADS
38#include <OS.h>
39#include <TLS.h>
40#endif
41
Daniel Veillardb8478642001-10-12 17:29:10 +000042#if defined(SOLARIS)
43#include <note.h>
44#endif
45
Daniel Veillard6f350292001-10-14 09:56:15 +000046/* #define DEBUG_THREADS */
Daniel Veillardb8478642001-10-12 17:29:10 +000047
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000048#ifdef HAVE_PTHREAD_H
49
50static int libxml_is_threaded = -1;
Michael Heimpoldfff8a6b2014-12-22 11:12:12 +080051#if defined(__GNUC__) && defined(__GLIBC__)
Nick Wellnhofer2cdaaab2017-09-14 21:30:51 +020052#ifdef __linux__
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000053#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
Nick Wellnhofer1f09aea2017-06-17 15:05:34 +020054#pragma weak pthread_once
55#pragma weak pthread_getspecific
56#pragma weak pthread_setspecific
57#pragma weak pthread_key_create
58#pragma weak pthread_key_delete
59#pragma weak pthread_mutex_init
60#pragma weak pthread_mutex_destroy
61#pragma weak pthread_mutex_lock
62#pragma weak pthread_mutex_unlock
63#pragma weak pthread_cond_init
64#pragma weak pthread_cond_destroy
65#pragma weak pthread_cond_wait
66#pragma weak pthread_equal
67#pragma weak pthread_self
68#pragma weak pthread_key_create
69#pragma weak pthread_key_delete
70#pragma weak pthread_cond_signal
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000071#endif
Nick Wellnhofer2cdaaab2017-09-14 21:30:51 +020072#endif /* __linux__ */
Michael Heimpoldfff8a6b2014-12-22 11:12:12 +080073#endif /* defined(__GNUC__) && defined(__GLIBC__) */
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000074#endif /* HAVE_PTHREAD_H */
75
Daniel Veillardb8478642001-10-12 17:29:10 +000076/*
77 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
78 * to avoid some crazyness since xmlMalloc/xmlFree may actually
79 * be hosted on allocated blocks needing them for the allocation ...
80 */
81
82/*
83 * xmlMutex are a simple mutual exception locks
84 */
85struct _xmlMutex {
86#ifdef HAVE_PTHREAD_H
87 pthread_mutex_t lock;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000088#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +000089 HANDLE mutex;
Daniel Veillard82cb3192003-10-29 13:39:15 +000090#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +000091 sem_id sem;
92 thread_id tid;
Daniel Veillardb8478642001-10-12 17:29:10 +000093#else
94 int empty;
95#endif
96};
97
98/*
99 * xmlRMutex are reentrant mutual exception locks
100 */
101struct _xmlRMutex {
102#ifdef HAVE_PTHREAD_H
103 pthread_mutex_t lock;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000104 unsigned int held;
105 unsigned int waiters;
106 pthread_t tid;
107 pthread_cond_t cv;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000108#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000109 CRITICAL_SECTION cs;
110 unsigned int count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000111#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000112 xmlMutexPtr lock;
113 thread_id tid;
114 int32 count;
Daniel Veillardb8478642001-10-12 17:29:10 +0000115#else
116 int empty;
117#endif
118};
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000119
Daniel Veillardb8478642001-10-12 17:29:10 +0000120/*
121 * This module still has some internal static data.
122 * - xmlLibraryLock a global lock
123 * - globalkey used for per-thread data
Daniel Veillardb8478642001-10-12 17:29:10 +0000124 */
Daniel Veillard6f350292001-10-14 09:56:15 +0000125
Daniel Veillardb8478642001-10-12 17:29:10 +0000126#ifdef HAVE_PTHREAD_H
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000127static pthread_key_t globalkey;
128static pthread_t mainthread;
Daniel Veillarde28313b2001-12-06 14:08:31 +0000129static pthread_once_t once_control = PTHREAD_ONCE_INIT;
Friedrich Haubensak3f6cfbd2012-09-12 17:34:53 +0200130static pthread_once_t once_control_init = PTHREAD_ONCE_INIT;
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000131static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000132#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000133#if defined(HAVE_COMPILER_TLS)
134static __declspec(thread) xmlGlobalState tlstate;
135static __declspec(thread) int tlstate_inited = 0;
136#else /* HAVE_COMPILER_TLS */
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000137static DWORD globalkey = TLS_OUT_OF_INDEXES;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000138#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000139static DWORD mainthread;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000140static struct {
Daniel Veillard36616dd2005-02-25 07:31:49 +0000141 DWORD done;
142 DWORD control;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000143} run_once = { 0, 0};
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000144static volatile LPCRITICAL_SECTION global_init_lock = NULL;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000145
Daniel Veillard82cb3192003-10-29 13:39:15 +0000146/* endif HAVE_WIN32_THREADS */
147#elif defined HAVE_BEOS_THREADS
148int32 globalkey = 0;
149thread_id mainthread = 0;
150int32 run_once_init = 0;
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000151static int32 global_init_lock = -1;
152static vint32 global_init_count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000153#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000154
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000155static xmlRMutexPtr xmlLibraryLock = NULL;
156
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000157#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000158static void xmlOnceInit(void);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000159#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000160
161/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000162 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000163 *
164 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
165 * synchronizing access to data.
166 *
167 * Returns a new simple mutex pointer or NULL in case of error
168 */
169xmlMutexPtr
170xmlNewMutex(void)
171{
172 xmlMutexPtr tok;
173
174 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
175 return (NULL);
176#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000177 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000178 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000179#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000180 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000181#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000182 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
183 free(tok);
184 return NULL;
185 }
186 tok->tid = -1;
Daniel Veillardb8478642001-10-12 17:29:10 +0000187#endif
188 return (tok);
189}
190
191/**
192 * xmlFreeMutex:
193 * @tok: the simple mutex
194 *
195 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
196 * struct.
197 */
198void
199xmlFreeMutex(xmlMutexPtr tok)
200{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000201 if (tok == NULL)
202 return;
Daniel Veillarddf101d82003-07-08 14:03:36 +0000203
Daniel Veillardb8478642001-10-12 17:29:10 +0000204#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000205 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000206 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000207#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000208 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000209#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000210 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000211#endif
212 free(tok);
213}
214
215/**
216 * xmlMutexLock:
217 * @tok: the simple mutex
218 *
219 * xmlMutexLock() is used to lock a libxml2 token.
220 */
221void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000222xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000223{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000224 if (tok == NULL)
225 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000226#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000227 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000228 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000229#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000230 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000231#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000232 if (acquire_sem(tok->sem) != B_NO_ERROR) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000233#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000234 xmlGenericError(xmlGenericErrorContext,
235 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
Daniel Veillard82cb3192003-10-29 13:39:15 +0000236#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000237 }
238 tok->tid = find_thread(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000239#endif
240
241}
242
243/**
244 * xmlMutexUnlock:
245 * @tok: the simple mutex
246 *
247 * xmlMutexUnlock() is used to unlock a libxml2 token.
248 */
249void
Daniel Veillard5805be22003-08-28 08:03:23 +0000250xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000251{
Daniel Veillard5805be22003-08-28 08:03:23 +0000252 if (tok == NULL)
253 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000254#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000255 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000256 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000257#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000258 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000259#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000260 if (tok->tid == find_thread(NULL)) {
261 tok->tid = -1;
262 release_sem(tok->sem);
263 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000264#endif
265}
266
267/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000268 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000269 *
270 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
271 * synchronizing access to data. token_r is a re-entrant lock and thus useful
272 * for synchronizing access to data structures that may be manipulated in a
273 * recursive fashion.
274 *
275 * Returns the new reentrant mutex pointer or NULL in case of error
276 */
277xmlRMutexPtr
278xmlNewRMutex(void)
279{
280 xmlRMutexPtr tok;
281
282 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
283 return (NULL);
284#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000285 if (libxml_is_threaded != 0) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000286 pthread_mutex_init(&tok->lock, NULL);
287 tok->held = 0;
288 tok->waiters = 0;
289 pthread_cond_init(&tok->cv, NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000290 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000291#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000292 InitializeCriticalSection(&tok->cs);
293 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000294#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000295 if ((tok->lock = xmlNewMutex()) == NULL) {
296 free(tok);
297 return NULL;
298 }
299 tok->count = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000300#endif
301 return (tok);
302}
303
304/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000305 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000306 * @tok: the reentrant mutex
307 *
308 * xmlRFreeMutex() is used to reclaim resources associated with a
309 * reentrant mutex.
310 */
311void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000312xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000313{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000314 if (tok == NULL)
315 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000316#ifdef HAVE_PTHREAD_H
Daniel Veillarda8b54132006-06-29 11:50:18 +0000317 if (libxml_is_threaded != 0) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000318 pthread_mutex_destroy(&tok->lock);
319 pthread_cond_destroy(&tok->cv);
Daniel Veillarda8b54132006-06-29 11:50:18 +0000320 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000321#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000322 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000323#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000324 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000325#endif
326 free(tok);
327}
328
329/**
330 * xmlRMutexLock:
331 * @tok: the reentrant mutex
332 *
333 * xmlRMutexLock() is used to lock a libxml2 token_r.
334 */
335void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000336xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000337{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000338 if (tok == NULL)
339 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000340#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000341 if (libxml_is_threaded == 0)
342 return;
343
Daniel Veillardb8478642001-10-12 17:29:10 +0000344 pthread_mutex_lock(&tok->lock);
345 if (tok->held) {
346 if (pthread_equal(tok->tid, pthread_self())) {
347 tok->held++;
348 pthread_mutex_unlock(&tok->lock);
349 return;
350 } else {
351 tok->waiters++;
352 while (tok->held)
353 pthread_cond_wait(&tok->cv, &tok->lock);
354 tok->waiters--;
355 }
356 }
357 tok->tid = pthread_self();
358 tok->held = 1;
359 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000360#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000361 EnterCriticalSection(&tok->cs);
Daniel Veillard8854e462014-10-13 15:03:58 +0800362 tok->count++;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000363#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000364 if (tok->lock->tid == find_thread(NULL)) {
365 tok->count++;
366 return;
367 } else {
368 xmlMutexLock(tok->lock);
369 tok->count = 1;
370 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000371#endif
372}
373
374/**
375 * xmlRMutexUnlock:
376 * @tok: the reentrant mutex
377 *
378 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
379 */
380void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000381xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000382{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000383 if (tok == NULL)
384 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000385#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000386 if (libxml_is_threaded == 0)
387 return;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000388
Daniel Veillardb8478642001-10-12 17:29:10 +0000389 pthread_mutex_lock(&tok->lock);
390 tok->held--;
391 if (tok->held == 0) {
392 if (tok->waiters)
393 pthread_cond_signal(&tok->cv);
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200394 memset(&tok->tid, 0, sizeof(tok->tid));
Daniel Veillardb8478642001-10-12 17:29:10 +0000395 }
396 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000397#elif defined HAVE_WIN32_THREADS
Daniel Veillard8854e462014-10-13 15:03:58 +0800398 if (tok->count > 0) {
Daniel Veillard8854e462014-10-13 15:03:58 +0800399 tok->count--;
Steve Nairn620a7062015-03-03 19:40:06 +0800400 LeaveCriticalSection(&tok->cs);
Daniel Veillard8854e462014-10-13 15:03:58 +0800401 }
Daniel Veillard82cb3192003-10-29 13:39:15 +0000402#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000403 if (tok->lock->tid == find_thread(NULL)) {
404 tok->count--;
405 if (tok->count == 0) {
406 xmlMutexUnlock(tok->lock);
407 }
408 return;
409 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000410#endif
411}
412
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000413/**
414 * xmlGlobalInitMutexLock
415 *
416 * Makes sure that the global initialization mutex is initialized and
417 * locks it.
418 */
419void
420__xmlGlobalInitMutexLock(void)
421{
422 /* Make sure the global init lock is initialized and then lock it. */
423#ifdef HAVE_PTHREAD_H
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000424 /* The mutex is statically initialized, so we just lock it. */
Daniel Richard G5706b6d2012-08-06 11:32:54 +0800425 if (pthread_mutex_lock != NULL)
Mike Hommeye6f05092010-10-15 19:50:03 +0200426 pthread_mutex_lock(&global_init_lock);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000427#elif defined HAVE_WIN32_THREADS
428 LPCRITICAL_SECTION cs;
429
430 /* Create a new critical section */
431 if (global_init_lock == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000432 cs = malloc(sizeof(CRITICAL_SECTION));
433 if (cs == NULL) {
434 xmlGenericError(xmlGenericErrorContext,
435 "xmlGlobalInitMutexLock: out of memory\n");
436 return;
437 }
438 InitializeCriticalSection(cs);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000439
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000440 /* Swap it into the global_init_lock */
Rob Richardse967f0b2007-06-08 19:36:04 +0000441#ifdef InterlockedCompareExchangePointer
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000442 InterlockedCompareExchangePointer(&global_init_lock, cs, NULL);
443#else /* Use older void* version */
444 InterlockedCompareExchange((void **) &global_init_lock,
445 (void *) cs, NULL);
Rob Richardse967f0b2007-06-08 19:36:04 +0000446#endif /* InterlockedCompareExchangePointer */
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000447
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000448 /* If another thread successfully recorded its critical
449 * section in the global_init_lock then discard the one
450 * allocated by this thread. */
451 if (global_init_lock != cs) {
452 DeleteCriticalSection(cs);
453 free(cs);
454 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000455 }
456
457 /* Lock the chosen critical section */
458 EnterCriticalSection(global_init_lock);
459#elif defined HAVE_BEOS_THREADS
460 int32 sem;
461
462 /* Allocate a new semaphore */
463 sem = create_sem(1, "xmlGlobalinitMutex");
464
465 while (global_init_lock == -1) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000466 if (atomic_add(&global_init_count, 1) == 0) {
467 global_init_lock = sem;
468 } else {
469 snooze(1);
470 atomic_add(&global_init_count, -1);
471 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000472 }
473
474 /* If another thread successfully recorded its critical
475 * section in the global_init_lock then discard the one
476 * allocated by this thread. */
477 if (global_init_lock != sem)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000478 delete_sem(sem);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000479
480 /* Acquire the chosen semaphore */
481 if (acquire_sem(global_init_lock) != B_NO_ERROR) {
482#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000483 xmlGenericError(xmlGenericErrorContext,
484 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000485#endif
486 }
487#endif
488}
489
490void
491__xmlGlobalInitMutexUnlock(void)
492{
493#ifdef HAVE_PTHREAD_H
Daniel Richard G5706b6d2012-08-06 11:32:54 +0800494 if (pthread_mutex_unlock != NULL)
Mike Hommeye6f05092010-10-15 19:50:03 +0200495 pthread_mutex_unlock(&global_init_lock);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000496#elif defined HAVE_WIN32_THREADS
Daniel Veillard14d465d2008-03-24 11:12:55 +0000497 if (global_init_lock != NULL) {
498 LeaveCriticalSection(global_init_lock);
499 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000500#elif defined HAVE_BEOS_THREADS
501 release_sem(global_init_lock);
502#endif
503}
504
Rob Richards91eb5602007-11-16 10:54:59 +0000505/**
506 * xmlGlobalInitMutexDestroy
507 *
508 * Makes sure that the global initialization mutex is destroyed before
509 * application termination.
510 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000511void
512__xmlGlobalInitMutexDestroy(void)
Rob Richards91eb5602007-11-16 10:54:59 +0000513{
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200514#ifdef HAVE_PTHREAD_H
515#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000516 if (global_init_lock != NULL) {
517 DeleteCriticalSection(global_init_lock);
518 free(global_init_lock);
519 global_init_lock = NULL;
Rob Richards91eb5602007-11-16 10:54:59 +0000520 }
521#endif
522}
523
Daniel Veillardb8478642001-10-12 17:29:10 +0000524/************************************************************************
525 * *
526 * Per thread global state handling *
527 * *
528 ************************************************************************/
529
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000530#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000531#ifdef xmlLastError
532#undef xmlLastError
533#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000534
Daniel Veillardb8478642001-10-12 17:29:10 +0000535/**
536 * xmlFreeGlobalState:
537 * @state: a thread global state
538 *
539 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
540 * global state. It is is used here to reclaim memory resources.
541 */
542static void
543xmlFreeGlobalState(void *state)
544{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000545 xmlGlobalState *gs = (xmlGlobalState *) state;
546
547 /* free any memory allocated in the thread's xmlLastError */
548 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000549 free(state);
550}
551
552/**
553 * xmlNewGlobalState:
554 *
555 * xmlNewGlobalState() allocates a global state. This structure is used to
556 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000557 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000558 *
559 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
560 */
561static xmlGlobalStatePtr
562xmlNewGlobalState(void)
563{
564 xmlGlobalState *gs;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000565
Daniel Veillardb8478642001-10-12 17:29:10 +0000566 gs = malloc(sizeof(xmlGlobalState));
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000567 if (gs == NULL) {
568 xmlGenericError(xmlGenericErrorContext,
569 "xmlGetGlobalState: out of memory\n");
570 return (NULL);
571 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000572
William M. Brack8b2c7f12002-11-22 05:07:29 +0000573 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000574 xmlInitializeGlobalState(gs);
575 return (gs);
576}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000577#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000578
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200579#ifdef HAVE_PTHREAD_H
Eric Zurcher243b0342009-10-01 00:13:07 +0200580#elif defined HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000581#if !defined(HAVE_COMPILER_TLS)
582#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000583typedef struct _xmlGlobalStateCleanupHelperParams {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000584 HANDLE thread;
585 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000586} xmlGlobalStateCleanupHelperParams;
587
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000588static void XMLCDECL
589xmlGlobalStateCleanupHelper(void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000590{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000591 xmlGlobalStateCleanupHelperParams *params =
592 (xmlGlobalStateCleanupHelperParams *) p;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000593 WaitForSingleObject(params->thread, INFINITE);
594 CloseHandle(params->thread);
595 xmlFreeGlobalState(params->memory);
596 free(params);
597 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000598}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000599#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
600
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000601typedef struct _xmlGlobalStateCleanupHelperParams {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000602 void *memory;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000603 struct _xmlGlobalStateCleanupHelperParams *prev;
604 struct _xmlGlobalStateCleanupHelperParams *next;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000605} xmlGlobalStateCleanupHelperParams;
606
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000607static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000608static CRITICAL_SECTION cleanup_helpers_cs;
609
610#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
611#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000612#endif /* HAVE_WIN32_THREADS */
613
Daniel Veillard82cb3192003-10-29 13:39:15 +0000614#if defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000615
William M. Brackb1d53162003-11-18 06:54:40 +0000616/**
617 * xmlGlobalStateCleanup:
618 * @data: unused parameter
619 *
620 * Used for Beos only
621 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000622void
623xmlGlobalStateCleanup(void *data)
Daniel Veillard82cb3192003-10-29 13:39:15 +0000624{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000625 void *globalval = tls_get(globalkey);
626
627 if (globalval != NULL)
628 xmlFreeGlobalState(globalval);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000629}
630#endif
631
Daniel Veillard01c13b52002-12-10 15:19:08 +0000632/**
633 * xmlGetGlobalState:
634 *
635 * xmlGetGlobalState() is called to retrieve the global state for a thread.
636 *
637 * Returns the thread global state or NULL in case of error
638 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000639xmlGlobalStatePtr
640xmlGetGlobalState(void)
641{
642#ifdef HAVE_PTHREAD_H
643 xmlGlobalState *globalval;
644
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000645 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000646 return (NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000647
Daniel Veillarde28313b2001-12-06 14:08:31 +0000648 pthread_once(&once_control, xmlOnceInit);
649
Daniel Veillardb8478642001-10-12 17:29:10 +0000650 if ((globalval = (xmlGlobalState *)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000651 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000652 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000653 if (tsd == NULL)
654 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000655
656 pthread_setspecific(globalkey, tsd);
657 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000658 }
659 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000660#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000661#if defined(HAVE_COMPILER_TLS)
662 if (!tlstate_inited) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000663 tlstate_inited = 1;
664 xmlInitializeGlobalState(&tlstate);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000665 }
666 return &tlstate;
667#else /* HAVE_COMPILER_TLS */
668 xmlGlobalState *globalval;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000669 xmlGlobalStateCleanupHelperParams *p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000670
Daniel Veillard62121e22005-02-24 15:38:52 +0000671 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000672#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000673 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000674#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000675 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
676 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000677#endif
678 if (globalval == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000679 xmlGlobalState *tsd = xmlNewGlobalState();
680
681 if (tsd == NULL)
682 return(NULL);
683 p = (xmlGlobalStateCleanupHelperParams *)
684 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
685 if (p == NULL) {
686 xmlGenericError(xmlGenericErrorContext,
687 "xmlGetGlobalState: out of memory\n");
Daniel Veillardbf2ebff2009-01-18 14:57:04 +0000688 xmlFreeGlobalState(tsd);
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000689 return(NULL);
690 }
691 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000692#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000693 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
694 GetCurrentProcess(), &p->thread, 0, TRUE,
695 DUPLICATE_SAME_ACCESS);
696 TlsSetValue(globalkey, tsd);
697 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000698#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000699 EnterCriticalSection(&cleanup_helpers_cs);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000700 if (cleanup_helpers_head != NULL) {
701 cleanup_helpers_head->prev = p;
702 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000703 p->next = cleanup_helpers_head;
704 p->prev = NULL;
705 cleanup_helpers_head = p;
706 TlsSetValue(globalkey, p);
707 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000708#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000709
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000710 return (tsd);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000711 }
712 return (globalval);
713#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000714#elif defined HAVE_BEOS_THREADS
715 xmlGlobalState *globalval;
716
717 xmlOnceInit();
718
Daniel Veillard14d465d2008-03-24 11:12:55 +0000719 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000720 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000721 if (tsd == NULL)
722 return (NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000723
724 tls_set(globalkey, tsd);
725 on_exit_thread(xmlGlobalStateCleanup, NULL);
726 return (tsd);
727 }
728 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000729#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000730 return (NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000731#endif
732}
733
Daniel Veillardb8478642001-10-12 17:29:10 +0000734/************************************************************************
735 * *
736 * Library wide thread interfaces *
737 * *
738 ************************************************************************/
739
740/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000741 * xmlGetThreadId:
742 *
743 * xmlGetThreadId() find the current thread ID number
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200744 * Note that this is likely to be broken on some platforms using pthreads
745 * as the specification doesn't mandate pthread_t to be an integer type
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000746 *
747 * Returns the current thread ID number
748 */
749int
750xmlGetThreadId(void)
751{
752#ifdef HAVE_PTHREAD_H
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200753 pthread_t id;
754 int ret;
755
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000756 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000757 return (0);
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200758 id = pthread_self();
759 /* horrible but preserves compat, see warning above */
760 memcpy(&ret, &id, sizeof(ret));
761 return (ret);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000762#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000763 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000764#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000765 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000766#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000767 return ((int) 0);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000768#endif
769}
770
771/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000772 * xmlIsMainThread:
773 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000774 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000775 *
776 * Returns 1 if the current thread is the main thread, 0 otherwise
777 */
778int
779xmlIsMainThread(void)
780{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000781#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000782 if (libxml_is_threaded == -1)
783 xmlInitThreads();
784 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000785 return (1);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000786 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000787#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000788 xmlOnceInit();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000789#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000790 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000791#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000792
Daniel Veillard6f350292001-10-14 09:56:15 +0000793#ifdef DEBUG_THREADS
794 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
795#endif
796#ifdef HAVE_PTHREAD_H
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200797 return (pthread_equal(mainthread,pthread_self()));
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000798#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000799 return (mainthread == GetCurrentThreadId());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000800#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000801 return (mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000802#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000803 return (1);
Daniel Veillard6f350292001-10-14 09:56:15 +0000804#endif
805}
806
807/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000808 * xmlLockLibrary:
809 *
810 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
811 * library.
812 */
813void
814xmlLockLibrary(void)
815{
Daniel Veillard6f350292001-10-14 09:56:15 +0000816#ifdef DEBUG_THREADS
817 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
818#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000819 xmlRMutexLock(xmlLibraryLock);
820}
821
822/**
823 * xmlUnlockLibrary:
824 *
825 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
826 * library.
827 */
828void
829xmlUnlockLibrary(void)
830{
Daniel Veillard6f350292001-10-14 09:56:15 +0000831#ifdef DEBUG_THREADS
832 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
833#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000834 xmlRMutexUnlock(xmlLibraryLock);
835}
836
837/**
838 * xmlInitThreads:
839 *
840 * xmlInitThreads() is used to to initialize all the thread related
841 * data of the libxml2 library.
842 */
843void
844xmlInitThreads(void)
845{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000846#ifdef HAVE_PTHREAD_H
847 if (libxml_is_threaded == -1) {
848 if ((pthread_once != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000849 (pthread_getspecific != NULL) &&
850 (pthread_setspecific != NULL) &&
851 (pthread_key_create != NULL) &&
Daniel Veillardd4a3f242009-01-18 15:41:30 +0000852 (pthread_key_delete != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000853 (pthread_mutex_init != NULL) &&
854 (pthread_mutex_destroy != NULL) &&
855 (pthread_mutex_lock != NULL) &&
856 (pthread_mutex_unlock != NULL) &&
857 (pthread_cond_init != NULL) &&
Daniel Veillard2cba4152008-08-27 11:45:41 +0000858 (pthread_cond_destroy != NULL) &&
859 (pthread_cond_wait != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000860 (pthread_equal != NULL) &&
861 (pthread_self != NULL) &&
862 (pthread_cond_signal != NULL)) {
863 libxml_is_threaded = 1;
864
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000865/* fprintf(stderr, "Running multithreaded\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000866 } else {
867
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000868/* fprintf(stderr, "Running without multithread\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000869 libxml_is_threaded = 0;
870 }
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000871 }
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200872#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
873 InitializeCriticalSection(&cleanup_helpers_cs);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000874#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000875}
876
877/**
878 * xmlCleanupThreads:
879 *
880 * xmlCleanupThreads() is used to to cleanup all the thread related
881 * data of the libxml2 library once processing has ended.
Daniel Veillard01101202009-02-21 09:22:04 +0000882 *
883 * WARNING: if your application is multithreaded or has plugin support
884 * calling this may crash the application if another thread or
885 * a plugin is still using libxml2. It's sometimes very hard to
886 * guess if libxml2 is in use in the application, some libraries
887 * or plugins may use it without notice. In case of doubt abstain
888 * from calling this function or do it just before calling exit()
889 * to avoid leak reports from valgrind !
Daniel Veillardb8478642001-10-12 17:29:10 +0000890 */
891void
892xmlCleanupThreads(void)
893{
Daniel Veillard6f350292001-10-14 09:56:15 +0000894#ifdef DEBUG_THREADS
895 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
896#endif
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200897#ifdef HAVE_PTHREAD_H
898 if ((libxml_is_threaded) && (pthread_key_delete != NULL))
899 pthread_key_delete(globalkey);
Friedrich Haubensak3f6cfbd2012-09-12 17:34:53 +0200900 once_control = once_control_init;
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200901#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000902 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000903 xmlGlobalStateCleanupHelperParams *p;
904
905 EnterCriticalSection(&cleanup_helpers_cs);
906 p = cleanup_helpers_head;
907 while (p != NULL) {
908 xmlGlobalStateCleanupHelperParams *temp = p;
909
910 p = p->next;
911 xmlFreeGlobalState(temp->memory);
912 free(temp);
913 }
914 cleanup_helpers_head = 0;
915 LeaveCriticalSection(&cleanup_helpers_cs);
916 TlsFree(globalkey);
917 globalkey = TLS_OUT_OF_INDEXES;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000918 }
919 DeleteCriticalSection(&cleanup_helpers_cs);
920#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000921}
Daniel Veillard6f350292001-10-14 09:56:15 +0000922
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000923#ifdef LIBXML_THREAD_ENABLED
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000924
Daniel Veillarde28313b2001-12-06 14:08:31 +0000925/**
926 * xmlOnceInit
927 *
928 * xmlOnceInit() is used to initialize the value of mainthread for use
929 * in other routines. This function should only be called using
930 * pthread_once() in association with the once_control variable to ensure
931 * that the function is only called once. See man pthread_once for more
932 * details.
933 */
934static void
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000935xmlOnceInit(void)
936{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000937#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000938 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000939 mainthread = pthread_self();
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800940 __xmlInitializeDict();
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200941#elif defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000942 if (!run_once.done) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000943 if (InterlockedIncrement(&run_once.control) == 1) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000944#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000945 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000946#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000947 mainthread = GetCurrentThreadId();
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800948 __xmlInitializeDict();
Daniel Veillard62121e22005-02-24 15:38:52 +0000949 run_once.done = 1;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000950 } else {
Daniel Veillard62121e22005-02-24 15:38:52 +0000951 /* Another thread is working; give up our slice and
952 * wait until they're done. */
953 while (!run_once.done)
954 Sleep(0);
955 }
956 }
Eric Zurcher243b0342009-10-01 00:13:07 +0200957#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000958 if (atomic_add(&run_once_init, 1) == 0) {
959 globalkey = tls_allocate();
960 tls_set(globalkey, NULL);
961 mainthread = find_thread(NULL);
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800962 __xmlInitializeDict();
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000963 } else
964 atomic_add(&run_once_init, -1);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000965#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000966}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000967#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000968
969/**
William M. Brack7a821652003-08-15 07:27:40 +0000970 * DllMain:
971 * @hinstDLL: handle to DLL instance
972 * @fdwReason: Reason code for entry
973 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000974 *
975 * Entry point for Windows library. It is being used to free thread-specific
976 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000977 *
978 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000979 */
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200980#ifdef HAVE_PTHREAD_H
981#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000982#if defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000983BOOL XMLCALL
984xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000985#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000986BOOL WINAPI
987DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000988#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000989{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000990 switch (fdwReason) {
991 case DLL_THREAD_DETACH:
992 if (globalkey != TLS_OUT_OF_INDEXES) {
993 xmlGlobalState *globalval = NULL;
994 xmlGlobalStateCleanupHelperParams *p =
995 (xmlGlobalStateCleanupHelperParams *)
996 TlsGetValue(globalkey);
997 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
998 if (globalval) {
999 xmlFreeGlobalState(globalval);
1000 TlsSetValue(globalkey, NULL);
1001 }
1002 if (p) {
1003 EnterCriticalSection(&cleanup_helpers_cs);
1004 if (p == cleanup_helpers_head)
1005 cleanup_helpers_head = p->next;
1006 else
1007 p->prev->next = p->next;
1008 if (p->next != NULL)
1009 p->next->prev = p->prev;
1010 LeaveCriticalSection(&cleanup_helpers_cs);
1011 free(p);
1012 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001013 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +00001014 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +00001015 }
1016 return TRUE;
1017}
1018#endif
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001019#define bottom_threads
1020#include "elfgcchack.h"