Coverage Report

Created: 2023-06-07 06:14

/src/libxml2/threads.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * threads.c: set of generic threading related routines
3
 *
4
 * See Copyright for the status of this software.
5
 *
6
 * Gary Pennington <Gary.Pennington@uk.sun.com>
7
 * daniel@veillard.com
8
 */
9
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/globals.h>
18
19
#if defined(SOLARIS)
20
#include <note.h>
21
#endif
22
23
#include "private/dict.h"
24
#include "private/threads.h"
25
26
/* #define DEBUG_THREADS */
27
28
#if defined(HAVE_POSIX_THREADS) && \
29
    defined(__GLIBC__) && \
30
    __GLIBC__ * 100 + __GLIBC_MINOR__ >= 234
31
32
/*
33
 * The modern way available since glibc 2.32.
34
 *
35
 * The check above is for glibc 2.34 which merged the pthread symbols into
36
 * libc. Since we still allow linking without pthread symbols (see below),
37
 * this only works if pthread symbols are guaranteed to be available.
38
 */
39
40
#include <sys/single_threaded.h>
41
42
#define XML_IS_THREADED() (!__libc_single_threaded)
43
#define XML_IS_NEVER_THREADED() 0
44
45
#elif defined(HAVE_POSIX_THREADS) && \
46
      defined(__GLIBC__) && \
47
      defined(__GNUC__)
48
49
/*
50
 * The traditional way to check for single-threaded applications with
51
 * glibc was to check whether the separate libpthread library is
52
 * linked in. This works by not linking libxml2 with libpthread (see
53
 * BASE_THREAD_LIBS in configure.ac and Makefile.am) and declaring
54
 * pthread functions as weak symbols.
55
 *
56
 * In glibc 2.34, the pthread symbols were moved from libpthread to libc,
57
 * so this doesn't work anymore.
58
 *
59
 * At some point, this legacy code and the BASE_THREAD_LIBS hack in
60
 * configure.ac can probably be removed.
61
 */
62
63
#pragma weak pthread_getspecific
64
#pragma weak pthread_setspecific
65
#pragma weak pthread_key_create
66
#pragma weak pthread_key_delete
67
#pragma weak pthread_mutex_init
68
#pragma weak pthread_mutex_destroy
69
#pragma weak pthread_mutex_lock
70
#pragma weak pthread_mutex_unlock
71
#pragma weak pthread_cond_init
72
#pragma weak pthread_cond_destroy
73
#pragma weak pthread_cond_wait
74
#pragma weak pthread_equal
75
#pragma weak pthread_self
76
#pragma weak pthread_key_create
77
#pragma weak pthread_key_delete
78
#pragma weak pthread_cond_signal
79
80
#define XML_PTHREAD_WEAK
81
53.0M
#define XML_IS_THREADED() libxml_is_threaded
82
17
#define XML_IS_NEVER_THREADED() (!libxml_is_threaded)
83
84
static int libxml_is_threaded = -1;
85
86
#else /* other POSIX platforms */
87
88
#define XML_IS_THREADED() 1
89
#define XML_IS_NEVER_THREADED() 0
90
91
#endif
92
93
/*
94
 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
95
 *       to avoid some craziness since xmlMalloc/xmlFree may actually
96
 *       be hosted on allocated blocks needing them for the allocation ...
97
 */
98
99
/*
100
 * xmlRMutex are reentrant mutual exception locks
101
 */
102
struct _xmlRMutex {
103
#ifdef HAVE_POSIX_THREADS
104
    pthread_mutex_t lock;
105
    unsigned int held;
106
    unsigned int waiters;
107
    pthread_t tid;
108
    pthread_cond_t cv;
109
#elif defined HAVE_WIN32_THREADS
110
    CRITICAL_SECTION cs;
111
#else
112
    int empty;
113
#endif
114
};
115
116
/*
117
 * This module still has some internal static data.
118
 *   - xmlLibraryLock a global lock
119
 *   - globalkey used for per-thread data
120
 */
