Coverage Report

Created: 2025-08-04 07:15

/src/libxml2-2.9.7/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
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>
29
#elif defined HAVE_WIN32_THREADS
30
#define WIN32_LEAN_AND_MEAN
31
#include <windows.h>
32
#ifndef HAVE_COMPILER_TLS
33
#include <process.h>
34
#endif
35
#endif
36
37
#ifdef HAVE_BEOS_THREADS
38
#include <OS.h>
39
#include <TLS.h>
40
#endif
41
42
#if defined(SOLARIS)
43
#include <note.h>
44
#endif
45
46
/* #define DEBUG_THREADS */
47
48
#ifdef HAVE_PTHREAD_H
49
50
static int libxml_is_threaded = -1;
51
#if defined(__GNUC__) && defined(__GLIBC__)
52
#ifdef __linux__
53
#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
54
#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
71
#endif
72
#endif /* __linux__ */
73
#endif /* defined(__GNUC__) && defined(__GLIBC__) */
74
#endif /* HAVE_PTHREAD_H */
75
76
/*
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
 */
85
struct _xmlMutex {
86
#ifdef HAVE_PTHREAD_H
87
    pthread_mutex_t lock;
88
#elif defined HAVE_WIN32_THREADS
89
    HANDLE mutex;
90
#elif defined HAVE_BEOS_THREADS
91
    sem_id sem;
92
    thread_id tid;
93
#else
94
    int empty;
95
#endif
96
};
97
98
/*
99
 * xmlRMutex are reentrant mutual exception locks
100
 */
101
struct _xmlRMutex {
102
#ifdef HAVE_PTHREAD_H
103
    pthread_mutex_t lock;
104
    unsigned int held;
105
    unsigned int waiters;
106
    pthread_t tid;
107
    pthread_cond_t cv;
108
#elif defined HAVE_WIN32_THREADS
109
    CRITICAL_SECTION cs;
110
    unsigned int count;
111
#elif defined HAVE_BEOS_THREADS
112
    xmlMutexPtr lock;
113
    thread_id tid;
114
    int32 count;
115
#else
116
    int empty;
117
#endif
118
};
119
120
/*
121
 * This module still has some internal static data.
122
 *   - xmlLibraryLock a global lock
123
 *   - globalkey used for per-thread data
124
 */
125
126
#ifdef HAVE_PTHREAD_H
127
static pthread_key_t globalkey;
128
static pthread_t mainthread;
129
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
130
static pthread_once_t once_control_init = PTHREAD_ONCE_INIT;
131
static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
132
#elif defined HAVE_WIN32_THREADS
133
#if defined(HAVE_COMPILER_TLS)
134
static __declspec(thread) xmlGlobalState tlstate;
135
static __declspec(thread) int tlstate_inited = 0;
136
#else /* HAVE_COMPILER_TLS */
137
static DWORD globalkey = TLS_OUT_OF_INDEXES;
138
#endif /* HAVE_COMPILER_TLS */
139
static DWORD mainthread;
140
static struct {
141
    DWORD done;
142
    LONG control;
143
} run_once = { 0, 0};
144
static volatile LPCRITICAL_SECTION global_init_lock = NULL;
145
146
/* endif HAVE_WIN32_THREADS */
147
#elif defined HAVE_BEOS_THREADS
148
int32 globalkey = 0;
149
thread_id mainthread = 0;
150
int32 run_once_init = 0;
151
static int32 global_init_lock = -1;
152
static vint32 global_init_count = 0;
153
#endif
154
155
static xmlRMutexPtr xmlLibraryLock = NULL;
156
157
#ifdef LIBXML_THREAD_ENABLED
158
static void xmlOnceInit(void);
159
#endif
160
161
/**
162
 * xmlNewMutex:
163
 *
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
 */
