blob: 0433ac0f5919d57b585e3c61adf01f2f2db33efe [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
Nick Wellnhofer2677fbf2017-11-27 14:20:31 +010050#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 303) && \
51 defined(__GLIBC__) && defined(__linux__)
52
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000053static int libxml_is_threaded = -1;
Nick Wellnhofer2677fbf2017-11-27 14:20:31 +010054
55#define XML_PTHREAD_WEAK
56
Nick Wellnhofer1f09aea2017-06-17 15:05:34 +020057#pragma weak pthread_once
58#pragma weak pthread_getspecific
59#pragma weak pthread_setspecific
60#pragma weak pthread_key_create
61#pragma weak pthread_key_delete
62#pragma weak pthread_mutex_init
63#pragma weak pthread_mutex_destroy
64#pragma weak pthread_mutex_lock
65#pragma weak pthread_mutex_unlock
66#pragma weak pthread_cond_init
67#pragma weak pthread_cond_destroy
68#pragma weak pthread_cond_wait
69#pragma weak pthread_equal
70#pragma weak pthread_self
71#pragma weak pthread_key_create
72#pragma weak pthread_key_delete
73#pragma weak pthread_cond_signal
Nick Wellnhofer2677fbf2017-11-27 14:20:31 +010074
75#else /* __GNUC__, __GLIBC__, __linux__ */
76
77static int libxml_is_threaded = 1;
78
79#endif /* __GNUC__, __GLIBC__, __linux__ */
80
Daniel Veillarddbfe05a2005-05-04 09:18:00 +000081#endif /* HAVE_PTHREAD_H */
82
Daniel Veillardb8478642001-10-12 17:29:10 +000083/*
84 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
85 * to avoid some crazyness since xmlMalloc/xmlFree may actually
86 * be hosted on allocated blocks needing them for the allocation ...
87 */
88
89/*
90 * xmlMutex are a simple mutual exception locks
91 */
92struct _xmlMutex {
93#ifdef HAVE_PTHREAD_H
94 pthread_mutex_t lock;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +000095#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +000096 HANDLE mutex;
Daniel Veillard82cb3192003-10-29 13:39:15 +000097#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +000098 sem_id sem;
99 thread_id tid;
Daniel Veillardb8478642001-10-12 17:29:10 +0000100#else
101 int empty;
102#endif
103};
104
105/*
106 * xmlRMutex are reentrant mutual exception locks
107 */
108struct _xmlRMutex {
109#ifdef HAVE_PTHREAD_H
110 pthread_mutex_t lock;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000111 unsigned int held;
112 unsigned int waiters;
113 pthread_t tid;
114 pthread_cond_t cv;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000115#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000116 CRITICAL_SECTION cs;
117 unsigned int count;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000118#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000119 xmlMutexPtr lock;
120 thread_id tid;
121 int32 count;
Daniel Veillardb8478642001-10-12 17:29:10 +0000122#else
123 int empty;
124#endif
125};
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000126
Daniel Veillardb8478642001-10-12 17:29:10 +0000127/*
128 * This module still has some internal static data.
129 * - xmlLibraryLock a global lock
130 * - globalkey used for per-thread data
Daniel Veillardb8478642001-10-12 17:29:10 +0000131 */
Daniel Veillard6f350292001-10-14 09:56:15 +0000132
Daniel Veillardb8478642001-10-12 17:29:10 +0000133#ifdef HAVE_PTHREAD_H
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000134static pthread_key_t globalkey;
135static pthread_t mainthread;
Daniel Veillarde28313b2001-12-06 14:08:31 +0000136static pthread_once_t once_control = PTHREAD_ONCE_INIT;
Friedrich Haubensak3f6cfbd2012-09-12 17:34:53 +0200137static pthread_once_t once_control_init = PTHREAD_ONCE_INIT;
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000138static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000139#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000140#if defined(HAVE_COMPILER_TLS)
141static __declspec(thread) xmlGlobalState tlstate;
142static __declspec(thread) int tlstate_inited = 0;
143#else /* HAVE_COMPILER_TLS */
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000144static DWORD globalkey = TLS_OUT_OF_INDEXES;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000145#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000146static DWORD mainthread;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000147static struct {
Daniel Veillard36616dd2005-02-25 07:31:49 +0000148 DWORD done;
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200149 LONG control;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000150} run_once = { 0, 0};
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000151static volatile LPCRITICAL_SECTION global_init_lock = NULL;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000152
Daniel Veillard82cb3192003-10-29 13:39:15 +0000153/* endif HAVE_WIN32_THREADS */
154#elif defined HAVE_BEOS_THREADS
155int32 globalkey = 0;
156thread_id mainthread = 0;
157int32 run_once_init = 0;
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000158static int32 global_init_lock = -1;
159static vint32 global_init_count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000160#endif
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000161
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000162static xmlRMutexPtr xmlLibraryLock = NULL;
163
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000164#ifdef LIBXML_THREAD_ENABLED
Daniel Veillarde28313b2001-12-06 14:08:31 +0000165static void xmlOnceInit(void);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000166#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000167
168/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000169 * xmlNewMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000170 *
171 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
172 * synchronizing access to data.
173 *
174 * Returns a new simple mutex pointer or NULL in case of error
175 */
176xmlMutexPtr
177xmlNewMutex(void)
178{
179 xmlMutexPtr tok;
180
181 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
182 return (NULL);
183#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000184 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000185 pthread_mutex_init(&tok->lock, NULL);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000186#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000187 tok->mutex = CreateMutex(NULL, FALSE, NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000188#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000189 if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
190 free(tok);
191 return NULL;
192 }
193 tok->tid = -1;
Daniel Veillardb8478642001-10-12 17:29:10 +0000194#endif
195 return (tok);
196}
197
198/**
199 * xmlFreeMutex:
200 * @tok: the simple mutex
201 *
202 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
203 * struct.
204 */
205void
206xmlFreeMutex(xmlMutexPtr tok)
207{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000208 if (tok == NULL)
209 return;
Daniel Veillarddf101d82003-07-08 14:03:36 +0000210
Daniel Veillardb8478642001-10-12 17:29:10 +0000211#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000212 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000213 pthread_mutex_destroy(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000214#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000215 CloseHandle(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000216#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000217 delete_sem(tok->sem);
Daniel Veillardb8478642001-10-12 17:29:10 +0000218#endif
219 free(tok);
220}
221
222/**
223 * xmlMutexLock:
224 * @tok: the simple mutex
225 *
226 * xmlMutexLock() is used to lock a libxml2 token.
227 */
228void
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000229xmlMutexLock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000230{
Daniel Veillard70bcb0e2003-08-08 14:00:28 +0000231 if (tok == NULL)
232 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000233#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000234 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000235 pthread_mutex_lock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000236#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000237 WaitForSingleObject(tok->mutex, INFINITE);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000238#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000239 if (acquire_sem(tok->sem) != B_NO_ERROR) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000240#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000241 xmlGenericError(xmlGenericErrorContext,
242 "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
Daniel Veillard82cb3192003-10-29 13:39:15 +0000243#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000244 }
245 tok->tid = find_thread(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000246#endif
247
248}
249
250/**
251 * xmlMutexUnlock:
252 * @tok: the simple mutex
253 *
254 * xmlMutexUnlock() is used to unlock a libxml2 token.
255 */
256void
Daniel Veillard5805be22003-08-28 08:03:23 +0000257xmlMutexUnlock(xmlMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000258{
Daniel Veillard5805be22003-08-28 08:03:23 +0000259 if (tok == NULL)
260 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000261#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000262 if (libxml_is_threaded != 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000263 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000264#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000265 ReleaseMutex(tok->mutex);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000266#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000267 if (tok->tid == find_thread(NULL)) {
268 tok->tid = -1;
269 release_sem(tok->sem);
270 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000271#endif
272}
273
274/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000275 * xmlNewRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000276 *
277 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
278 * synchronizing access to data. token_r is a re-entrant lock and thus useful
279 * for synchronizing access to data structures that may be manipulated in a
280 * recursive fashion.
281 *
282 * Returns the new reentrant mutex pointer or NULL in case of error
283 */
284xmlRMutexPtr
285xmlNewRMutex(void)
286{
287 xmlRMutexPtr tok;
288
289 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
290 return (NULL);
291#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000292 if (libxml_is_threaded != 0) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000293 pthread_mutex_init(&tok->lock, NULL);
294 tok->held = 0;
295 tok->waiters = 0;
296 pthread_cond_init(&tok->cv, NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000297 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000298#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000299 InitializeCriticalSection(&tok->cs);
300 tok->count = 0;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000301#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000302 if ((tok->lock = xmlNewMutex()) == NULL) {
303 free(tok);
304 return NULL;
305 }
306 tok->count = 0;
Daniel Veillardb8478642001-10-12 17:29:10 +0000307#endif
308 return (tok);
309}
310
311/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000312 * xmlFreeRMutex:
Daniel Veillardb8478642001-10-12 17:29:10 +0000313 * @tok: the reentrant mutex
314 *
315 * xmlRFreeMutex() is used to reclaim resources associated with a
316 * reentrant mutex.
317 */
318void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000319xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000320{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000321 if (tok == NULL)
322 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000323#ifdef HAVE_PTHREAD_H
Daniel Veillarda8b54132006-06-29 11:50:18 +0000324 if (libxml_is_threaded != 0) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000325 pthread_mutex_destroy(&tok->lock);
326 pthread_cond_destroy(&tok->cv);
Daniel Veillarda8b54132006-06-29 11:50:18 +0000327 }
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000328#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000329 DeleteCriticalSection(&tok->cs);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000330#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000331 xmlFreeMutex(tok->lock);
Daniel Veillardb8478642001-10-12 17:29:10 +0000332#endif
333 free(tok);
334}
335
336/**
337 * xmlRMutexLock:
338 * @tok: the reentrant mutex
339 *
340 * xmlRMutexLock() is used to lock a libxml2 token_r.
341 */
342void
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000343xmlRMutexLock(xmlRMutexPtr tok)
Daniel Veillardb8478642001-10-12 17:29:10 +0000344{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000345 if (tok == NULL)
346 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000347#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000348 if (libxml_is_threaded == 0)
349 return;
350
Daniel Veillardb8478642001-10-12 17:29:10 +0000351 pthread_mutex_lock(&tok->lock);
352 if (tok->held) {
353 if (pthread_equal(tok->tid, pthread_self())) {
354 tok->held++;
355 pthread_mutex_unlock(&tok->lock);
356 return;
357 } else {
358 tok->waiters++;
359 while (tok->held)
360 pthread_cond_wait(&tok->cv, &tok->lock);
361 tok->waiters--;
362 }
363 }
364 tok->tid = pthread_self();
365 tok->held = 1;
366 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000367#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000368 EnterCriticalSection(&tok->cs);
Daniel Veillard8854e462014-10-13 15:03:58 +0800369 tok->count++;
Daniel Veillard82cb3192003-10-29 13:39:15 +0000370#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000371 if (tok->lock->tid == find_thread(NULL)) {
372 tok->count++;
373 return;
374 } else {
375 xmlMutexLock(tok->lock);
376 tok->count = 1;
377 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000378#endif
379}
380
381/**
382 * xmlRMutexUnlock:
383 * @tok: the reentrant mutex
384 *
385 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
386 */
387void
Daniel Veillard0ba59232002-02-10 13:20:39 +0000388xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Daniel Veillardb8478642001-10-12 17:29:10 +0000389{
Daniel Veillard5f1e1f82003-09-11 23:35:09 +0000390 if (tok == NULL)
391 return;
Daniel Veillardb8478642001-10-12 17:29:10 +0000392#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000393 if (libxml_is_threaded == 0)
394 return;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000395
Daniel Veillardb8478642001-10-12 17:29:10 +0000396 pthread_mutex_lock(&tok->lock);
397 tok->held--;
398 if (tok->held == 0) {
399 if (tok->waiters)
400 pthread_cond_signal(&tok->cv);
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200401 memset(&tok->tid, 0, sizeof(tok->tid));
Daniel Veillardb8478642001-10-12 17:29:10 +0000402 }
403 pthread_mutex_unlock(&tok->lock);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000404#elif defined HAVE_WIN32_THREADS
Daniel Veillard8854e462014-10-13 15:03:58 +0800405 if (tok->count > 0) {
Daniel Veillard8854e462014-10-13 15:03:58 +0800406 tok->count--;
Steve Nairn620a7062015-03-03 19:40:06 +0800407 LeaveCriticalSection(&tok->cs);
Daniel Veillard8854e462014-10-13 15:03:58 +0800408 }
Daniel Veillard82cb3192003-10-29 13:39:15 +0000409#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000410 if (tok->lock->tid == find_thread(NULL)) {
411 tok->count--;
412 if (tok->count == 0) {
413 xmlMutexUnlock(tok->lock);
414 }
415 return;
416 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000417#endif
418}
419
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000420/**
421 * xmlGlobalInitMutexLock
422 *
423 * Makes sure that the global initialization mutex is initialized and
424 * locks it.
425 */
426void
427__xmlGlobalInitMutexLock(void)
428{
429 /* Make sure the global init lock is initialized and then lock it. */
430#ifdef HAVE_PTHREAD_H
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000431 /* The mutex is statically initialized, so we just lock it. */
Nick Wellnhofer2677fbf2017-11-27 14:20:31 +0100432#ifdef XML_PTHREAD_WEAK
433 if (pthread_mutex_lock == NULL)
434 return;
435#endif /* XML_PTHREAD_WEAK */
436 pthread_mutex_lock(&global_init_lock);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000437#elif defined HAVE_WIN32_THREADS
438 LPCRITICAL_SECTION cs;
439
440 /* Create a new critical section */
441 if (global_init_lock == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000442 cs = malloc(sizeof(CRITICAL_SECTION));
443 if (cs == NULL) {
444 xmlGenericError(xmlGenericErrorContext,
445 "xmlGlobalInitMutexLock: out of memory\n");
446 return;
447 }
448 InitializeCriticalSection(cs);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000449
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000450 /* Swap it into the global_init_lock */
Rob Richardse967f0b2007-06-08 19:36:04 +0000451#ifdef InterlockedCompareExchangePointer
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200452 InterlockedCompareExchangePointer((void **) &global_init_lock,
453 cs, NULL);
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000454#else /* Use older void* version */
455 InterlockedCompareExchange((void **) &global_init_lock,
456 (void *) cs, NULL);
Rob Richardse967f0b2007-06-08 19:36:04 +0000457#endif /* InterlockedCompareExchangePointer */
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000458
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000459 /* If another thread successfully recorded its critical
460 * section in the global_init_lock then discard the one
461 * allocated by this thread. */
462 if (global_init_lock != cs) {
463 DeleteCriticalSection(cs);
464 free(cs);
465 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000466 }
467
468 /* Lock the chosen critical section */
469 EnterCriticalSection(global_init_lock);
470#elif defined HAVE_BEOS_THREADS
471 int32 sem;
472
473 /* Allocate a new semaphore */
474 sem = create_sem(1, "xmlGlobalinitMutex");
475
476 while (global_init_lock == -1) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000477 if (atomic_add(&global_init_count, 1) == 0) {
478 global_init_lock = sem;
479 } else {
480 snooze(1);
481 atomic_add(&global_init_count, -1);
482 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000483 }
484
485 /* If another thread successfully recorded its critical
486 * section in the global_init_lock then discard the one
487 * allocated by this thread. */
488 if (global_init_lock != sem)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000489 delete_sem(sem);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000490
491 /* Acquire the chosen semaphore */
492 if (acquire_sem(global_init_lock) != B_NO_ERROR) {
493#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000494 xmlGenericError(xmlGenericErrorContext,
495 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000496#endif
497 }
498#endif
499}
500
501void
502__xmlGlobalInitMutexUnlock(void)
503{
504#ifdef HAVE_PTHREAD_H
Nick Wellnhofer2677fbf2017-11-27 14:20:31 +0100505#ifdef XML_PTHREAD_WEAK
506 if (pthread_mutex_unlock == NULL)
507 return;
508#endif /* XML_PTHREAD_WEAK */
509 pthread_mutex_unlock(&global_init_lock);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000510#elif defined HAVE_WIN32_THREADS
Daniel Veillard14d465d2008-03-24 11:12:55 +0000511 if (global_init_lock != NULL) {
512 LeaveCriticalSection(global_init_lock);
513 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000514#elif defined HAVE_BEOS_THREADS
515 release_sem(global_init_lock);
516#endif
517}
518
Rob Richards91eb5602007-11-16 10:54:59 +0000519/**
520 * xmlGlobalInitMutexDestroy
521 *
522 * Makes sure that the global initialization mutex is destroyed before
523 * application termination.
524 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000525void
526__xmlGlobalInitMutexDestroy(void)
Rob Richards91eb5602007-11-16 10:54:59 +0000527{
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200528#ifdef HAVE_PTHREAD_H
529#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000530 if (global_init_lock != NULL) {
531 DeleteCriticalSection(global_init_lock);
532 free(global_init_lock);
533 global_init_lock = NULL;
Rob Richards91eb5602007-11-16 10:54:59 +0000534 }
535#endif
536}
537
Daniel Veillardb8478642001-10-12 17:29:10 +0000538/************************************************************************
539 * *
540 * Per thread global state handling *
541 * *
542 ************************************************************************/
543
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000544#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000545#ifdef xmlLastError
546#undef xmlLastError
547#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000548
Daniel Veillardb8478642001-10-12 17:29:10 +0000549/**
550 * xmlFreeGlobalState:
551 * @state: a thread global state
552 *
553 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
554 * global state. It is is used here to reclaim memory resources.
555 */
556static void
557xmlFreeGlobalState(void *state)
558{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000559 xmlGlobalState *gs = (xmlGlobalState *) state;
560
561 /* free any memory allocated in the thread's xmlLastError */
562 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000563 free(state);
564}
565
566/**
567 * xmlNewGlobalState:
568 *
569 * xmlNewGlobalState() allocates a global state. This structure is used to
570 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000571 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000572 *
573 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
574 */
575static xmlGlobalStatePtr
576xmlNewGlobalState(void)
577{
578 xmlGlobalState *gs;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000579
Daniel Veillardb8478642001-10-12 17:29:10 +0000580 gs = malloc(sizeof(xmlGlobalState));
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000581 if (gs == NULL) {
582 xmlGenericError(xmlGenericErrorContext,
583 "xmlGetGlobalState: out of memory\n");
584 return (NULL);
585 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000586
William M. Brack8b2c7f12002-11-22 05:07:29 +0000587 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000588 xmlInitializeGlobalState(gs);
589 return (gs);
590}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000591#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000592
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200593#ifdef HAVE_PTHREAD_H
Eric Zurcher243b0342009-10-01 00:13:07 +0200594#elif defined HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000595#if !defined(HAVE_COMPILER_TLS)
596#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000597typedef struct _xmlGlobalStateCleanupHelperParams {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000598 HANDLE thread;
599 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000600} xmlGlobalStateCleanupHelperParams;
601
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000602static void XMLCDECL
603xmlGlobalStateCleanupHelper(void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000604{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000605 xmlGlobalStateCleanupHelperParams *params =
606 (xmlGlobalStateCleanupHelperParams *) p;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000607 WaitForSingleObject(params->thread, INFINITE);
608 CloseHandle(params->thread);
609 xmlFreeGlobalState(params->memory);
610 free(params);
611 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000612}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000613#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
614
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000615typedef struct _xmlGlobalStateCleanupHelperParams {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000616 void *memory;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000617 struct _xmlGlobalStateCleanupHelperParams *prev;
618 struct _xmlGlobalStateCleanupHelperParams *next;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000619} xmlGlobalStateCleanupHelperParams;
620
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000621static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000622static CRITICAL_SECTION cleanup_helpers_cs;
623
624#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
625#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000626#endif /* HAVE_WIN32_THREADS */
627
Daniel Veillard82cb3192003-10-29 13:39:15 +0000628#if defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000629
William M. Brackb1d53162003-11-18 06:54:40 +0000630/**
631 * xmlGlobalStateCleanup:
632 * @data: unused parameter
633 *
634 * Used for Beos only
635 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000636void
637xmlGlobalStateCleanup(void *data)
Daniel Veillard82cb3192003-10-29 13:39:15 +0000638{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000639 void *globalval = tls_get(globalkey);
640
641 if (globalval != NULL)
642 xmlFreeGlobalState(globalval);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000643}
644#endif
645
Daniel Veillard01c13b52002-12-10 15:19:08 +0000646/**
647 * xmlGetGlobalState:
648 *
649 * xmlGetGlobalState() is called to retrieve the global state for a thread.
650 *
651 * Returns the thread global state or NULL in case of error
652 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000653xmlGlobalStatePtr
654xmlGetGlobalState(void)
655{
656#ifdef HAVE_PTHREAD_H
657 xmlGlobalState *globalval;
658
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000659 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000660 return (NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000661
Daniel Veillarde28313b2001-12-06 14:08:31 +0000662 pthread_once(&once_control, xmlOnceInit);
663
Daniel Veillardb8478642001-10-12 17:29:10 +0000664 if ((globalval = (xmlGlobalState *)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000665 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000666 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000667 if (tsd == NULL)
668 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000669
670 pthread_setspecific(globalkey, tsd);
671 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000672 }
673 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000674#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000675#if defined(HAVE_COMPILER_TLS)
676 if (!tlstate_inited) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000677 tlstate_inited = 1;
678 xmlInitializeGlobalState(&tlstate);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000679 }
680 return &tlstate;
681#else /* HAVE_COMPILER_TLS */
682 xmlGlobalState *globalval;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000683 xmlGlobalStateCleanupHelperParams *p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000684
Daniel Veillard62121e22005-02-24 15:38:52 +0000685 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000686#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000687 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000688#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000689 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
690 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000691#endif
692 if (globalval == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000693 xmlGlobalState *tsd = xmlNewGlobalState();
694
695 if (tsd == NULL)
696 return(NULL);
697 p = (xmlGlobalStateCleanupHelperParams *)
698 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
699 if (p == NULL) {
700 xmlGenericError(xmlGenericErrorContext,
701 "xmlGetGlobalState: out of memory\n");
Daniel Veillardbf2ebff2009-01-18 14:57:04 +0000702 xmlFreeGlobalState(tsd);
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000703 return(NULL);
704 }
705 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000706#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000707 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
708 GetCurrentProcess(), &p->thread, 0, TRUE,
709 DUPLICATE_SAME_ACCESS);
710 TlsSetValue(globalkey, tsd);
711 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000712#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000713 EnterCriticalSection(&cleanup_helpers_cs);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000714 if (cleanup_helpers_head != NULL) {
715 cleanup_helpers_head->prev = p;
716 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000717 p->next = cleanup_helpers_head;
718 p->prev = NULL;
719 cleanup_helpers_head = p;
720 TlsSetValue(globalkey, p);
721 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000722#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000723
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000724 return (tsd);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000725 }
726 return (globalval);
727#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000728#elif defined HAVE_BEOS_THREADS
729 xmlGlobalState *globalval;
730
731 xmlOnceInit();
732
Daniel Veillard14d465d2008-03-24 11:12:55 +0000733 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000734 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000735 if (tsd == NULL)
736 return (NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000737
738 tls_set(globalkey, tsd);
739 on_exit_thread(xmlGlobalStateCleanup, NULL);
740 return (tsd);
741 }
742 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000743#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000744 return (NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000745#endif
746}
747
Daniel Veillardb8478642001-10-12 17:29:10 +0000748/************************************************************************
749 * *
750 * Library wide thread interfaces *
751 * *
752 ************************************************************************/
753
754/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000755 * xmlGetThreadId:
756 *
757 * xmlGetThreadId() find the current thread ID number
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200758 * Note that this is likely to be broken on some platforms using pthreads
759 * as the specification doesn't mandate pthread_t to be an integer type
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000760 *
761 * Returns the current thread ID number
762 */
763int
764xmlGetThreadId(void)
765{
766#ifdef HAVE_PTHREAD_H
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200767 pthread_t id;
768 int ret;
769
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000770 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000771 return (0);
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200772 id = pthread_self();
773 /* horrible but preserves compat, see warning above */
774 memcpy(&ret, &id, sizeof(ret));
775 return (ret);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000776#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000777 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000778#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000779 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000780#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000781 return ((int) 0);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000782#endif
783}
784
785/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000786 * xmlIsMainThread:
787 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000788 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000789 *
790 * Returns 1 if the current thread is the main thread, 0 otherwise
791 */
792int
793xmlIsMainThread(void)
794{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000795#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000796 if (libxml_is_threaded == -1)
797 xmlInitThreads();
798 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000799 return (1);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000800 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000801#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000802 xmlOnceInit();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000803#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000804 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000805#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000806
Daniel Veillard6f350292001-10-14 09:56:15 +0000807#ifdef DEBUG_THREADS
808 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
809#endif
810#ifdef HAVE_PTHREAD_H
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200811 return (pthread_equal(mainthread,pthread_self()));
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000812#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000813 return (mainthread == GetCurrentThreadId());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000814#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000815 return (mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000816#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000817 return (1);
Daniel Veillard6f350292001-10-14 09:56:15 +0000818#endif
819}
820
821/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000822 * xmlLockLibrary:
823 *
824 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
825 * library.
826 */
827void
828xmlLockLibrary(void)
829{
Daniel Veillard6f350292001-10-14 09:56:15 +0000830#ifdef DEBUG_THREADS
831 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
832#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000833 xmlRMutexLock(xmlLibraryLock);
834}
835
836/**
837 * xmlUnlockLibrary:
838 *
839 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
840 * library.
841 */
842void
843xmlUnlockLibrary(void)
844{
Daniel Veillard6f350292001-10-14 09:56:15 +0000845#ifdef DEBUG_THREADS
846 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
847#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000848 xmlRMutexUnlock(xmlLibraryLock);
849}
850
851/**
852 * xmlInitThreads:
853 *
854 * xmlInitThreads() is used to to initialize all the thread related
855 * data of the libxml2 library.
856 */
857void
858xmlInitThreads(void)
859{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000860#ifdef HAVE_PTHREAD_H
Nick Wellnhofer2677fbf2017-11-27 14:20:31 +0100861#ifdef XML_PTHREAD_WEAK
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000862 if (libxml_is_threaded == -1) {
863 if ((pthread_once != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000864 (pthread_getspecific != NULL) &&
865 (pthread_setspecific != NULL) &&
866 (pthread_key_create != NULL) &&
Daniel Veillardd4a3f242009-01-18 15:41:30 +0000867 (pthread_key_delete != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000868 (pthread_mutex_init != NULL) &&
869 (pthread_mutex_destroy != NULL) &&
870 (pthread_mutex_lock != NULL) &&
871 (pthread_mutex_unlock != NULL) &&
872 (pthread_cond_init != NULL) &&
Daniel Veillard2cba4152008-08-27 11:45:41 +0000873 (pthread_cond_destroy != NULL) &&
874 (pthread_cond_wait != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000875 (pthread_equal != NULL) &&
876 (pthread_self != NULL) &&
877 (pthread_cond_signal != NULL)) {
878 libxml_is_threaded = 1;
879
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000880/* fprintf(stderr, "Running multithreaded\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000881 } else {
882
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000883/* fprintf(stderr, "Running without multithread\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000884 libxml_is_threaded = 0;
885 }
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000886 }
Nick Wellnhofer2677fbf2017-11-27 14:20:31 +0100887#endif /* XML_PTHREAD_WEAK */
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200888#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
889 InitializeCriticalSection(&cleanup_helpers_cs);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000890#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000891}
892
893/**
894 * xmlCleanupThreads:
895 *
896 * xmlCleanupThreads() is used to to cleanup all the thread related
897 * data of the libxml2 library once processing has ended.
Daniel Veillard01101202009-02-21 09:22:04 +0000898 *
899 * WARNING: if your application is multithreaded or has plugin support
900 * calling this may crash the application if another thread or
901 * a plugin is still using libxml2. It's sometimes very hard to
902 * guess if libxml2 is in use in the application, some libraries
903 * or plugins may use it without notice. In case of doubt abstain
904 * from calling this function or do it just before calling exit()
905 * to avoid leak reports from valgrind !
Daniel Veillardb8478642001-10-12 17:29:10 +0000906 */
907void
908xmlCleanupThreads(void)
909{
Daniel Veillard6f350292001-10-14 09:56:15 +0000910#ifdef DEBUG_THREADS
911 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
912#endif
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200913#ifdef HAVE_PTHREAD_H
Nick Wellnhofer2677fbf2017-11-27 14:20:31 +0100914 if (libxml_is_threaded != 0)
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200915 pthread_key_delete(globalkey);
Friedrich Haubensak3f6cfbd2012-09-12 17:34:53 +0200916 once_control = once_control_init;
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200917#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000918 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000919 xmlGlobalStateCleanupHelperParams *p;
920
921 EnterCriticalSection(&cleanup_helpers_cs);
922 p = cleanup_helpers_head;
923 while (p != NULL) {
924 xmlGlobalStateCleanupHelperParams *temp = p;
925
926 p = p->next;
927 xmlFreeGlobalState(temp->memory);
928 free(temp);
929 }
930 cleanup_helpers_head = 0;
931 LeaveCriticalSection(&cleanup_helpers_cs);
932 TlsFree(globalkey);
933 globalkey = TLS_OUT_OF_INDEXES;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000934 }
935 DeleteCriticalSection(&cleanup_helpers_cs);
936#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000937}
Daniel Veillard6f350292001-10-14 09:56:15 +0000938
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000939#ifdef LIBXML_THREAD_ENABLED
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000940
Daniel Veillarde28313b2001-12-06 14:08:31 +0000941/**
942 * xmlOnceInit
943 *
944 * xmlOnceInit() is used to initialize the value of mainthread for use
945 * in other routines. This function should only be called using
946 * pthread_once() in association with the once_control variable to ensure
947 * that the function is only called once. See man pthread_once for more
948 * details.
949 */
950static void
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000951xmlOnceInit(void)
952{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000953#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000954 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000955 mainthread = pthread_self();
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800956 __xmlInitializeDict();
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200957#elif defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000958 if (!run_once.done) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000959 if (InterlockedIncrement(&run_once.control) == 1) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000960#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000961 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000962#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000963 mainthread = GetCurrentThreadId();
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800964 __xmlInitializeDict();
Daniel Veillard62121e22005-02-24 15:38:52 +0000965 run_once.done = 1;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000966 } else {
Daniel Veillard62121e22005-02-24 15:38:52 +0000967 /* Another thread is working; give up our slice and
968 * wait until they're done. */
969 while (!run_once.done)
970 Sleep(0);
971 }
972 }
Eric Zurcher243b0342009-10-01 00:13:07 +0200973#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000974 if (atomic_add(&run_once_init, 1) == 0) {
975 globalkey = tls_allocate();
976 tls_set(globalkey, NULL);
977 mainthread = find_thread(NULL);
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800978 __xmlInitializeDict();
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000979 } else
980 atomic_add(&run_once_init, -1);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000981#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000982}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000983#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000984
985/**
William M. Brack7a821652003-08-15 07:27:40 +0000986 * DllMain:
987 * @hinstDLL: handle to DLL instance
988 * @fdwReason: Reason code for entry
989 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000990 *
991 * Entry point for Windows library. It is being used to free thread-specific
992 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000993 *
994 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000995 */
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200996#ifdef HAVE_PTHREAD_H
997#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000998#if defined(LIBXML_STATIC_FOR_DLL)
J. Peter Mugaas882a1652017-10-21 14:04:20 +0200999int XMLCALL
1000xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
1001 ATTRIBUTE_UNUSED void *lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001002#else
J. Peter Mugaasf05af832017-10-21 14:09:16 +02001003/* declare to avoid "no previous prototype for 'DllMain'" warning */
1004/* Note that we do NOT want to include this function declaration in
1005 a public header because it's meant to be called by Windows itself,
1006 not a program that uses this library. This also has to be exported. */
1007
1008XMLPUBFUN BOOL WINAPI
1009DllMain (HINSTANCE hinstDLL,
1010 DWORD fdwReason,
1011 LPVOID lpvReserved);
1012
Daniel Veillardddbe38b2008-03-18 08:24:25 +00001013BOOL WINAPI
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +02001014DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
1015 ATTRIBUTE_UNUSED LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001016#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +00001017{
Daniel Veillardddbe38b2008-03-18 08:24:25 +00001018 switch (fdwReason) {
1019 case DLL_THREAD_DETACH:
1020 if (globalkey != TLS_OUT_OF_INDEXES) {
1021 xmlGlobalState *globalval = NULL;
1022 xmlGlobalStateCleanupHelperParams *p =
1023 (xmlGlobalStateCleanupHelperParams *)
1024 TlsGetValue(globalkey);
1025 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
1026 if (globalval) {
1027 xmlFreeGlobalState(globalval);
1028 TlsSetValue(globalkey, NULL);
1029 }
1030 if (p) {
1031 EnterCriticalSection(&cleanup_helpers_cs);
1032 if (p == cleanup_helpers_head)
1033 cleanup_helpers_head = p->next;
1034 else
1035 p->prev->next = p->next;
1036 if (p->next != NULL)
1037 p->next->prev = p->prev;
1038 LeaveCriticalSection(&cleanup_helpers_cs);
1039 free(p);
1040 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001041 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +00001042 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +00001043 }
1044 return TRUE;
1045}
1046#endif
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001047#define bottom_threads
1048#include "elfgcchack.h"