121
122
#ifdef HAVE_POSIX_THREADS
123
static pthread_key_t globalkey;
124
static pthread_t mainthread;
125
static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
126
#elif defined HAVE_WIN32_THREADS
127
#if defined(HAVE_COMPILER_TLS)
128
static __declspec(thread) xmlGlobalState tlstate;
129
static __declspec(thread) int tlstate_inited = 0;
130
#else /* HAVE_COMPILER_TLS */
131
static DWORD globalkey = TLS_OUT_OF_INDEXES;
132
#endif /* HAVE_COMPILER_TLS */
133
static DWORD mainthread;
134
static volatile LPCRITICAL_SECTION global_init_lock = NULL;
135
#endif
136
137
static xmlRMutexPtr xmlLibraryLock = NULL;
138
139
/**
140
 * xmlInitMutex:
141
 * @mutex:  the mutex
142
 *
143
 * Initialize a mutex.
144
 */
145
void
146
xmlInitMutex(xmlMutexPtr mutex)
147
16
{
148
16
#ifdef HAVE_POSIX_THREADS
149
16
    if (XML_IS_NEVER_THREADED() == 0)
150
16
        pthread_mutex_init(&mutex->lock, NULL);
151
#elif defined HAVE_WIN32_THREADS
152
    InitializeCriticalSection(&mutex->cs);
153
#else
154
    (void) mutex;
155
#endif
156
16
}
157
158
/**
159
 * xmlNewMutex:
160
 *
161
 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
162
 * synchronizing access to data.
163
 *
164
 * Returns a new simple mutex pointer or NULL in case of error
165
 */
166
xmlMutexPtr
167
xmlNewMutex(void)
168
4
{
169
4
    xmlMutexPtr tok;
170
171
4
    if ((tok = malloc(sizeof(xmlMutex))) == NULL)
172
0
        return (NULL);
173
4
    xmlInitMutex(tok);
174
4
    return (tok);
175
4
}
176
177
/**
178
 * xmlCleanupMutex:
179
 * @mutex:  the simple mutex
180
 *
181
 * Reclaim resources associated with a mutex.
182
 */
183
void
184
xmlCleanupMutex(xmlMutexPtr mutex)
185
0
{
186
0
#ifdef HAVE_POSIX_THREADS
187
0
    if (XML_IS_NEVER_THREADED() == 0)
188
0
        pthread_mutex_destroy(&mutex->lock);
189
#elif defined HAVE_WIN32_THREADS
190
    DeleteCriticalSection(&mutex->cs);
191
#else
192
    (void) mutex;
193
#endif
194
0
}
195
196
/**
197
 * xmlFreeMutex:
198
 * @tok:  the simple mutex
199
 *
200
 * Free a mutex.
201
 */
202
void
203
xmlFreeMutex(xmlMutexPtr tok)
204
0
{
205
0
    if (tok == NULL)
206
0
        return;
207
208
0
    xmlCleanupMutex(tok);
209
0
    free(tok);
210
0
}
211
212
/**
213
 * xmlMutexLock:
214
 * @tok:  the simple mutex
215
 *
216
 * xmlMutexLock() is used to lock a libxml2 token.
217
 */
218
void
219
xmlMutexLock(xmlMutexPtr tok)
220
4.00M
{
221
4.00M
    if (tok == NULL)
222
32
        return;
223
4.00M
#ifdef HAVE_POSIX_THREADS
224
    /*
225
     * This assumes that __libc_single_threaded won't change while the
226
     * lock is held.
227
     */
228
4.00M
    if (XML_IS_THREADED() != 0)
229
4.00M
        pthread_mutex_lock(&tok->lock);
230
#elif defined HAVE_WIN32_THREADS
231
    EnterCriticalSection(&tok->cs);
232
#endif
233
234
4.00M
}
235
236
/**
237
 * xmlMutexUnlock:
238
 * @tok:  the simple mutex
239
 *
240
 * xmlMutexUnlock() is used to unlock a libxml2 token.
241
 */
