Coverage Report

Created: 2023-10-27 07:47

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