ReactOS 0.4.16-dev-2206-gc56950d
threads.c
Go to the documentation of this file.
1
10#define IN_LIBXML
11#include "libxml.h"
12
13#include <string.h>
14#include <stdlib.h>
15
16#include <libxml/threads.h>
17#include <libxml/parser.h>
18#ifdef LIBXML_CATALOG_ENABLED
19#include <libxml/catalog.h>
20#endif
21#ifdef LIBXML_SCHEMAS_ENABLED
23#include <libxml/relaxng.h>
24#endif
25
26#if defined(SOLARIS)
27#include <note.h>
28#endif
29
30#include "private/dict.h"
31#include "private/enc.h"
32#include "private/globals.h"
33#include "private/memory.h"
34#include "private/threads.h"
35#include "private/xpath.h"
36
37#if defined(HAVE_POSIX_THREADS) && \
38 defined(__GLIBC__) && \
39 __GLIBC__ * 100 + __GLIBC_MINOR__ >= 234
40
41/*
42 * The modern way available since glibc 2.32.
43 *
44 * The check above is for glibc 2.34 which merged the pthread symbols into
45 * libc. Since we still allow linking without pthread symbols (see below),
46 * this only works if pthread symbols are guaranteed to be available.
47 */
48
49#include <sys/single_threaded.h>
50
51#define XML_IS_THREADED() (!__libc_single_threaded)
52#define XML_IS_NEVER_THREADED() 0
53
54#elif defined(HAVE_POSIX_THREADS) && \
55 defined(__GLIBC__) && \
56 defined(__GNUC__)
57
58/*
59 * The traditional way to check for single-threaded applications with
60 * glibc was to check whether the separate libpthread library is
61 * linked in. This works by not linking libxml2 with libpthread (see
62 * BASE_THREAD_LIBS in configure.ac and Makefile.am) and declaring
63 * pthread functions as weak symbols.
64 *
65 * In glibc 2.34, the pthread symbols were moved from libpthread to libc,
66 * so this doesn't work anymore.
67 *
68 * At some point, this legacy code and the BASE_THREAD_LIBS hack in
69 * configure.ac can probably be removed.
70 */
71
72#pragma weak pthread_mutex_init
73#pragma weak pthread_mutex_destroy
74#pragma weak pthread_mutex_lock
75#pragma weak pthread_mutex_unlock
76#pragma weak pthread_cond_init
77#pragma weak pthread_cond_destroy
78#pragma weak pthread_cond_wait
79#pragma weak pthread_equal
80#pragma weak pthread_self
81#pragma weak pthread_cond_signal
82
83#define XML_PTHREAD_WEAK
84#define XML_IS_THREADED() libxml_is_threaded
85#define XML_IS_NEVER_THREADED() (!libxml_is_threaded)
86
87static int libxml_is_threaded = -1;
88
89#else /* other POSIX platforms */
90
91#define XML_IS_THREADED() 1
92#define XML_IS_NEVER_THREADED() 0
93
94#endif
95
96/*
97 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
98 * to avoid some craziness since xmlMalloc/xmlFree may actually
99 * be hosted on allocated blocks needing them for the allocation ...
100 */
101
102/*
103 * xmlRMutex are reentrant mutual exception locks
104 */
106#ifdef HAVE_POSIX_THREADS
107 pthread_mutex_t lock;
108 unsigned int held;
109 unsigned int waiters;
110 pthread_t tid;
111 pthread_cond_t cv;
112#elif defined HAVE_WIN32_THREADS
114#else
115 int empty;
116#endif
117};
118
120
127void
129{
130#ifdef HAVE_POSIX_THREADS
131 if (XML_IS_NEVER_THREADED() == 0)
132 pthread_mutex_init(&mutex->lock, NULL);
133#elif defined HAVE_WIN32_THREADS
135#else
136 (void) mutex;
137#endif
138}
139
150{
151 xmlMutexPtr tok;
152
153 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
154 return (NULL);
155 xmlInitMutex(tok);
156 return (tok);
157}
158
165void
167{
168#ifdef HAVE_POSIX_THREADS
169 if (XML_IS_NEVER_THREADED() == 0)
170 pthread_mutex_destroy(&mutex->lock);
171#elif defined HAVE_WIN32_THREADS
173#else
174 (void) mutex;
175#endif
176}
177
184void
186{
187 if (tok == NULL)
188 return;
189
190 xmlCleanupMutex(tok);
191 free(tok);
192}
193
200void
202{
203 if (tok == NULL)
204 return;
205#ifdef HAVE_POSIX_THREADS
206 /*
207 * This assumes that __libc_single_threaded won't change while the
208 * lock is held.
209 */
210 if (XML_IS_THREADED() != 0)
211 pthread_mutex_lock(&tok->lock);
212#elif defined HAVE_WIN32_THREADS
213 EnterCriticalSection(&tok->cs);
214#endif
215
216}
217
224void
226{
227 if (tok == NULL)
228 return;
229#ifdef HAVE_POSIX_THREADS
230 if (XML_IS_THREADED() != 0)
231 pthread_mutex_unlock(&tok->lock);
232#elif defined HAVE_WIN32_THREADS
233 LeaveCriticalSection(&tok->cs);
234#endif
235}
236
249{
250 xmlRMutexPtr tok;
251
252 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
253 return (NULL);
254#ifdef HAVE_POSIX_THREADS
255 if (XML_IS_NEVER_THREADED() == 0) {
256 pthread_mutex_init(&tok->lock, NULL);
257 tok->held = 0;
258 tok->waiters = 0;
259 pthread_cond_init(&tok->cv, NULL);
260 }
261#elif defined HAVE_WIN32_THREADS
263#endif
264 return (tok);
265}
266
274void
276{
277 if (tok == NULL)
278 return;
279#ifdef HAVE_POSIX_THREADS
280 if (XML_IS_NEVER_THREADED() == 0) {
281 pthread_mutex_destroy(&tok->lock);
282 pthread_cond_destroy(&tok->cv);
283 }
284#elif defined HAVE_WIN32_THREADS
285 DeleteCriticalSection(&tok->cs);
286#endif
287 free(tok);
288}
289
296void
298{
299 if (tok == NULL)
300 return;
301#ifdef HAVE_POSIX_THREADS
302 if (XML_IS_THREADED() == 0)
303 return;
304
305 pthread_mutex_lock(&tok->lock);
306 if (tok->held) {
307 if (pthread_equal(tok->tid, pthread_self())) {
308 tok->held++;
309 pthread_mutex_unlock(&tok->lock);
310 return;
311 } else {
312 tok->waiters++;
313 while (tok->held)
314 pthread_cond_wait(&tok->cv, &tok->lock);
315 tok->waiters--;
316 }
317 }
318 tok->tid = pthread_self();
319 tok->held = 1;
320 pthread_mutex_unlock(&tok->lock);
321#elif defined HAVE_WIN32_THREADS
322 EnterCriticalSection(&tok->cs);
323#endif
324}
325
332void
334{
335 if (tok == NULL)
336 return;
337#ifdef HAVE_POSIX_THREADS
338 if (XML_IS_THREADED() == 0)
339 return;
340
341 pthread_mutex_lock(&tok->lock);
342 tok->held--;
343 if (tok->held == 0) {
344 if (tok->waiters)
345 pthread_cond_signal(&tok->cv);
346 memset(&tok->tid, 0, sizeof(tok->tid));
347 }
348 pthread_mutex_unlock(&tok->lock);
349#elif defined HAVE_WIN32_THREADS
350 LeaveCriticalSection(&tok->cs);
351#endif
352}
353
354/************************************************************************
355 * *
356 * Library wide thread interfaces *
357 * *
358 ************************************************************************/
359
371int
373{
374#ifdef HAVE_POSIX_THREADS
375 pthread_t id;
376 int ret;
377
378 if (XML_IS_THREADED() == 0)
379 return (0);
380 id = pthread_self();
381 /* horrible but preserves compat, see warning above */
382 memcpy(&ret, &id, sizeof(ret));
383 return (ret);
384#elif defined HAVE_WIN32_THREADS
385 return GetCurrentThreadId();
386#else
387 return ((int) 0);
388#endif
389}
390
397void
399{
401}
402
409void
411{
413}
414
420void
422{
424}
425
434void
436{
437}
438
439/************************************************************************
440 * *
441 * Library wide initialization *
442 * *
443 ************************************************************************/
444
445static int xmlParserInitialized = 0;
447
448
449#ifdef HAVE_POSIX_THREADS
450static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
451#elif defined HAVE_WIN32_THREADS
452static volatile LPCRITICAL_SECTION global_init_lock = NULL;
453#endif
454
461static void
463#ifdef HAVE_POSIX_THREADS
464
465#ifdef XML_PTHREAD_WEAK
466 /*
467 * This is somewhat unreliable since libpthread could be loaded
468 * later with dlopen() and threads could be created. But it's
469 * long-standing behavior and hard to work around.
470 */
471 if (libxml_is_threaded == -1)
472 libxml_is_threaded =
473 (pthread_mutex_init != NULL) &&
474 (pthread_mutex_destroy != NULL) &&
475 (pthread_mutex_lock != NULL) &&
476 (pthread_mutex_unlock != NULL) &&
477 (pthread_cond_init != NULL) &&
478 (pthread_cond_destroy != NULL) &&
479 (pthread_cond_wait != NULL) &&
480 /*
481 * pthread_equal can be inline, resuting in -Waddress warnings.
482 * Let's assume it's available if all the other functions are.
483 */
484 /* (pthread_equal != NULL) && */
485 (pthread_self != NULL) &&
486 (pthread_cond_signal != NULL);
487#endif
488
489 /* The mutex is statically initialized, so we just lock it. */
490 if (XML_IS_THREADED() != 0)
491 pthread_mutex_lock(&global_init_lock);
492
493#elif defined HAVE_WIN32_THREADS
494
496
497 /* Create a new critical section */
498 if (global_init_lock == NULL) {
499 cs = malloc(sizeof(CRITICAL_SECTION));
500 if (cs == NULL) {
502 "xmlGlobalInitMutexLock: out of memory\n");
503 return;
504 }
506
507 /* Swap it into the global_init_lock */
508#ifdef InterlockedCompareExchangePointer
509 InterlockedCompareExchangePointer((void **) &global_init_lock,
510 cs, NULL);
511#else /* Use older void* version */
512 InterlockedCompareExchange((void **) &global_init_lock,
513 (void *) cs, NULL);
514#endif /* InterlockedCompareExchangePointer */
515
516 /* If another thread successfully recorded its critical
517 * section in the global_init_lock then discard the one
518 * allocated by this thread. */
519 if (global_init_lock != cs) {
521 free(cs);
522 }
523 }
524
525 /* Lock the chosen critical section */
526 EnterCriticalSection(global_init_lock);
527
528#endif
529}
530
531static void
533#ifdef HAVE_POSIX_THREADS
534 if (XML_IS_THREADED() != 0)
535 pthread_mutex_unlock(&global_init_lock);
536#elif defined HAVE_WIN32_THREADS
537 if (global_init_lock != NULL)
538 LeaveCriticalSection(global_init_lock);
539#endif
540}
541
548static void
550#ifdef HAVE_POSIX_THREADS
551#elif defined HAVE_WIN32_THREADS
552 if (global_init_lock != NULL) {
553 DeleteCriticalSection(global_init_lock);
554 free(global_init_lock);
555 global_init_lock = NULL;
556 }
557#endif
558}
559
568void
570 /*
571 * Note that the initialization code must not make memory allocations.
572 */
573 if (xmlParserInitialized != 0)
574 return;
575
577
578 if (xmlParserInnerInitialized == 0) {
579#if defined(_WIN32) && \
580 !defined(LIBXML_THREAD_ALLOC_ENABLED) && \
581 (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
582 if (xmlFree == free)
584#endif
585
586 xmlInitMemoryInternal(); /* Should come second */
591#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
593#endif
594
596#ifdef LIBXML_OUTPUT_ENABLED
597 xmlRegisterDefaultOutputCallbacks();
598#endif /* LIBXML_OUTPUT_ENABLED */
599
601 }
602
604
606}
607
629void
632 return;
633
634 /* These functions can call xmlFree. */
635
637#ifdef LIBXML_CATALOG_ENABLED
638 xmlCatalogCleanup();
639#endif
640#ifdef LIBXML_SCHEMAS_ENABLED
641 xmlSchemaCleanupTypes();
642 xmlRelaxNGCleanupTypes();
643#endif
644
645 /* These functions should never call xmlFree. */
646
648#ifdef LIBXML_OUTPUT_ENABLED
649 xmlCleanupOutputCallbacks();
650#endif
651
655 /*
656 * Must come last. On Windows, xmlCleanupGlobalsInternal can call
657 * xmlFree which uses xmlMemMutex in debug mode.
658 */
660
662
665}
666
667#if defined(HAVE_ATTRIBUTE_DESTRUCTOR) && \
668 !defined(LIBXML_THREAD_ALLOC_ENABLED) && \
669 !defined(LIBXML_STATIC) && \
670 !defined(_WIN32)
671static void
672ATTRIBUTE_DESTRUCTOR
673xmlDestructor(void) {
674 /*
675 * Calling custom deallocation functions in a destructor can cause
676 * problems, for example with Nokogiri.
677 */
678 if (xmlFree == free)
680}
681#endif
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
int __cdecl atexit(void(__cdecl *)(void))
Definition: atonexit.c:97
return ret
Definition: mutex.c:146
void xmlInitEncodingInternal(void)
Definition: encoding.c:1470
void xmlCleanupCharEncodingHandlers(void)
Definition: encoding.c:1490
GLuint id
Definition: glext.h:5910
#define ATTRIBUTE_UNUSED
Definition: i386-dis.c:36
#define cs
Definition: i386-dis.c:442
static TfClientId tid
#define InterlockedCompareExchangePointer
Definition: interlocked.h:144
#define InterlockedCompareExchange
Definition: interlocked.h:119
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
CONDITION_VARIABLE cv
Definition: sync.c:1887
XML_HIDDEN void xmlInitXPathInternal(void)
ATTRIBUTE_NO_SANITIZE_INTEGER void xmlInitRandom(void)
Definition: dict.c:918
void xmlCleanupDictInternal(void)
Definition: dict.c:121
void xmlCleanupRandom(void)
Definition: dict.c:932
void xmlInitDictInternal(void)
Definition: dict.c:99
void * xmlGenericErrorContext
Definition: globals.c:410
xmlFreeFunc xmlFree
Definition: globals.c:184
xmlGenericErrorFunc xmlGenericError
Definition: globals.c:396
void xmlInitGlobalsInternal(void)
Definition: globals.c:571
void xmlCleanupGlobalsInternal(void)
Definition: globals.c:617
XML_HIDDEN void xmlCleanupMemoryInternal(void)
Definition: xmlmemory.c:880
XML_HIDDEN void xmlInitMemoryInternal(void)
Definition: xmlmemory.c:846
#define memset(x, y, z)
Definition: compat.h:39
int empty
Definition: threads.c:115
Definition: module.h:456
FAST_MUTEX lock
Definition: module.h:457
VOID WINAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection)
Definition: synch.c:751
rwlock_t lock
Definition: tcpcore.h:0
xmlMutexPtr xmlNewMutex(void)
Definition: threads.c:149
void xmlLockLibrary(void)
Definition: threads.c:398
static int xmlParserInitialized
Definition: threads.c:445
int xmlGetThreadId(void)
Definition: threads.c:372
static void xmlGlobalInitMutexUnlock(void)
Definition: threads.c:532
xmlRMutexPtr xmlNewRMutex(void)
Definition: threads.c:248
void xmlInitParser(void)
Definition: threads.c:569
void xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Definition: threads.c:275
#define XML_IS_THREADED()
Definition: threads.c:91
void xmlCleanupParser(void)
Definition: threads.c:630
void xmlInitThreads(void)
Definition: threads.c:421
void xmlUnlockLibrary(void)
Definition: threads.c:410
static void xmlGlobalInitMutexDestroy(void)
Definition: threads.c:549
void xmlCleanupMutex(xmlMutexPtr mutex)
Definition: threads.c:166
static int xmlParserInnerInitialized
Definition: threads.c:446
void xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
Definition: threads.c:333
void xmlInitMutex(xmlMutexPtr mutex)
Definition: threads.c:128
void xmlMutexLock(xmlMutexPtr tok)
Definition: threads.c:201
void xmlMutexUnlock(xmlMutexPtr tok)
Definition: threads.c:225
static void xmlGlobalInitMutexLock(void)
Definition: threads.c:462
static xmlRMutexPtr xmlLibraryLock
Definition: threads.c:119
void xmlRMutexLock(xmlRMutexPtr tok)
Definition: threads.c:297
#define XML_IS_NEVER_THREADED()
Definition: threads.c:92
void xmlFreeMutex(xmlMutexPtr tok)
Definition: threads.c:185
void xmlCleanupThreads(void)
Definition: threads.c:435
DWORD WINAPI GetCurrentThreadId(void)
Definition: thread.c:459
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
void WINAPI DeleteCriticalSection(PCRITICAL_SECTION)
XMLPUBFUN void xmlRegisterDefaultInputCallbacks(void)
XML_GLOBALS_IO XMLPUBFUN void xmlCleanupInputCallbacks(void)