242
void
243
xmlMutexUnlock(xmlMutexPtr tok)
244
4.00M
{
245
4.00M
    if (tok == NULL)
246
32
        return;
247
4.00M
#ifdef HAVE_POSIX_THREADS
248
4.00M
    if (XML_IS_THREADED() != 0)
249
4.00M
        pthread_mutex_unlock(&tok->lock);
250
#elif defined HAVE_WIN32_THREADS
251
    LeaveCriticalSection(&tok->cs);
252
#endif
253
4.00M
}
254
255
/**
256
 * xmlNewRMutex:
257
 *
258
 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
259
 * synchronizing access to data. token_r is a re-entrant lock and thus useful
260
 * for synchronizing access to data structures that may be manipulated in a
261
 * recursive fashion.
262
 *
263
 * Returns the new reentrant mutex pointer or NULL in case of error
264
 */
265
xmlRMutexPtr
266
xmlNewRMutex(void)
267
1
{
268
1
    xmlRMutexPtr tok;
269
270
1
    if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
271
0
        return (NULL);
272
1
#ifdef HAVE_POSIX_THREADS
273
1
    if (XML_IS_NEVER_THREADED() == 0) {
274
1
        pthread_mutex_init(&tok->lock, NULL);
275
1
        tok->held = 0;
276
1
        tok->waiters = 0;
277
1
        pthread_cond_init(&tok->cv, NULL);
278
1
    }
279
#elif defined HAVE_WIN32_THREADS
280
    InitializeCriticalSection(&tok->cs);
281
#endif
282
1
    return (tok);
283
1
}
284
285
/**
286
 * xmlFreeRMutex:
287
 * @tok:  the reentrant mutex
288
 *
289
 * xmlRFreeMutex() is used to reclaim resources associated with a
290
 * reentrant mutex.
291
 */
292
void
293
xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
294
0
{
295
0
    if (tok == NULL)
296
0
        return;
297
0
#ifdef HAVE_POSIX_THREADS
298
0
    if (XML_IS_NEVER_THREADED() == 0) {
299
0
        pthread_mutex_destroy(&tok->lock);
300
0
        pthread_cond_destroy(&tok->cv);
301
0
    }
302
#elif defined HAVE_WIN32_THREADS
303
    DeleteCriticalSection(&tok->cs);
304
#endif
305
0
    free(tok);
306
0
}
307
308
/**
309
 * xmlRMutexLock:
310
 * @tok:  the reentrant mutex
311
 *
312
 * xmlRMutexLock() is used to lock a libxml2 token_r.
313
 */
314
void
315
xmlRMutexLock(xmlRMutexPtr tok)
316
2.35k
{
317
2.35k
    if (tok == NULL)
318
2.35k
        return;
319
1
#ifdef HAVE_POSIX_THREADS
320
1
    if (XML_IS_THREADED() == 0)
321
0
        return;
322
323
1
    pthread_mutex_lock(&tok->lock);
324
1
    if (tok->held) {
325
0
        if (pthread_equal(tok->tid, pthread_self())) {
326
0
            tok->held++;
327
0
            pthread_mutex_unlock(&tok->lock);
328
0
            return;
329
0
        } else {
330
0
            tok->waiters++;
331
0
            while (tok->held)
332
0
                pthread_cond_wait(&tok->cv, &tok->lock);
333
0
            tok->waiters--;
334
0
        }
335
0
    }
336
1
    tok->tid = pthread_self();
337
1
    tok->held = 1;
338
1
    pthread_mutex_unlock(&tok->lock);
339
#elif defined HAVE_WIN32_THREADS
340
    EnterCriticalSection(&tok->cs);
341
#endif
342
1
}
343
344
/**
345
 * xmlRMutexUnlock:
346
 * @tok:  the reentrant mutex
347
 *
348
 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
349
 */
