blob: bca49546d2d729405cd3dd53816fe68970c0ae69 [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;
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200142 LONG 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
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200442 InterlockedCompareExchangePointer((void **) &global_init_lock,
443 cs, NULL);
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000444#else /* Use older void* version */
445 InterlockedCompareExchange((void **) &global_init_lock,
446 (void *) cs, NULL);
Rob Richardse967f0b2007-06-08 19:36:04 +0000447#endif /* InterlockedCompareExchangePointer */
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000448
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000449 /* If another thread successfully recorded its critical
450 * section in the global_init_lock then discard the one
451 * allocated by this thread. */
452 if (global_init_lock != cs) {
453 DeleteCriticalSection(cs);
454 free(cs);
455 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000456 }
457
458 /* Lock the chosen critical section */
459 EnterCriticalSection(global_init_lock);
460#elif defined HAVE_BEOS_THREADS
461 int32 sem;
462
463 /* Allocate a new semaphore */
464 sem = create_sem(1, "xmlGlobalinitMutex");
465
466 while (global_init_lock == -1) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000467 if (atomic_add(&global_init_count, 1) == 0) {
468 global_init_lock = sem;
469 } else {
470 snooze(1);
471 atomic_add(&global_init_count, -1);
472 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000473 }
474
475 /* If another thread successfully recorded its critical
476 * section in the global_init_lock then discard the one
477 * allocated by this thread. */
478 if (global_init_lock != sem)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000479 delete_sem(sem);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000480
481 /* Acquire the chosen semaphore */
482 if (acquire_sem(global_init_lock) != B_NO_ERROR) {
483#ifdef DEBUG_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000484 xmlGenericError(xmlGenericErrorContext,
485 "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000486#endif
487 }
488#endif
489}
490
491void
492__xmlGlobalInitMutexUnlock(void)
493{
494#ifdef HAVE_PTHREAD_H
Daniel Richard G5706b6d2012-08-06 11:32:54 +0800495 if (pthread_mutex_unlock != NULL)
Mike Hommeye6f05092010-10-15 19:50:03 +0200496 pthread_mutex_unlock(&global_init_lock);
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000497#elif defined HAVE_WIN32_THREADS
Daniel Veillard14d465d2008-03-24 11:12:55 +0000498 if (global_init_lock != NULL) {
499 LeaveCriticalSection(global_init_lock);
500 }
Daniel Veillardfde5b0b2007-02-12 17:31:53 +0000501#elif defined HAVE_BEOS_THREADS
502 release_sem(global_init_lock);
503#endif
504}
505
Rob Richards91eb5602007-11-16 10:54:59 +0000506/**
507 * xmlGlobalInitMutexDestroy
508 *
509 * Makes sure that the global initialization mutex is destroyed before
510 * application termination.
511 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000512void
513__xmlGlobalInitMutexDestroy(void)
Rob Richards91eb5602007-11-16 10:54:59 +0000514{
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200515#ifdef HAVE_PTHREAD_H
516#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000517 if (global_init_lock != NULL) {
518 DeleteCriticalSection(global_init_lock);
519 free(global_init_lock);
520 global_init_lock = NULL;
Rob Richards91eb5602007-11-16 10:54:59 +0000521 }
522#endif
523}
524
Daniel Veillardb8478642001-10-12 17:29:10 +0000525/************************************************************************
526 * *
527 * Per thread global state handling *
528 * *
529 ************************************************************************/
530
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000531#ifdef LIBXML_THREAD_ENABLED
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000532#ifdef xmlLastError
533#undef xmlLastError
534#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000535
Daniel Veillardb8478642001-10-12 17:29:10 +0000536/**
537 * xmlFreeGlobalState:
538 * @state: a thread global state
539 *
540 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
541 * global state. It is is used here to reclaim memory resources.
542 */
543static void
544xmlFreeGlobalState(void *state)
545{
Daniel Veillard01c3bd52004-10-22 13:16:10 +0000546 xmlGlobalState *gs = (xmlGlobalState *) state;
547
548 /* free any memory allocated in the thread's xmlLastError */
549 xmlResetError(&(gs->xmlLastError));
Daniel Veillardb8478642001-10-12 17:29:10 +0000550 free(state);
551}
552
553/**
554 * xmlNewGlobalState:
555 *
556 * xmlNewGlobalState() allocates a global state. This structure is used to
557 * hold all data for use by a thread when supporting backwards compatibility
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000558 * of libxml2 to pre-thread-safe behaviour.
Daniel Veillardb8478642001-10-12 17:29:10 +0000559 *
560 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
561 */
562static xmlGlobalStatePtr
563xmlNewGlobalState(void)
564{
565 xmlGlobalState *gs;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000566
Daniel Veillardb8478642001-10-12 17:29:10 +0000567 gs = malloc(sizeof(xmlGlobalState));
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000568 if (gs == NULL) {
569 xmlGenericError(xmlGenericErrorContext,
570 "xmlGetGlobalState: out of memory\n");
571 return (NULL);
572 }
Daniel Veillardb8478642001-10-12 17:29:10 +0000573
William M. Brack8b2c7f12002-11-22 05:07:29 +0000574 memset(gs, 0, sizeof(xmlGlobalState));
Daniel Veillardb8478642001-10-12 17:29:10 +0000575 xmlInitializeGlobalState(gs);
576 return (gs);
577}
Daniel Veillard8bdb91d2001-10-31 17:52:43 +0000578#endif /* LIBXML_THREAD_ENABLED */
Daniel Veillardb8478642001-10-12 17:29:10 +0000579
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200580#ifdef HAVE_PTHREAD_H
Eric Zurcher243b0342009-10-01 00:13:07 +0200581#elif defined HAVE_WIN32_THREADS
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000582#if !defined(HAVE_COMPILER_TLS)
583#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000584typedef struct _xmlGlobalStateCleanupHelperParams {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000585 HANDLE thread;
586 void *memory;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000587} xmlGlobalStateCleanupHelperParams;
588
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000589static void XMLCDECL
590xmlGlobalStateCleanupHelper(void *p)
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000591{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000592 xmlGlobalStateCleanupHelperParams *params =
593 (xmlGlobalStateCleanupHelperParams *) p;
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000594 WaitForSingleObject(params->thread, INFINITE);
595 CloseHandle(params->thread);
596 xmlFreeGlobalState(params->memory);
597 free(params);
598 _endthread();
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000599}
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000600#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
601
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000602typedef struct _xmlGlobalStateCleanupHelperParams {
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000603 void *memory;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000604 struct _xmlGlobalStateCleanupHelperParams *prev;
605 struct _xmlGlobalStateCleanupHelperParams *next;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000606} xmlGlobalStateCleanupHelperParams;
607
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000608static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000609static CRITICAL_SECTION cleanup_helpers_cs;
610
611#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
612#endif /* HAVE_COMPILER_TLS */
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000613#endif /* HAVE_WIN32_THREADS */
614
Daniel Veillard82cb3192003-10-29 13:39:15 +0000615#if defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000616
William M. Brackb1d53162003-11-18 06:54:40 +0000617/**
618 * xmlGlobalStateCleanup:
619 * @data: unused parameter
620 *
621 * Used for Beos only
622 */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000623void
624xmlGlobalStateCleanup(void *data)
Daniel Veillard82cb3192003-10-29 13:39:15 +0000625{
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000626 void *globalval = tls_get(globalkey);
627
628 if (globalval != NULL)
629 xmlFreeGlobalState(globalval);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000630}
631#endif
632
Daniel Veillard01c13b52002-12-10 15:19:08 +0000633/**
634 * xmlGetGlobalState:
635 *
636 * xmlGetGlobalState() is called to retrieve the global state for a thread.
637 *
638 * Returns the thread global state or NULL in case of error
639 */
Daniel Veillardb8478642001-10-12 17:29:10 +0000640xmlGlobalStatePtr
641xmlGetGlobalState(void)
642{
643#ifdef HAVE_PTHREAD_H
644 xmlGlobalState *globalval;
645
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000646 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000647 return (NULL);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000648
Daniel Veillarde28313b2001-12-06 14:08:31 +0000649 pthread_once(&once_control, xmlOnceInit);
650
Daniel Veillardb8478642001-10-12 17:29:10 +0000651 if ((globalval = (xmlGlobalState *)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000652 pthread_getspecific(globalkey)) == NULL) {
Daniel Veillardb8478642001-10-12 17:29:10 +0000653 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000654 if (tsd == NULL)
655 return(NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000656
657 pthread_setspecific(globalkey, tsd);
658 return (tsd);
Daniel Veillard6f350292001-10-14 09:56:15 +0000659 }
660 return (globalval);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000661#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000662#if defined(HAVE_COMPILER_TLS)
663 if (!tlstate_inited) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000664 tlstate_inited = 1;
665 xmlInitializeGlobalState(&tlstate);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000666 }
667 return &tlstate;
668#else /* HAVE_COMPILER_TLS */
669 xmlGlobalState *globalval;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000670 xmlGlobalStateCleanupHelperParams *p;
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000671
Daniel Veillard62121e22005-02-24 15:38:52 +0000672 xmlOnceInit();
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000673#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000674 globalval = (xmlGlobalState *) TlsGetValue(globalkey);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000675#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000676 p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
677 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000678#endif
679 if (globalval == NULL) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000680 xmlGlobalState *tsd = xmlNewGlobalState();
681
682 if (tsd == NULL)
683 return(NULL);
684 p = (xmlGlobalStateCleanupHelperParams *)
685 malloc(sizeof(xmlGlobalStateCleanupHelperParams));
686 if (p == NULL) {
687 xmlGenericError(xmlGenericErrorContext,
688 "xmlGetGlobalState: out of memory\n");
Daniel Veillardbf2ebff2009-01-18 14:57:04 +0000689 xmlFreeGlobalState(tsd);
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000690 return(NULL);
691 }
692 p->memory = tsd;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000693#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000694 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
695 GetCurrentProcess(), &p->thread, 0, TRUE,
696 DUPLICATE_SAME_ACCESS);
697 TlsSetValue(globalkey, tsd);
698 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000699#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000700 EnterCriticalSection(&cleanup_helpers_cs);
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000701 if (cleanup_helpers_head != NULL) {
702 cleanup_helpers_head->prev = p;
703 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000704 p->next = cleanup_helpers_head;
705 p->prev = NULL;
706 cleanup_helpers_head = p;
707 TlsSetValue(globalkey, p);
708 LeaveCriticalSection(&cleanup_helpers_cs);
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000709#endif
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000710
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000711 return (tsd);
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000712 }
713 return (globalval);
714#endif /* HAVE_COMPILER_TLS */
Daniel Veillard82cb3192003-10-29 13:39:15 +0000715#elif defined HAVE_BEOS_THREADS
716 xmlGlobalState *globalval;
717
718 xmlOnceInit();
719
Daniel Veillard14d465d2008-03-24 11:12:55 +0000720 if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
Daniel Veillard82cb3192003-10-29 13:39:15 +0000721 xmlGlobalState *tsd = xmlNewGlobalState();
Daniel Veillard14d465d2008-03-24 11:12:55 +0000722 if (tsd == NULL)
723 return (NULL);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000724
725 tls_set(globalkey, tsd);
726 on_exit_thread(xmlGlobalStateCleanup, NULL);
727 return (tsd);
728 }
729 return (globalval);
Daniel Veillard6f350292001-10-14 09:56:15 +0000730#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000731 return (NULL);
Daniel Veillardb8478642001-10-12 17:29:10 +0000732#endif
733}
734
Daniel Veillardb8478642001-10-12 17:29:10 +0000735/************************************************************************
736 * *
737 * Library wide thread interfaces *
738 * *
739 ************************************************************************/
740
741/**
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000742 * xmlGetThreadId:
743 *
744 * xmlGetThreadId() find the current thread ID number
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200745 * Note that this is likely to be broken on some platforms using pthreads
746 * as the specification doesn't mandate pthread_t to be an integer type
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000747 *
748 * Returns the current thread ID number
749 */
750int
751xmlGetThreadId(void)
752{
753#ifdef HAVE_PTHREAD_H
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200754 pthread_t id;
755 int ret;
756
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000757 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000758 return (0);
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200759 id = pthread_self();
760 /* horrible but preserves compat, see warning above */
761 memcpy(&ret, &id, sizeof(ret));
762 return (ret);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000763#elif defined HAVE_WIN32_THREADS
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000764 return GetCurrentThreadId();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000765#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000766 return find_thread(NULL);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000767#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000768 return ((int) 0);
Daniel Veillard3c01b1d2001-10-17 15:58:35 +0000769#endif
770}
771
772/**
Daniel Veillard6f350292001-10-14 09:56:15 +0000773 * xmlIsMainThread:
774 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +0000775 * xmlIsMainThread() check whether the current thread is the main thread.
Daniel Veillard6f350292001-10-14 09:56:15 +0000776 *
777 * Returns 1 if the current thread is the main thread, 0 otherwise
778 */
779int
780xmlIsMainThread(void)
781{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000782#ifdef HAVE_PTHREAD_H
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000783 if (libxml_is_threaded == -1)
784 xmlInitThreads();
785 if (libxml_is_threaded == 0)
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000786 return (1);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000787 pthread_once(&once_control, xmlOnceInit);
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000788#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000789 xmlOnceInit();
Daniel Veillard82cb3192003-10-29 13:39:15 +0000790#elif defined HAVE_BEOS_THREADS
Daniel Veillard62121e22005-02-24 15:38:52 +0000791 xmlOnceInit();
Daniel Veillarde28313b2001-12-06 14:08:31 +0000792#endif
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000793
Daniel Veillard6f350292001-10-14 09:56:15 +0000794#ifdef DEBUG_THREADS
795 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
796#endif
797#ifdef HAVE_PTHREAD_H
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200798 return (pthread_equal(mainthread,pthread_self()));
Daniel Veillarddb0eb8d2002-01-13 13:35:00 +0000799#elif defined HAVE_WIN32_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000800 return (mainthread == GetCurrentThreadId());
Daniel Veillard82cb3192003-10-29 13:39:15 +0000801#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000802 return (mainthread == find_thread(NULL));
Daniel Veillard6f350292001-10-14 09:56:15 +0000803#else
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000804 return (1);
Daniel Veillard6f350292001-10-14 09:56:15 +0000805#endif
806}
807
808/**
Daniel Veillardb8478642001-10-12 17:29:10 +0000809 * xmlLockLibrary:
810 *
811 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
812 * library.
813 */
814void
815xmlLockLibrary(void)
816{
Daniel Veillard6f350292001-10-14 09:56:15 +0000817#ifdef DEBUG_THREADS
818 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
819#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000820 xmlRMutexLock(xmlLibraryLock);
821}
822
823/**
824 * xmlUnlockLibrary:
825 *
826 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
827 * library.
828 */
829void
830xmlUnlockLibrary(void)
831{
Daniel Veillard6f350292001-10-14 09:56:15 +0000832#ifdef DEBUG_THREADS
833 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
834#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000835 xmlRMutexUnlock(xmlLibraryLock);
836}
837
838/**
839 * xmlInitThreads:
840 *
841 * xmlInitThreads() is used to to initialize all the thread related
842 * data of the libxml2 library.
843 */
844void
845xmlInitThreads(void)
846{
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000847#ifdef HAVE_PTHREAD_H
848 if (libxml_is_threaded == -1) {
849 if ((pthread_once != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000850 (pthread_getspecific != NULL) &&
851 (pthread_setspecific != NULL) &&
852 (pthread_key_create != NULL) &&
Daniel Veillardd4a3f242009-01-18 15:41:30 +0000853 (pthread_key_delete != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000854 (pthread_mutex_init != NULL) &&
855 (pthread_mutex_destroy != NULL) &&
856 (pthread_mutex_lock != NULL) &&
857 (pthread_mutex_unlock != NULL) &&
858 (pthread_cond_init != NULL) &&
Daniel Veillard2cba4152008-08-27 11:45:41 +0000859 (pthread_cond_destroy != NULL) &&
860 (pthread_cond_wait != NULL) &&
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000861 (pthread_equal != NULL) &&
862 (pthread_self != NULL) &&
863 (pthread_cond_signal != NULL)) {
864 libxml_is_threaded = 1;
865
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000866/* fprintf(stderr, "Running multithreaded\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000867 } else {
868
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000869/* fprintf(stderr, "Running without multithread\n"); */
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000870 libxml_is_threaded = 0;
871 }
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000872 }
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200873#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
874 InitializeCriticalSection(&cleanup_helpers_cs);
Daniel Veillarddbfe05a2005-05-04 09:18:00 +0000875#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000876}
877
878/**
879 * xmlCleanupThreads:
880 *
881 * xmlCleanupThreads() is used to to cleanup all the thread related
882 * data of the libxml2 library once processing has ended.
Daniel Veillard01101202009-02-21 09:22:04 +0000883 *
884 * WARNING: if your application is multithreaded or has plugin support
885 * calling this may crash the application if another thread or
886 * a plugin is still using libxml2. It's sometimes very hard to
887 * guess if libxml2 is in use in the application, some libraries
888 * or plugins may use it without notice. In case of doubt abstain
889 * from calling this function or do it just before calling exit()
890 * to avoid leak reports from valgrind !
Daniel Veillardb8478642001-10-12 17:29:10 +0000891 */
892void
893xmlCleanupThreads(void)
894{
Daniel Veillard6f350292001-10-14 09:56:15 +0000895#ifdef DEBUG_THREADS
896 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
897#endif
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200898#ifdef HAVE_PTHREAD_H
899 if ((libxml_is_threaded) && (pthread_key_delete != NULL))
900 pthread_key_delete(globalkey);
Friedrich Haubensak3f6cfbd2012-09-12 17:34:53 +0200901 once_control = once_control_init;
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200902#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000903 if (globalkey != TLS_OUT_OF_INDEXES) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000904 xmlGlobalStateCleanupHelperParams *p;
905
906 EnterCriticalSection(&cleanup_helpers_cs);
907 p = cleanup_helpers_head;
908 while (p != NULL) {
909 xmlGlobalStateCleanupHelperParams *temp = p;
910
911 p = p->next;
912 xmlFreeGlobalState(temp->memory);
913 free(temp);
914 }
915 cleanup_helpers_head = 0;
916 LeaveCriticalSection(&cleanup_helpers_cs);
917 TlsFree(globalkey);
918 globalkey = TLS_OUT_OF_INDEXES;
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000919 }
920 DeleteCriticalSection(&cleanup_helpers_cs);
921#endif
Daniel Veillarde28313b2001-12-06 14:08:31 +0000922}
Daniel Veillard6f350292001-10-14 09:56:15 +0000923
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000924#ifdef LIBXML_THREAD_ENABLED
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000925
Daniel Veillarde28313b2001-12-06 14:08:31 +0000926/**
927 * xmlOnceInit
928 *
929 * xmlOnceInit() is used to initialize the value of mainthread for use
930 * in other routines. This function should only be called using
931 * pthread_once() in association with the once_control variable to ensure
932 * that the function is only called once. See man pthread_once for more
933 * details.
934 */
935static void
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000936xmlOnceInit(void)
937{
Daniel Veillarde28313b2001-12-06 14:08:31 +0000938#ifdef HAVE_PTHREAD_H
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000939 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
Daniel Veillarde28313b2001-12-06 14:08:31 +0000940 mainthread = pthread_self();
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800941 __xmlInitializeDict();
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200942#elif defined(HAVE_WIN32_THREADS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000943 if (!run_once.done) {
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000944 if (InterlockedIncrement(&run_once.control) == 1) {
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000945#if !defined(HAVE_COMPILER_TLS)
Daniel Veillard62121e22005-02-24 15:38:52 +0000946 globalkey = TlsAlloc();
Igor Zlatkovicf2160a02002-10-31 15:58:42 +0000947#endif
Daniel Veillard62121e22005-02-24 15:38:52 +0000948 mainthread = GetCurrentThreadId();
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800949 __xmlInitializeDict();
Daniel Veillard62121e22005-02-24 15:38:52 +0000950 run_once.done = 1;
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000951 } else {
Daniel Veillard62121e22005-02-24 15:38:52 +0000952 /* Another thread is working; give up our slice and
953 * wait until they're done. */
954 while (!run_once.done)
955 Sleep(0);
956 }
957 }
Eric Zurcher243b0342009-10-01 00:13:07 +0200958#elif defined HAVE_BEOS_THREADS
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000959 if (atomic_add(&run_once_init, 1) == 0) {
960 globalkey = tls_allocate();
961 tls_set(globalkey, NULL);
962 mainthread = find_thread(NULL);
Daniel Veillard5fe9e9e2013-04-05 23:10:41 +0800963 __xmlInitializeDict();
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000964 } else
965 atomic_add(&run_once_init, -1);
Daniel Veillard82cb3192003-10-29 13:39:15 +0000966#endif
Daniel Veillardb8478642001-10-12 17:29:10 +0000967}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000968#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000969
970/**
William M. Brack7a821652003-08-15 07:27:40 +0000971 * DllMain:
972 * @hinstDLL: handle to DLL instance
973 * @fdwReason: Reason code for entry
974 * @lpvReserved: generic pointer (depends upon reason code)
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000975 *
976 * Entry point for Windows library. It is being used to free thread-specific
977 * storage.
William M. Brack7a821652003-08-15 07:27:40 +0000978 *
979 * Returns TRUE always
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +0000980 */
Daniel Veillardd87c5d12009-09-10 17:46:07 +0200981#ifdef HAVE_PTHREAD_H
982#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000983#if defined(LIBXML_STATIC_FOR_DLL)
J. Peter Mugaas882a1652017-10-21 14:04:20 +0200984int XMLCALL
985xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
986 ATTRIBUTE_UNUSED void *lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +0000987#else
J. Peter Mugaasf05af832017-10-21 14:09:16 +0200988/* declare to avoid "no previous prototype for 'DllMain'" warning */
989/* Note that we do NOT want to include this function declaration in
990 a public header because it's meant to be called by Windows itself,
991 not a program that uses this library. This also has to be exported. */
992
993XMLPUBFUN BOOL WINAPI
994DllMain (HINSTANCE hinstDLL,
995 DWORD fdwReason,
996 LPVOID lpvReserved);
997
Daniel Veillardddbe38b2008-03-18 08:24:25 +0000998BOOL WINAPI
Nick Wellnhofer6472dfe2017-10-09 16:50:57 +0200999DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
1000 ATTRIBUTE_UNUSED LPVOID lpvReserved)
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001001#endif
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +00001002{
Daniel Veillardddbe38b2008-03-18 08:24:25 +00001003 switch (fdwReason) {
1004 case DLL_THREAD_DETACH:
1005 if (globalkey != TLS_OUT_OF_INDEXES) {
1006 xmlGlobalState *globalval = NULL;
1007 xmlGlobalStateCleanupHelperParams *p =
1008 (xmlGlobalStateCleanupHelperParams *)
1009 TlsGetValue(globalkey);
1010 globalval = (xmlGlobalState *) (p ? p->memory : NULL);
1011 if (globalval) {
1012 xmlFreeGlobalState(globalval);
1013 TlsSetValue(globalkey, NULL);
1014 }
1015 if (p) {
1016 EnterCriticalSection(&cleanup_helpers_cs);
1017 if (p == cleanup_helpers_head)
1018 cleanup_helpers_head = p->next;
1019 else
1020 p->prev->next = p->next;
1021 if (p->next != NULL)
1022 p->next->prev = p->prev;
1023 LeaveCriticalSection(&cleanup_helpers_cs);
1024 free(p);
1025 }
Daniel Veillardd96f6d32003-10-07 21:25:12 +00001026 }
Daniel Veillardddbe38b2008-03-18 08:24:25 +00001027 break;
Igor Zlatkovicd58a42d2003-05-17 10:55:15 +00001028 }
1029 return TRUE;
1030}
1031#endif
Daniel Veillard5d4644e2005-04-01 13:11:58 +00001032#define bottom_threads
1033#include "elfgcchack.h"