169
xmlMutexPtr
170
xmlNewMutex(void)
171
28
{
172
28
    xmlMutexPtr tok;
173
174
28
    if ((tok = malloc(sizeof(xmlMutex))) == NULL)
175
0
        return (NULL);
176
28
#ifdef HAVE_PTHREAD_H
177
28
    if (libxml_is_threaded != 0)
178
28
        pthread_mutex_init(&tok->lock, NULL);
179
#elif defined HAVE_WIN32_THREADS
180
    tok->mutex = CreateMutex(NULL, FALSE, NULL);
181
#elif defined HAVE_BEOS_THREADS
182
    if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
183
        free(tok);
184
        return NULL;
185
    }
186
    tok->tid = -1;
187
#endif
188
28
    return (tok);
189
28
}
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
 */
198
void
199
xmlFreeMutex(xmlMutexPtr tok)
200
0
{
201
0
    if (tok == NULL)
202
0
        return;
203
204
0
#ifdef HAVE_PTHREAD_H
205
0
    if (libxml_is_threaded != 0)
206
0
        pthread_mutex_destroy(&tok->lock);
207
#elif defined HAVE_WIN32_THREADS
208
    CloseHandle(tok->mutex);
209
#elif defined HAVE_BEOS_THREADS
210
    delete_sem(tok->sem);
211
#endif
212
0
    free(tok);
213
0
}
214
215
/**
216
 * xmlMutexLock:
217
 * @tok:  the simple mutex
218
 *
219
 * xmlMutexLock() is used to lock a libxml2 token.
220
 */