350
void
351
xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
352
2.35k
{
353
2.35k
    if (tok == NULL)
354
2.35k
        return;
355
1
#ifdef HAVE_POSIX_THREADS
356
1
    if (XML_IS_THREADED() == 0)
357
0
        return;
358
359
1
    pthread_mutex_lock(&tok->lock);
360
1
    tok->held--;
361
1
    if (tok->held == 0) {
362
1
        if (tok->waiters)
363
0
            pthread_cond_signal(&tok->cv);
364
1
        memset(&tok->tid, 0, sizeof(tok->tid));
365
1
    }
366
1
    pthread_mutex_unlock(&tok->lock);
367
#elif defined HAVE_WIN32_THREADS
368
    LeaveCriticalSection(&tok->cs);
369
#endif
370
1
}
371
372
/**
373
 * xmlGlobalInitMutexLock
374
 *
375
 * Makes sure that the global initialization mutex is initialized and
376
 * locks it.
377
 */
378
void
379
__xmlGlobalInitMutexLock(void)
380
4
{
381
    /* Make sure the global init lock is initialized and then lock it. */
382
4
#ifdef HAVE_POSIX_THREADS
383
4
#ifdef XML_PTHREAD_WEAK
384
4
    if (pthread_mutex_lock == NULL)
385
0
        return;
386
#else
387
    if (XML_IS_THREADED() == 0)
388
        return;
389
#endif
390
    /* The mutex is statically initialized, so we just lock it. */
391
4
    pthread_mutex_lock(&global_init_lock);
392
#elif defined HAVE_WIN32_THREADS
393
    LPCRITICAL_SECTION cs;
394
395
    /* Create a new critical section */
396
    if (global_init_lock == NULL) {
397
        cs = malloc(sizeof(CRITICAL_SECTION));
398
        if (cs == NULL) {
399
            xmlGenericError(xmlGenericErrorContext,
400
                            "xmlGlobalInitMutexLock: out of memory\n");
401
            return;
402
        }
403
        InitializeCriticalSection(cs);
404
405
        /* Swap it into the global_init_lock */
406
#ifdef InterlockedCompareExchangePointer
407
        InterlockedCompareExchangePointer((void **) &global_init_lock,
408
                                          cs, NULL);
409
#else /* Use older void* version */
410
        InterlockedCompareExchange((void **) &global_init_lock,
411
                                   (void *) cs, NULL);
412
#endif /* InterlockedCompareExchangePointer */
413
414
        /* If another thread successfully recorded its critical
415
         * section in the global_init_lock then discard the one
416
         * allocated by this thread. */
417
        if (global_init_lock != cs) {
418
            DeleteCriticalSection(cs);
419
            free(cs);
420
        }
421
    }
422
423
    /* Lock the chosen critical section */
424
    EnterCriticalSection(global_init_lock);
425
#endif
426
4
}
427
428
void
429
__xmlGlobalInitMutexUnlock(void)
430
4
{
431
4
#ifdef HAVE_POSIX_THREADS
432
4
#ifdef XML_PTHREAD_WEAK
433
4
    if (pthread_mutex_lock == NULL)
434
0
        return;
435
#else
436
    if (XML_IS_THREADED() == 0)
437
        return;
438
#endif
439
4
    pthread_mutex_unlock(&global_init_lock);
440
#elif defined HAVE_WIN32_THREADS
441
    if (global_init_lock != NULL) {
442
  LeaveCriticalSection(global_init_lock);
443
    }
444
#endif
445
4
}
446
447
/**
448
 * xmlGlobalInitMutexDestroy
449
 *
450
 * Makes sure that the global initialization mutex is destroyed before
451
 * application termination.
452
 */
453
void
454
__xmlGlobalInitMutexDestroy(void)
455
0
{
456
0
#ifdef HAVE_POSIX_THREADS
457
#elif defined HAVE_WIN32_THREADS
458
    if (global_init_lock != NULL) {
459
        DeleteCriticalSection(global_init_lock);
460
        free(global_init_lock);
461
        global_init_lock = NULL;
462
    }
463
#endif
464
0
}
465
466
/************************************************************************
467
 *                  *
468
 *      Per thread global state handling    *
469
 *                  *
470
 ************************************************************************/
471
472
#ifdef LIBXML_THREAD_ENABLED
473
#ifdef xmlLastError
474
#undef xmlLastError
475
#endif
476
477
/**
478
 * xmlFreeGlobalState:
479
 * @state:  a thread global state
480
 *
481
 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
482
 * global state. It is is used here to reclaim memory resources.
483
 */
484
static void
485
xmlFreeGlobalState(void *state)
486
0
{
487
0
    xmlGlobalState *gs = (xmlGlobalState *) state;
488
489
    /* free any memory allocated in the thread's xmlLastError */
490
0
    xmlResetError(&(gs->xmlLastError));
491
0
    free(state);
492
0
}
493
494
/**
495
 * xmlNewGlobalState:
496
 *
497
 * xmlNewGlobalState() allocates a global state. This structure is used to
498
 * hold all data for use by a thread when supporting backwards compatibility
499
 * of libxml2 to pre-thread-safe behaviour.
500
 *
501
 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
502
 */
503
static xmlGlobalStatePtr
504
xmlNewGlobalState(void)
505
0
{
506
0
    xmlGlobalState *gs;
507
508
0
    gs = malloc(sizeof(xmlGlobalState));
509
0
    if (gs == NULL) {
510
0
  xmlGenericError(xmlGenericErrorContext,
511
0
      "xmlGetGlobalState: out of memory\n");
512
0
        return (NULL);
513
0
    }
514
515
0
    memset(gs, 0, sizeof(xmlGlobalState));
516
0
    xmlInitializeGlobalState(gs);
517
0
    return (gs);
518
0
}
519
#endif /* LIBXML_THREAD_ENABLED */
520
521
#ifdef HAVE_POSIX_THREADS
522
#elif defined HAVE_WIN32_THREADS
523
#if !defined(HAVE_COMPILER_TLS)
524
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
525
typedef struct _xmlGlobalStateCleanupHelperParams {
526
    HANDLE thread;
527
    void *memory;
528
} xmlGlobalStateCleanupHelperParams;
529
530
static void
531
xmlGlobalStateCleanupHelper(void *p)
532
{
533
    xmlGlobalStateCleanupHelperParams *params =
534
        (xmlGlobalStateCleanupHelperParams *) p;
535
    WaitForSingleObject(params->thread, INFINITE);
536
    CloseHandle(params->thread);
537
    xmlFreeGlobalState(params->memory);
538
    free(params);
539
    _endthread();
540
}
541
#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
542
543
typedef struct _xmlGlobalStateCleanupHelperParams {
544
    void *memory;
545
    struct _xmlGlobalStateCleanupHelperParams *prev;
546
    struct _xmlGlobalStateCleanupHelperParams *next;
547
} xmlGlobalStateCleanupHelperParams;
548
549
static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
550
static CRITICAL_SECTION cleanup_helpers_cs;
551
552
#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
553
#endif /* HAVE_COMPILER_TLS */
554
#endif /* HAVE_WIN32_THREADS */
555
556
/**
557
 * xmlGetGlobalState:
558
 *
559
 * DEPRECATED: Internal function, do not use.
560
 *
561
 * xmlGetGlobalState() is called to retrieve the global state for a thread.
562
 *
563
 * Returns the thread global state or NULL in case of error
564
 */