221
void
222
xmlMutexLock(xmlMutexPtr tok)
223
0
{
224
0
    if (tok == NULL)
225
0
        return;
226
0
#ifdef HAVE_PTHREAD_H
227
0
    if (libxml_is_threaded != 0)
228
0
        pthread_mutex_lock(&tok->lock);
229
#elif defined HAVE_WIN32_THREADS
230
    WaitForSingleObject(tok->mutex, INFINITE);
231
#elif defined HAVE_BEOS_THREADS
232
    if (acquire_sem(tok->sem) != B_NO_ERROR) {
233
#ifdef DEBUG_THREADS
234
        xmlGenericError(xmlGenericErrorContext,
235
                        "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
236
#endif
237
    }
238
    tok->tid = find_thread(NULL);
239
#endif
240
241
0
}
242
243
/**
244
 * xmlMutexUnlock:
245
 * @tok:  the simple mutex
246
 *
247
 * xmlMutexUnlock() is used to unlock a libxml2 token.
248
 */
249
void
250
xmlMutexUnlock(xmlMutexPtr tok)
251
0
{
252
0
    if (tok == NULL)
253
0
        return;
254
0
#ifdef HAVE_PTHREAD_H
255
0
    if (libxml_is_threaded != 0)
256
0
        pthread_mutex_unlock(&tok->lock);
257
#elif defined HAVE_WIN32_THREADS
258
    ReleaseMutex(tok->mutex);
259
#elif defined HAVE_BEOS_THREADS
260
    if (tok->tid == find_thread(NULL)) {
261
        tok->tid = -1;
262
        release_sem(tok->sem);
263
    }
264
#endif
265
0
}
266
267
/**
268
 * xmlNewRMutex:
269
 *
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
 */
277
xmlRMutexPtr
278
xmlNewRMutex(void)
279
14
{
280
14
    xmlRMutexPtr tok;
281
282
14
    if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
283
0
        return (NULL);
284
14
#ifdef HAVE_PTHREAD_H
285
14
    if (libxml_is_threaded != 0) {
286
14
        pthread_mutex_init(&tok->lock, NULL);
287
14
        tok->held = 0;
288
14
        tok->waiters = 0;
289
14
        pthread_cond_init(&tok->cv, NULL);
290
14
    }
291
#elif defined HAVE_WIN32_THREADS
292
    InitializeCriticalSection(&tok->cs);
293
    tok->count = 0;
294
#elif defined HAVE_BEOS_THREADS
295
    if ((tok->lock = xmlNewMutex()) == NULL) {
296
        free(tok);
297
        return NULL;
298
    }
299
    tok->count = 0;
300
#endif
301
14
    return (tok);
302
14
}
303
304
/**
305
 * xmlFreeRMutex:
306
 * @tok:  the reentrant mutex
307
 *
308
 * xmlRFreeMutex() is used to reclaim resources associated with a
309
 * reentrant mutex.
310
 */
311
void
312
xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
313
0
{
314
0
    if (tok == NULL)
315
0
        return;
316
0
#ifdef HAVE_PTHREAD_H
317
0
    if (libxml_is_threaded != 0) {
318
0
        pthread_mutex_destroy(&tok->lock);
319
0
        pthread_cond_destroy(&tok->cv);
320
0
    }
321
#elif defined HAVE_WIN32_THREADS
322
    DeleteCriticalSection(&tok->cs);
323
#elif defined HAVE_BEOS_THREADS
324
    xmlFreeMutex(tok->lock);
325
#endif
326
0
    free(tok);
327
0
}
328
329
/**
330
 * xmlRMutexLock:
331
 * @tok:  the reentrant mutex
332
 *
333
 * xmlRMutexLock() is used to lock a libxml2 token_r.
334
 */
335
void
336
xmlRMutexLock(xmlRMutexPtr tok)
337
14
{
338
14
    if (tok == NULL)
339
0
        return;
340
14
#ifdef HAVE_PTHREAD_H
341
14
    if (libxml_is_threaded == 0)
342
0
        return;
343
344
14
    pthread_mutex_lock(&tok->lock);
345
14
    if (tok->held) {
346
0
        if (pthread_equal(tok->tid, pthread_self())) {
347
0
            tok->held++;
348
0
            pthread_mutex_unlock(&tok->lock);
349
0
            return;
350
0
        } else {
351
0
            tok->waiters++;
352
0
            while (tok->held)
353
0
                pthread_cond_wait(&tok->cv, &tok->lock);
354
0
            tok->waiters--;
355
0
        }
356
0
    }
357
14
    tok->tid = pthread_self();
358
14
    tok->held = 1;
359
14
    pthread_mutex_unlock(&tok->lock);
360
#elif defined HAVE_WIN32_THREADS
361
    EnterCriticalSection(&tok->cs);
362
    tok->count++;
363
#elif defined HAVE_BEOS_THREADS
364
    if (tok->lock->tid == find_thread(NULL)) {
365
        tok->count++;
366
        return;
367
    } else {
368
        xmlMutexLock(tok->lock);
369
        tok->count = 1;
370
    }
371
#endif
372
14
}
373
374
/**
375
 * xmlRMutexUnlock:
376
 * @tok:  the reentrant mutex
377
 *
378
 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
379
 */
380
void
381
xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
382
14
{
383
14
    if (tok == NULL)
384
0
        return;
385
14
#ifdef HAVE_PTHREAD_H
386
14
    if (libxml_is_threaded == 0)
387
0
        return;
388
389
14
    pthread_mutex_lock(&tok->lock);
390
14
    tok->held--;
391
14
    if (tok->held == 0) {
392
14
        if (tok->waiters)
393
0
            pthread_cond_signal(&tok->cv);
394
14
        memset(&tok->tid, 0, sizeof(tok->tid));
395
14
    }
396
14
    pthread_mutex_unlock(&tok->lock);
397
#elif defined HAVE_WIN32_THREADS
398
    if (tok->count > 0) {
399
  tok->count--;
400
        LeaveCriticalSection(&tok->cs);
401
    }
402
#elif defined HAVE_BEOS_THREADS
403
    if (tok->lock->tid == find_thread(NULL)) {
404
        tok->count--;
405
        if (tok->count == 0) {
406
            xmlMutexUnlock(tok->lock);
407
        }
408
        return;
409
    }
410
#endif
411
14
}
412
413
/**
414
 * xmlGlobalInitMutexLock
415
 *
416
 * Makes sure that the global initialization mutex is initialized and
417
 * locks it.
418
 */
419
void
420
__xmlGlobalInitMutexLock(void)
421
14
{
422
    /* Make sure the global init lock is initialized and then lock it. */
423
14
#ifdef HAVE_PTHREAD_H
424
    /* The mutex is statically initialized, so we just lock it. */
425
14
    if (pthread_mutex_lock != NULL)
426
14
        pthread_mutex_lock(&global_init_lock);
427
#elif defined HAVE_WIN32_THREADS
428
    LPCRITICAL_SECTION cs;
429
430
    /* Create a new critical section */
431
    if (global_init_lock == NULL) {
432
        cs = malloc(sizeof(CRITICAL_SECTION));
433
        if (cs == NULL) {
434
            xmlGenericError(xmlGenericErrorContext,
435
                            "xmlGlobalInitMutexLock: out of memory\n");
436
            return;
437
        }
438
        InitializeCriticalSection(cs);
439
440
        /* Swap it into the global_init_lock */
441
#ifdef InterlockedCompareExchangePointer
442
        InterlockedCompareExchangePointer((void **) &global_init_lock,
443
                                          cs, NULL);
444
#else /* Use older void* version */
445
        InterlockedCompareExchange((void **) &global_init_lock,
446
                                   (void *) cs, NULL);
447
#endif /* InterlockedCompareExchangePointer */
448
449
        /* 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
        }
456
    }
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) {
467
        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
        }
473
    }
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)
479
        delete_sem(sem);
480
481
    /* Acquire the chosen semaphore */
482
    if (acquire_sem(global_init_lock) != B_NO_ERROR) {
483
#ifdef DEBUG_THREADS
484
        xmlGenericError(xmlGenericErrorContext,
485
                        "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
486
#endif
487
    }
488
#endif
489
14
}
490
491
void
492
__xmlGlobalInitMutexUnlock(void)
493
14
{
494
14
#ifdef HAVE_PTHREAD_H
495
14
    if (pthread_mutex_unlock != NULL)
496
14
        pthread_mutex_unlock(&global_init_lock);
497
#elif defined HAVE_WIN32_THREADS
498
    if (global_init_lock != NULL) {
499
  LeaveCriticalSection(global_init_lock);
500
    }
501
#elif defined HAVE_BEOS_THREADS
502
    release_sem(global_init_lock);
503
#endif
504
14
}
505
506
/**
507
 * xmlGlobalInitMutexDestroy
508
 *
509
 * Makes sure that the global initialization mutex is destroyed before
510
 * application termination.
511
 */
512
void
513
__xmlGlobalInitMutexDestroy(void)
514
0
{
515
0
#ifdef HAVE_PTHREAD_H
516
#elif defined HAVE_WIN32_THREADS
517
    if (global_init_lock != NULL) {
518
        DeleteCriticalSection(global_init_lock);
519
        free(global_init_lock);
520
        global_init_lock = NULL;
521
    }
522
#endif
523
0
}
524
525
/************************************************************************
526
 *                  *
527
 *      Per thread global state handling    *
528
 *                  *
529
 ************************************************************************/
530
531
#ifdef LIBXML_THREAD_ENABLED
532
#ifdef xmlLastError
533
#undef xmlLastError
534
#endif
535
536
/**
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
 */
543
static void
544
xmlFreeGlobalState(void *state)
545
0
{
546
0
    xmlGlobalState *gs = (xmlGlobalState *) state;
547
548
    /* free any memory allocated in the thread's xmlLastError */
549
0
    xmlResetError(&(gs->xmlLastError));
550
0
    free(state);
551
0
}
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
558
 * of libxml2 to pre-thread-safe behaviour.
559
 *
560
 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
561
 */
562
static xmlGlobalStatePtr
563
xmlNewGlobalState(void)
564
0
{
565
0
    xmlGlobalState *gs;
566
567
0
    gs = malloc(sizeof(xmlGlobalState));
568
0
    if (gs == NULL) {
569
0
  xmlGenericError(xmlGenericErrorContext,
570
0
      "xmlGetGlobalState: out of memory\n");
571
0
        return (NULL);
572
0
    }
573
574
0
    memset(gs, 0, sizeof(xmlGlobalState));
575
0
    xmlInitializeGlobalState(gs);
576
0
    return (gs);
577
0
}
578
#endif /* LIBXML_THREAD_ENABLED */
579
580
#ifdef HAVE_PTHREAD_H
581
#elif defined HAVE_WIN32_THREADS
582
#if !defined(HAVE_COMPILER_TLS)
583
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
584
typedef struct _xmlGlobalStateCleanupHelperParams {
585
    HANDLE thread;
586
    void *memory;
587
} xmlGlobalStateCleanupHelperParams;
588
589
static void XMLCDECL
590
xmlGlobalStateCleanupHelper(void *p)
591
{
592
    xmlGlobalStateCleanupHelperParams *params =
593
        (xmlGlobalStateCleanupHelperParams *) p;
594
    WaitForSingleObject(params->thread, INFINITE);
595
    CloseHandle(params->thread);
596
    xmlFreeGlobalState(params->memory);
597
    free(params);
598
    _endthread();
599
}
600
#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
601
602
typedef struct _xmlGlobalStateCleanupHelperParams {
603
    void *memory;
604
    struct _xmlGlobalStateCleanupHelperParams *prev;
605
    struct _xmlGlobalStateCleanupHelperParams *next;
606
} xmlGlobalStateCleanupHelperParams;
607
608
static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
609
static CRITICAL_SECTION cleanup_helpers_cs;
610
611
#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
612
#endif /* HAVE_COMPILER_TLS */
613
#endif /* HAVE_WIN32_THREADS */
614
615
#if defined HAVE_BEOS_THREADS
616
617
/**
618
 * xmlGlobalStateCleanup:
619
 * @data: unused parameter
620
 *
621
 * Used for Beos only
622
 */
623
void
624
xmlGlobalStateCleanup(void *data)
625
{
626
    void *globalval = tls_get(globalkey);
627
628
    if (globalval != NULL)
629
        xmlFreeGlobalState(globalval);
630
}
631
#endif
632
633
/**
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
 */
640
xmlGlobalStatePtr
641
xmlGetGlobalState(void)
642
0
{
643
0
#ifdef HAVE_PTHREAD_H
644
0
    xmlGlobalState *globalval;
645
646
0
    if (libxml_is_threaded == 0)
647
0
        return (NULL);
648
649
0
    pthread_once(&once_control, xmlOnceInit);
650
651
0
    if ((globalval = (xmlGlobalState *)
652
0
         pthread_getspecific(globalkey)) == NULL) {
653
0
        xmlGlobalState *tsd = xmlNewGlobalState();
654
0
  if (tsd == NULL)
655
0
      return(NULL);
656
657
0
        pthread_setspecific(globalkey, tsd);
658
0
        return (tsd);
659
0
    }
660
0
    return (globalval);
661
#elif defined HAVE_WIN32_THREADS
662
#if defined(HAVE_COMPILER_TLS)
663
    if (!tlstate_inited) {
664
        tlstate_inited = 1;
665
        xmlInitializeGlobalState(&tlstate);
666
    }
667
    return &tlstate;
668
#else /* HAVE_COMPILER_TLS */
669
    xmlGlobalState *globalval;
670
    xmlGlobalStateCleanupHelperParams *p;
671
672
    xmlOnceInit();
673
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
674
    globalval = (xmlGlobalState *) TlsGetValue(globalkey);
675
#else
676
    p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
677
    globalval = (xmlGlobalState *) (p ? p->memory : NULL);
678
#endif
679
    if (globalval == NULL) {
680
        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");
689
            xmlFreeGlobalState(tsd);
690
      return(NULL);
691
  }
692
        p->memory = tsd;
693
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
694
        DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
695
                        GetCurrentProcess(), &p->thread, 0, TRUE,
696
                        DUPLICATE_SAME_ACCESS);
697
        TlsSetValue(globalkey, tsd);
698
        _beginthread(xmlGlobalStateCleanupHelper, 0, p);
699
#else
700
        EnterCriticalSection(&cleanup_helpers_cs);
701
        if (cleanup_helpers_head != NULL) {
702
            cleanup_helpers_head->prev = p;
703
        }
704
        p->next = cleanup_helpers_head;
705
        p->prev = NULL;
706
        cleanup_helpers_head = p;
707
        TlsSetValue(globalkey, p);
708
        LeaveCriticalSection(&cleanup_helpers_cs);
709
#endif
710
711
        return (tsd);
712
    }
713
    return (globalval);
714
#endif /* HAVE_COMPILER_TLS */
715
#elif defined HAVE_BEOS_THREADS
716
    xmlGlobalState *globalval;
717
718
    xmlOnceInit();
719
720
    if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
721
        xmlGlobalState *tsd = xmlNewGlobalState();
722
  if (tsd == NULL)
723
      return (NULL);
724
725
        tls_set(globalkey, tsd);
726
        on_exit_thread(xmlGlobalStateCleanup, NULL);
727
        return (tsd);
728
    }
729
    return (globalval);
730
#else
731
    return (NULL);
732
#endif
733
0
}
734
735
/************************************************************************
736
 *                  *
737
 *      Library wide thread interfaces      *
738
 *                  *
739
 ************************************************************************/