565
xmlGlobalStatePtr
566
xmlGetGlobalState(void)
567
0
{
568
0
#ifdef HAVE_POSIX_THREADS
569
0
    xmlGlobalState *globalval;
570
571
0
    if (XML_IS_THREADED() == 0)
572
0
        return (NULL);
573
574
0
    if ((globalval = (xmlGlobalState *)
575
0
         pthread_getspecific(globalkey)) == NULL) {
576
0
        xmlGlobalState *tsd = xmlNewGlobalState();
577
0
  if (tsd == NULL)
578
0
      return(NULL);
579
580
0
        pthread_setspecific(globalkey, tsd);
581
0
        return (tsd);
582
0
    }
583
0
    return (globalval);
584
#elif defined HAVE_WIN32_THREADS
585
#if defined(HAVE_COMPILER_TLS)
586
    if (!tlstate_inited) {
587
        tlstate_inited = 1;
588
        xmlInitializeGlobalState(&tlstate);
589
    }
590
    return &tlstate;
591
#else /* HAVE_COMPILER_TLS */
592
    xmlGlobalState *globalval;
593
    xmlGlobalStateCleanupHelperParams *p;
594
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
595
    globalval = (xmlGlobalState *) TlsGetValue(globalkey);
596
#else
597
    p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
598
    globalval = (xmlGlobalState *) (p ? p->memory : NULL);
599
#endif
600
    if (globalval == NULL) {
601
        xmlGlobalState *tsd = xmlNewGlobalState();
602
603
        if (tsd == NULL)
604
      return(NULL);
605
        p = (xmlGlobalStateCleanupHelperParams *)
606
            malloc(sizeof(xmlGlobalStateCleanupHelperParams));
607
  if (p == NULL) {
608
            xmlGenericError(xmlGenericErrorContext,
609
                            "xmlGetGlobalState: out of memory\n");
610
            xmlFreeGlobalState(tsd);
611
      return(NULL);
612
  }
613
        p->memory = tsd;
614
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
615
        DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
616
                        GetCurrentProcess(), &p->thread, 0, TRUE,
617
                        DUPLICATE_SAME_ACCESS);
618
        TlsSetValue(globalkey, tsd);
619
        _beginthread(xmlGlobalStateCleanupHelper, 0, p);
620
#else
621
        EnterCriticalSection(&cleanup_helpers_cs);
622
        if (cleanup_helpers_head != NULL) {
623
            cleanup_helpers_head->prev = p;
624
        }
625
        p->next = cleanup_helpers_head;
626
        p->prev = NULL;
627
        cleanup_helpers_head = p;
628
        TlsSetValue(globalkey, p);
629
        LeaveCriticalSection(&cleanup_helpers_cs);
630
#endif
631
632
        return (tsd);
633
    }
634
    return (globalval);
635
#endif /* HAVE_COMPILER_TLS */
636
#else
637
    return (NULL);
638
#endif
639
0
}
640
641
/************************************************************************
642
 *                  *
643
 *      Library wide thread interfaces      *
644
 *                  *
645
 ************************************************************************/
646
647
/**
648
 * xmlGetThreadId:
649
 *
650
 * DEPRECATED: Internal function, do not use.
651
 *
652
 * xmlGetThreadId() find the current thread ID number
653
 * Note that this is likely to be broken on some platforms using pthreads
654
 * as the specification doesn't mandate pthread_t to be an integer type
655
 *
656
 * Returns the current thread ID number
657
 */
658
int
659
xmlGetThreadId(void)
660
0
{
661
0
#ifdef HAVE_POSIX_THREADS
662
0
    pthread_t id;
663
0
    int ret;
664
665
0
    if (XML_IS_THREADED() == 0)
666
0
        return (0);
667
0
    id = pthread_self();
668
    /* horrible but preserves compat, see warning above */
669
0
    memcpy(&ret, &id, sizeof(ret));
670
0
    return (ret);
671
#elif defined HAVE_WIN32_THREADS
672
    return GetCurrentThreadId();
673
#else
674
    return ((int) 0);
675
#endif
676
0
}
677
678
/**
679
 * xmlIsMainThread:
680
 *
681
 * DEPRECATED: Internal function, do not use.
682
 *
683
 * xmlIsMainThread() check whether the current thread is the main thread.
684
 *
685
 * Returns 1 if the current thread is the main thread, 0 otherwise
686
 */
687
int
688
xmlIsMainThread(void)
689
45.0M
{
690
45.0M
    xmlInitParser();
691
692
#ifdef DEBUG_THREADS
693
    xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
694
#endif
695
45.0M
#ifdef HAVE_POSIX_THREADS
696
45.0M
    if (XML_IS_THREADED() == 0)
697
0
        return (1);
698
45.0M
    return (pthread_equal(mainthread,pthread_self()));
699
#elif defined HAVE_WIN32_THREADS
700
    return (mainthread == GetCurrentThreadId());
701
#else
702
    return (1);
703
#endif
704
45.0M
}
705
706
/**
707
 * xmlLockLibrary:
708
 *
709
 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
710
 * library.
711
 */
712
void
713
xmlLockLibrary(void)
714
2.35k
{
715
#ifdef DEBUG_THREADS
716
    xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
717
#endif
718
2.35k
    xmlRMutexLock(xmlLibraryLock);
719
2.35k
}
720
721
/**
722
 * xmlUnlockLibrary:
723
 *
724
 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
725
 * library.
726
 */
727
void
728
xmlUnlockLibrary(void)
729
2.35k
{
730
#ifdef DEBUG_THREADS
731
    xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
732
#endif
733
2.35k
    xmlRMutexUnlock(xmlLibraryLock);
734
2.35k
}
735
736
/**
737
 * xmlInitThreads:
738
 *
739
 * DEPRECATED: Alias for xmlInitParser.
740
 */
741
void
742
xmlInitThreads(void)
743
0
{
744
0
    xmlInitParser();
745
0
}
746
747
/**
748
 * xmlInitThreadsInternal:
749
 *
750
 * Used to to initialize all the thread related data.
751
 */
752
void
753
xmlInitThreadsInternal(void)
754
4
{
755
4
#ifdef HAVE_POSIX_THREADS
756
4
#ifdef XML_PTHREAD_WEAK
757
    /*
758
     * This is somewhat unreliable since libpthread could be loaded
759
     * later with dlopen() and threads could be created. But it's
760
     * long-standing behavior and hard to work around.
761
     */
762
4
    if (libxml_is_threaded == -1)
763
4
        libxml_is_threaded =
764
4
            (pthread_getspecific != NULL) &&
765
4
            (pthread_setspecific != NULL) &&
766
4
            (pthread_key_create != NULL) &&
767
4
            (pthread_key_delete != NULL) &&
768
4
            (pthread_mutex_init != NULL) &&
769
4
            (pthread_mutex_destroy != NULL) &&
770
4
            (pthread_mutex_lock != NULL) &&
771
4
            (pthread_mutex_unlock != NULL) &&
772
4
            (pthread_cond_init != NULL) &&
773
4
            (pthread_cond_destroy != NULL) &&
774
4
            (pthread_cond_wait != NULL) &&
775
            /*
776
             * pthread_equal can be inline, resuting in -Waddress warnings.
777
             * Let's assume it's available if all the other functions are.
778
             */
779
            /* (pthread_equal != NULL) && */
780
4
            (pthread_self != NULL) &&
781
4
            (pthread_cond_signal != NULL);
782
4
    if (libxml_is_threaded == 0)
783
0
        return;
784
4
#endif /* XML_PTHREAD_WEAK */
785
4
    pthread_key_create(&globalkey, xmlFreeGlobalState);
786
4
    mainthread = pthread_self();
787
#elif defined(HAVE_WIN32_THREADS)
788
#if !defined(HAVE_COMPILER_TLS)
789
#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
790
    InitializeCriticalSection(&cleanup_helpers_cs);
791
#endif
792
    globalkey = TlsAlloc();
793
#endif
794
    mainthread = GetCurrentThreadId();
795
#endif
796
4
}
797
798
/**
799
 * xmlCleanupThreads:
800
 *
801
 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
802
 * to free global state but see the warnings there. xmlCleanupParser
803
 * should be only called once at program exit. In most cases, you don't
804
 * have call cleanup functions at all.
805
 */