740
741
/**
742
 * xmlGetThreadId:
743
 *
744
 * xmlGetThreadId() find the current thread ID number
745
 * 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
747
 *
748
 * Returns the current thread ID number
749
 */
750
int
751
xmlGetThreadId(void)
752
0
{
753
0
#ifdef HAVE_PTHREAD_H
754
0
    pthread_t id;
755
0
    int ret;
756
757
0
    if (libxml_is_threaded == 0)
758
0
        return (0);
759
0
    id = pthread_self();
760
    /* horrible but preserves compat, see warning above */
761
0
    memcpy(&ret, &id, sizeof(ret));
762
0
    return (ret);
763
#elif defined HAVE_WIN32_THREADS
764
    return GetCurrentThreadId();
765
#elif defined HAVE_BEOS_THREADS
766
    return find_thread(NULL);
767
#else
768
    return ((int) 0);
769
#endif
770
0
}
771
772
/**
773
 * xmlIsMainThread:
774
 *
775
 * xmlIsMainThread() check whether the current thread is the main thread.
776
 *
777
 * Returns 1 if the current thread is the main thread, 0 otherwise
778
 */
779
int
780
xmlIsMainThread(void)
781
56
{
782
56
#ifdef HAVE_PTHREAD_H
783
56
    if (libxml_is_threaded == -1)
784
0
        xmlInitThreads();
785
56
    if (libxml_is_threaded == 0)
786
0
        return (1);
787
56
    pthread_once(&once_control, xmlOnceInit);
788
#elif defined HAVE_WIN32_THREADS
789
    xmlOnceInit();
790
#elif defined HAVE_BEOS_THREADS
791
    xmlOnceInit();
792
#endif
793
794
#ifdef DEBUG_THREADS
795
    xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
796
#endif
797
56
#ifdef HAVE_PTHREAD_H
798
56
    return (pthread_equal(mainthread,pthread_self()));
799
#elif defined HAVE_WIN32_THREADS
800
    return (mainthread == GetCurrentThreadId());
801
#elif defined HAVE_BEOS_THREADS
802
    return (mainthread == find_thread(NULL));
803
#else
804
    return (1);
805
#endif
806
56
}
807
808
/**
809
 * xmlLockLibrary:
810
 *
811
 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
812
 * library.
813
 */