806
void
807
xmlCleanupThreads(void)
808
0
{
809
0
}
810
811
/**
812
 * xmlCleanupThreadsInternal:
813
 *
814
 * Used to to cleanup all the thread related data.
815
 */
816
void
817
xmlCleanupThreadsInternal(void)
818
0
{
819
0
#ifdef HAVE_POSIX_THREADS
820
0
#ifdef XML_PTHREAD_WEAK
821
0
    if (libxml_is_threaded == 0)
822
0
        return;
823
0
#endif /* XML_PTHREAD_WEAK */
824
0
    pthread_key_delete(globalkey);
825
#elif defined(HAVE_WIN32_THREADS)
826
#if !defined(HAVE_COMPILER_TLS)
827
    if (globalkey != TLS_OUT_OF_INDEXES) {
828
#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
829
        xmlGlobalStateCleanupHelperParams *p;
830
831
        EnterCriticalSection(&cleanup_helpers_cs);
832
        p = cleanup_helpers_head;
833
        while (p != NULL) {
834
            xmlGlobalStateCleanupHelperParams *temp = p;
835
836
            p = p->next;
837
            xmlFreeGlobalState(temp->memory);
838
            free(temp);
839
        }
840
        cleanup_helpers_head = 0;
841
        LeaveCriticalSection(&cleanup_helpers_cs);
842
#endif
843
        TlsFree(globalkey);
844
        globalkey = TLS_OUT_OF_INDEXES;
845
    }
846
#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
847
    DeleteCriticalSection(&cleanup_helpers_cs);
848
#endif
849
#endif
850
#endif
851
0
}
852
853
/**
854
 * DllMain:
855
 * @hinstDLL: handle to DLL instance
856
 * @fdwReason: Reason code for entry
857
 * @lpvReserved: generic pointer (depends upon reason code)
858
 *
859
 * Entry point for Windows library. It is being used to free thread-specific
860
 * storage.
861
 *
862
 * Returns TRUE always
863
 */
864
#ifdef HAVE_POSIX_THREADS
865
#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
866
#if defined(LIBXML_STATIC_FOR_DLL)
867
int
868
xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
869
           ATTRIBUTE_UNUSED void *lpvReserved)
870
#else
871
/* declare to avoid "no previous prototype for 'DllMain'" warning */
872
/* Note that we do NOT want to include this function declaration in
873
   a public header because it's meant to be called by Windows itself,
874
   not a program that uses this library.  This also has to be exported. */
875
876
XMLPUBFUN BOOL WINAPI
877
DllMain (HINSTANCE hinstDLL,
878
         DWORD     fdwReason,
879
         LPVOID    lpvReserved);
880
881
BOOL WINAPI
882
DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
883
        ATTRIBUTE_UNUSED LPVOID lpvReserved)
884
#endif
885
{
886
    switch (fdwReason) {
887
        case DLL_THREAD_DETACH:
888
            if (globalkey != TLS_OUT_OF_INDEXES) {
889
                xmlGlobalState *globalval = NULL;
890
                xmlGlobalStateCleanupHelperParams *p =
891
                    (xmlGlobalStateCleanupHelperParams *)
892
                    TlsGetValue(globalkey);
893
                globalval = (xmlGlobalState *) (p ? p->memory : NULL);
894
                if (globalval) {
895
                    xmlFreeGlobalState(globalval);
896
                    TlsSetValue(globalkey, NULL);
897
                }
898
                if (p) {
899
                    EnterCriticalSection(&cleanup_helpers_cs);
900
                    if (p == cleanup_helpers_head)
901
                        cleanup_helpers_head = p->next;
902
                    else
903
                        p->prev->next = p->next;
904
                    if (p->next != NULL)
905
                        p->next->prev = p->prev;
906
                    LeaveCriticalSection(&cleanup_helpers_cs);
907
                    free(p);
908
                }
909
            }
910
            break;
911
    }
912
    return TRUE;
913
}
914
#endif