814
void
815
xmlLockLibrary(void)
816
0
{
817
#ifdef DEBUG_THREADS
818
    xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
819
#endif
820
0
    xmlRMutexLock(xmlLibraryLock);
821
0
}
822
823
/**
824
 * xmlUnlockLibrary:
825
 *
826
 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
827
 * library.
828
 */
829
void
830
xmlUnlockLibrary(void)
831
0
{
832
#ifdef DEBUG_THREADS
833
    xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
834
#endif
835
0
    xmlRMutexUnlock(xmlLibraryLock);
836
0
}
837
838
/**
839
 * xmlInitThreads:
840
 *
841
 * xmlInitThreads() is used to to initialize all the thread related
842
 * data of the libxml2 library.
843
 */
844
void
845
xmlInitThreads(void)
846
14
{
847
14
#ifdef HAVE_PTHREAD_H
848
14
    if (libxml_is_threaded == -1) {
849
14
        if ((pthread_once != NULL) &&
850
14
            (pthread_getspecific != NULL) &&
851
14
            (pthread_setspecific != NULL) &&
852
14
            (pthread_key_create != NULL) &&
853
14
            (pthread_key_delete != NULL) &&
854
14
            (pthread_mutex_init != NULL) &&
855
14
            (pthread_mutex_destroy != NULL) &&
856
14
            (pthread_mutex_lock != NULL) &&
857
14
            (pthread_mutex_unlock != NULL) &&
858
14
            (pthread_cond_init != NULL) &&
859
14
            (pthread_cond_destroy != NULL) &&
860
14
            (pthread_cond_wait != NULL) &&
861
14
            (pthread_equal != NULL) &&
862
14
            (pthread_self != NULL) &&
863
14
            (pthread_cond_signal != NULL)) {
864
14
            libxml_is_threaded = 1;
865
866
/* fprintf(stderr, "Running multithreaded\n"); */
867
14
        } else {
868
869
/* fprintf(stderr, "Running without multithread\n"); */
870
0
            libxml_is_threaded = 0;
871
0
        }
872
14
    }
873
#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
874
    InitializeCriticalSection(&cleanup_helpers_cs);
875
#endif
876
14
}
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.
883
 *
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 !
891
 */
892
void
893
xmlCleanupThreads(void)
894
0
{
895
#ifdef DEBUG_THREADS
896
    xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
897
#endif
898
0
#ifdef HAVE_PTHREAD_H
899
0
    if ((libxml_is_threaded)  && (pthread_key_delete != NULL))
900
0
        pthread_key_delete(globalkey);
901
0
    once_control = once_control_init;
902
#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
903
    if (globalkey != TLS_OUT_OF_INDEXES) {
904
        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;
919
    }
920
    DeleteCriticalSection(&cleanup_helpers_cs);
921
#endif
922
0
}
923
924
#ifdef LIBXML_THREAD_ENABLED
925
926
/**
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
 */
935
static void
936
xmlOnceInit(void)
937
14
{
938
14
#ifdef HAVE_PTHREAD_H
939
14
    (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
940
14
    mainthread = pthread_self();
941
14
    __xmlInitializeDict();
942
#elif defined(HAVE_WIN32_THREADS)
943
    if (!run_once.done) {
944
        if (InterlockedIncrement(&run_once.control) == 1) {
945
#if !defined(HAVE_COMPILER_TLS)
946
            globalkey = TlsAlloc();
947
#endif
948
            mainthread = GetCurrentThreadId();
949
      __xmlInitializeDict();
950
            run_once.done = 1;
951
        } else {
952
            /* 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
    }
958
#elif defined HAVE_BEOS_THREADS
959
    if (atomic_add(&run_once_init, 1) == 0) {
960
        globalkey = tls_allocate();
961
        tls_set(globalkey, NULL);
962
        mainthread = find_thread(NULL);
963
  __xmlInitializeDict();
964
    } else
965
        atomic_add(&run_once_init, -1);
966
#endif
967
14
}
968
#endif
969
970
/**
971
 * DllMain:
972
 * @hinstDLL: handle to DLL instance
973
 * @fdwReason: Reason code for entry
974
 * @lpvReserved: generic pointer (depends upon reason code)
975
 *
976
 * Entry point for Windows library. It is being used to free thread-specific
977
 * storage.
978
 *
979
 * Returns TRUE always
980
 */
981
#ifdef HAVE_PTHREAD_H
982
#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
983
#if defined(LIBXML_STATIC_FOR_DLL)
984
int XMLCALL
985
xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
986
           ATTRIBUTE_UNUSED void *lpvReserved)
987
#else
988
/* 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
993
XMLPUBFUN BOOL WINAPI
994
DllMain (HINSTANCE hinstDLL,
995
         DWORD     fdwReason,
996
         LPVOID    lpvReserved);
997
998
BOOL WINAPI
999
DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
1000
        ATTRIBUTE_UNUSED LPVOID lpvReserved)
1001
#endif
1002
{
1003
    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
                }
1026
            }
1027
            break;
1028
    }
1029
    return TRUE;
1030
}
1031
#endif
1032
#define bottom_threads
1033
#include "elfgcchack.h"