Coverage Report

Created: 2023-06-07 06:05

/src/libxml2-2.10.3/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
#ifdef HAVE_PTHREAD_H
20
#include <pthread.h>
21
#elif defined HAVE_WIN32_THREADS
22
#define WIN32_LEAN_AND_MEAN
23
#include <windows.h>
24
#ifndef HAVE_COMPILER_TLS
25
#include <process.h>
26
#endif
27
#endif
28
29
#ifdef HAVE_BEOS_THREADS
30
#include <OS.h>
31
#include <TLS.h>
32
#endif
33
34
#if defined(SOLARIS)
35
#include <note.h>
36
#endif
37
38
/* #define DEBUG_THREADS */
39
40
#ifdef HAVE_PTHREAD_H
41
42
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 303) && \
43
    defined(__GLIBC__) && defined(__linux__)
44
45
static int libxml_is_threaded = -1;
46
47
#define XML_PTHREAD_WEAK
48
49
#pragma weak pthread_once
50
#pragma weak pthread_getspecific
51
#pragma weak pthread_setspecific
52
#pragma weak pthread_key_create
53
#pragma weak pthread_key_delete
54
#pragma weak pthread_mutex_init
55
#pragma weak pthread_mutex_destroy
56
#pragma weak pthread_mutex_lock
57
#pragma weak pthread_mutex_unlock
58
#pragma weak pthread_cond_init
59
#pragma weak pthread_cond_destroy
60
#pragma weak pthread_cond_wait
61
#pragma weak pthread_equal
62
#pragma weak pthread_self
63
#pragma weak pthread_key_create
64
#pragma weak pthread_key_delete
65
#pragma weak pthread_cond_signal
66
67
#else /* __GNUC__, __GLIBC__, __linux__ */
68
69
static int libxml_is_threaded = 1;
70
71
#endif /* __GNUC__, __GLIBC__, __linux__ */
72
73
#endif /* HAVE_PTHREAD_H */
74
75
/*
76
 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
77
 *       to avoid some craziness since xmlMalloc/xmlFree may actually
78
 *       be hosted on allocated blocks needing them for the allocation ...
79
 */
80
81
/*
82
 * xmlMutex are a simple mutual exception locks
83
 */
84
struct _xmlMutex {
85
#ifdef HAVE_PTHREAD_H
86
    pthread_mutex_t lock;
87
#elif defined HAVE_WIN32_THREADS
88
    CRITICAL_SECTION cs;
89
#elif defined HAVE_BEOS_THREADS
90
    sem_id sem;
91
    thread_id tid;
92
#else
93
    int empty;
94
#endif
95
};
96
97
/*
98
 * xmlRMutex are reentrant mutual exception locks
99
 */
100
struct _xmlRMutex {
101
#ifdef HAVE_PTHREAD_H
102
    pthread_mutex_t lock;
103
    unsigned int held;
104
    unsigned int waiters;
105
    pthread_t tid;
106
    pthread_cond_t cv;
107
#elif defined HAVE_WIN32_THREADS
108
    CRITICAL_SECTION cs;
109
#elif defined HAVE_BEOS_THREADS
110
    xmlMutexPtr lock;
111
    thread_id tid;
112
    int32 count;
113
#else
114
    int empty;
115
#endif
116
};
117
118
/*
119
 * This module still has some internal static data.
120
 *   - xmlLibraryLock a global lock
121
 *   - globalkey used for per-thread data
122
 */
123
124
#ifdef HAVE_PTHREAD_H
125
static pthread_key_t globalkey;
126
static pthread_t mainthread;
127
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
128
static pthread_once_t once_control_init = PTHREAD_ONCE_INIT;
129
static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
130
#elif defined HAVE_WIN32_THREADS
131
#if defined(HAVE_COMPILER_TLS)
132
static __declspec(thread) xmlGlobalState tlstate;
133
static __declspec(thread) int tlstate_inited = 0;
134
#else /* HAVE_COMPILER_TLS */
135
static DWORD globalkey = TLS_OUT_OF_INDEXES;
136
#endif /* HAVE_COMPILER_TLS */
137
static DWORD mainthread;
138
static struct {
139
    DWORD done;
140
    LONG control;
141
} run_once = { 0, 0};
142
static volatile LPCRITICAL_SECTION global_init_lock = NULL;
143
144
/* endif HAVE_WIN32_THREADS */
145
#elif defined HAVE_BEOS_THREADS
146
int32 globalkey = 0;
147
thread_id mainthread = 0;
148
int32 run_once_init = 0;
149
static int32 global_init_lock = -1;
150
static vint32 global_init_count = 0;
151
#endif
152
153
static xmlRMutexPtr xmlLibraryLock = NULL;
154
155
#ifdef LIBXML_THREAD_ENABLED
156
static void xmlOnceInit(void);
157
#endif
158
159
/**
160
 * xmlNewMutex:
161
 *
162
 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
163
 * synchronizing access to data.
164
 *
165
 * Returns a new simple mutex pointer or NULL in case of error
166
 */
167
xmlMutexPtr
168
xmlNewMutex(void)
169
3
{
170
3
    xmlMutexPtr tok;
171
172
3
    if ((tok = malloc(sizeof(xmlMutex))) == NULL)
173
0
        return (NULL);
174
3
#ifdef HAVE_PTHREAD_H
175
3
    if (libxml_is_threaded != 0)
176
3
        pthread_mutex_init(&tok->lock, NULL);
177
#elif defined HAVE_WIN32_THREADS
178
    InitializeCriticalSection(&tok->cs);
179
#elif defined HAVE_BEOS_THREADS
180
    if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
181
        free(tok);
182
        return NULL;
183
    }
184
    tok->tid = -1;
185
#endif
186
3
    return (tok);
187
3
}
188
189
/**
190
 * xmlFreeMutex:
191
 * @tok:  the simple mutex
192
 *
193
 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
194
 * struct.
195
 */
196
void
197
xmlFreeMutex(xmlMutexPtr tok)
198
0
{
199
0
    if (tok == NULL)
200
0
        return;
201
202
0
#ifdef HAVE_PTHREAD_H
203
0
    if (libxml_is_threaded != 0)
204
0
        pthread_mutex_destroy(&tok->lock);
205
#elif defined HAVE_WIN32_THREADS
206
    DeleteCriticalSection(&tok->cs);
207
#elif defined HAVE_BEOS_THREADS
208
    delete_sem(tok->sem);
209
#endif
210
0
    free(tok);
211
0
}
212
213
/**
214
 * xmlMutexLock:
215
 * @tok:  the simple mutex
216
 *
217
 * xmlMutexLock() is used to lock a libxml2 token.
218
 */
219
void
220
xmlMutexLock(xmlMutexPtr tok)
221
23.3k
{
222
23.3k
    if (tok == NULL)
223
0
        return;
224
23.3k
#ifdef HAVE_PTHREAD_H
225
23.3k
    if (libxml_is_threaded != 0)
226
23.3k
        pthread_mutex_lock(&tok->lock);
227
#elif defined HAVE_WIN32_THREADS
228
    EnterCriticalSection(&tok->cs);
229
#elif defined HAVE_BEOS_THREADS
230
    if (acquire_sem(tok->sem) != B_NO_ERROR) {
231
#ifdef DEBUG_THREADS
232
        xmlGenericError(xmlGenericErrorContext,
233
                        "xmlMutexLock():BeOS:Couldn't acquire semaphore\n");
234
#endif
235
    }
236
    tok->tid = find_thread(NULL);
237
#endif
238
239
23.3k
}
240
241
/**
242
 * xmlMutexUnlock:
243
 * @tok:  the simple mutex
244
 *
245
 * xmlMutexUnlock() is used to unlock a libxml2 token.
246
 */
247
void
248
xmlMutexUnlock(xmlMutexPtr tok)
249
23.3k
{
250
23.3k
    if (tok == NULL)
251
0
        return;
252
23.3k
#ifdef HAVE_PTHREAD_H
253
23.3k
    if (libxml_is_threaded != 0)
254
23.3k
        pthread_mutex_unlock(&tok->lock);
255
#elif defined HAVE_WIN32_THREADS
256
    LeaveCriticalSection(&tok->cs);
257
#elif defined HAVE_BEOS_THREADS
258
    if (tok->tid == find_thread(NULL)) {
259
        tok->tid = -1;
260
        release_sem(tok->sem);
261
    }
262
#endif
263
23.3k
}
264
265
/**
266
 * xmlNewRMutex:
267
 *
268
 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
269
 * synchronizing access to data. token_r is a re-entrant lock and thus useful
270
 * for synchronizing access to data structures that may be manipulated in a
271
 * recursive fashion.
272
 *
273
 * Returns the new reentrant mutex pointer or NULL in case of error
274
 */
275
xmlRMutexPtr
276
xmlNewRMutex(void)
277
1
{
278
1
    xmlRMutexPtr tok;
279
280
1
    if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
281
0
        return (NULL);
282
1
#ifdef HAVE_PTHREAD_H
283
1
    if (libxml_is_threaded != 0) {
284
1
        pthread_mutex_init(&tok->lock, NULL);
285
1
        tok->held = 0;
286
1
        tok->waiters = 0;
287
1
        pthread_cond_init(&tok->cv, NULL);
288
1
    }
289
#elif defined HAVE_WIN32_THREADS
290
    InitializeCriticalSection(&tok->cs);
291
#elif defined HAVE_BEOS_THREADS
292
    if ((tok->lock = xmlNewMutex()) == NULL) {
293
        free(tok);
294
        return NULL;
295
    }
296
    tok->count = 0;
297
#endif
298
1
    return (tok);
299
1
}
300
301
/**
302
 * xmlFreeRMutex:
303
 * @tok:  the reentrant mutex
304
 *
305
 * xmlRFreeMutex() is used to reclaim resources associated with a
306
 * reentrant mutex.
307
 */
308
void
309
xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
310
0
{
311
0
    if (tok == NULL)
312
0
        return;
313
0
#ifdef HAVE_PTHREAD_H
314
0
    if (libxml_is_threaded != 0) {
315
0
        pthread_mutex_destroy(&tok->lock);
316
0
        pthread_cond_destroy(&tok->cv);
317
0
    }
318
#elif defined HAVE_WIN32_THREADS
319
    DeleteCriticalSection(&tok->cs);
320
#elif defined HAVE_BEOS_THREADS
321
    xmlFreeMutex(tok->lock);
322
#endif
323
0
    free(tok);
324
0
}
325
326
/**
327
 * xmlRMutexLock:
328
 * @tok:  the reentrant mutex
329
 *
330
 * xmlRMutexLock() is used to lock a libxml2 token_r.
331
 */
332
void
333
xmlRMutexLock(xmlRMutexPtr tok)
334
1
{
335
1
    if (tok == NULL)
336
0
        return;
337
1
#ifdef HAVE_PTHREAD_H
338
1
    if (libxml_is_threaded == 0)
339
0
        return;
340
341
1
    pthread_mutex_lock(&tok->lock);
342
1
    if (tok->held) {
343
0
        if (pthread_equal(tok->tid, pthread_self())) {
344
0
            tok->held++;
345
0
            pthread_mutex_unlock(&tok->lock);
346
0
            return;
347
0
        } else {
348
0
            tok->waiters++;
349
0
            while (tok->held)
350
0
                pthread_cond_wait(&tok->cv, &tok->lock);
351
0
            tok->waiters--;
352
0
        }
353
0
    }
354
1
    tok->tid = pthread_self();
355
1
    tok->held = 1;
356
1
    pthread_mutex_unlock(&tok->lock);
357
#elif defined HAVE_WIN32_THREADS
358
    EnterCriticalSection(&tok->cs);
359
#elif defined HAVE_BEOS_THREADS
360
    if (tok->lock->tid == find_thread(NULL)) {
361
        tok->count++;
362
        return;
363
    } else {
364
        xmlMutexLock(tok->lock);
365
        tok->count = 1;
366
    }
367
#endif
368
1
}
369
370
/**
371
 * xmlRMutexUnlock:
372
 * @tok:  the reentrant mutex
373
 *
374
 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
375
 */
376
void
377
xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
378
1
{
379
1
    if (tok == NULL)
380
0
        return;
381
1
#ifdef HAVE_PTHREAD_H
382
1
    if (libxml_is_threaded == 0)
383
0
        return;
384
385
1
    pthread_mutex_lock(&tok->lock);
386
1
    tok->held--;
387
1
    if (tok->held == 0) {
388
1
        if (tok->waiters)
389
0
            pthread_cond_signal(&tok->cv);
390
1
        memset(&tok->tid, 0, sizeof(tok->tid));
391
1
    }
392
1
    pthread_mutex_unlock(&tok->lock);
393
#elif defined HAVE_WIN32_THREADS
394
    LeaveCriticalSection(&tok->cs);
395
#elif defined HAVE_BEOS_THREADS
396
    if (tok->lock->tid == find_thread(NULL)) {
397
        tok->count--;
398
        if (tok->count == 0) {
399
            xmlMutexUnlock(tok->lock);
400
        }
401
        return;
402
    }
403
#endif
404
1
}
405
406
/**
407
 * xmlGlobalInitMutexLock
408
 *
409
 * Makes sure that the global initialization mutex is initialized and
410
 * locks it.
411
 */
412
void
413
__xmlGlobalInitMutexLock(void)
414
1
{
415
    /* Make sure the global init lock is initialized and then lock it. */
416
1
#ifdef HAVE_PTHREAD_H
417
    /* The mutex is statically initialized, so we just lock it. */
418
1
#ifdef XML_PTHREAD_WEAK
419
1
    if (pthread_mutex_lock == NULL)
420
0
        return;
421
1
#endif /* XML_PTHREAD_WEAK */
422
1
    pthread_mutex_lock(&global_init_lock);
423
#elif defined HAVE_WIN32_THREADS
424
    LPCRITICAL_SECTION cs;
425
426
    /* Create a new critical section */
427
    if (global_init_lock == NULL) {
428
        cs = malloc(sizeof(CRITICAL_SECTION));
429
        if (cs == NULL) {
430
            xmlGenericError(xmlGenericErrorContext,
431
                            "xmlGlobalInitMutexLock: out of memory\n");
432
            return;
433
        }
434
        InitializeCriticalSection(cs);
435
436
        /* Swap it into the global_init_lock */
437
#ifdef InterlockedCompareExchangePointer
438
        InterlockedCompareExchangePointer((void **) &global_init_lock,
439
                                          cs, NULL);
440
#else /* Use older void* version */
441
        InterlockedCompareExchange((void **) &global_init_lock,
442
                                   (void *) cs, NULL);
443
#endif /* InterlockedCompareExchangePointer */
444
445
        /* If another thread successfully recorded its critical
446
         * section in the global_init_lock then discard the one
447
         * allocated by this thread. */
448
        if (global_init_lock != cs) {
449
            DeleteCriticalSection(cs);
450
            free(cs);
451
        }
452
    }
453
454
    /* Lock the chosen critical section */
455
    EnterCriticalSection(global_init_lock);
456
#elif defined HAVE_BEOS_THREADS
457
    int32 sem;
458
459
    /* Allocate a new semaphore */
460
    sem = create_sem(1, "xmlGlobalinitMutex");
461
462
    while (global_init_lock == -1) {
463
        if (atomic_add(&global_init_count, 1) == 0) {
464
            global_init_lock = sem;
465
        } else {
466
            snooze(1);
467
            atomic_add(&global_init_count, -1);
468
        }
469
    }
470
471
    /* If another thread successfully recorded its critical
472
     * section in the global_init_lock then discard the one
473
     * allocated by this thread. */
474
    if (global_init_lock != sem)
475
        delete_sem(sem);
476
477
    /* Acquire the chosen semaphore */
478
    if (acquire_sem(global_init_lock) != B_NO_ERROR) {
479
#ifdef DEBUG_THREADS
480
        xmlGenericError(xmlGenericErrorContext,
481
                        "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
482
#endif
483
    }
484
#endif
485
1
}
486
487
void
488
__xmlGlobalInitMutexUnlock(void)
489
1
{
490
1
#ifdef HAVE_PTHREAD_H
491
1
#ifdef XML_PTHREAD_WEAK
492
1
    if (pthread_mutex_unlock == NULL)
493
0
        return;
494
1
#endif /* XML_PTHREAD_WEAK */
495
1
    pthread_mutex_unlock(&global_init_lock);
496
#elif defined HAVE_WIN32_THREADS
497
    if (global_init_lock != NULL) {
498
  LeaveCriticalSection(global_init_lock);
499
    }
500
#elif defined HAVE_BEOS_THREADS
501
    release_sem(global_init_lock);
502
#endif
503
1
}
504
505
/**
506
 * xmlGlobalInitMutexDestroy
507
 *
508
 * Makes sure that the global initialization mutex is destroyed before
509
 * application termination.
510
 */
511
void
512
__xmlGlobalInitMutexDestroy(void)
513
0
{
514
0
#ifdef HAVE_PTHREAD_H
515
#elif defined HAVE_WIN32_THREADS
516
    if (global_init_lock != NULL) {
517
        DeleteCriticalSection(global_init_lock);
518
        free(global_init_lock);
519
        global_init_lock = NULL;
520
    }
521
#endif
522
0
}
523
524
/************************************************************************
525
 *                  *
526
 *      Per thread global state handling    *
527
 *                  *
528
 ************************************************************************/
529
530
#ifdef LIBXML_THREAD_ENABLED
531
#ifdef xmlLastError
532
#undef xmlLastError
533
#endif
534
535
/**
536
 * xmlFreeGlobalState:
537
 * @state:  a thread global state
538
 *
539
 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
540
 * global state. It is is used here to reclaim memory resources.
541
 */
542
static void
543
xmlFreeGlobalState(void *state)
544
0
{
545
0
    xmlGlobalState *gs = (xmlGlobalState *) state;
546
547
    /* free any memory allocated in the thread's xmlLastError */
548
0
    xmlResetError(&(gs->xmlLastError));
549
0
    free(state);
550
0
}
551
552
/**
553
 * xmlNewGlobalState:
554
 *
555
 * xmlNewGlobalState() allocates a global state. This structure is used to
556
 * hold all data for use by a thread when supporting backwards compatibility
557
 * of libxml2 to pre-thread-safe behaviour.
558
 *
559
 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
560
 */
561
static xmlGlobalStatePtr
562
xmlNewGlobalState(void)
563
0
{
564
0
    xmlGlobalState *gs;
565
566
0
    gs = malloc(sizeof(xmlGlobalState));
567
0
    if (gs == NULL) {
568
0
  xmlGenericError(xmlGenericErrorContext,
569
0
      "xmlGetGlobalState: out of memory\n");
570
0
        return (NULL);
571
0
    }
572
573
0
    memset(gs, 0, sizeof(xmlGlobalState));
574
0
    xmlInitializeGlobalState(gs);
575
0
    return (gs);
576
0
}
577
#endif /* LIBXML_THREAD_ENABLED */
578
579
#ifdef HAVE_PTHREAD_H
580
#elif defined HAVE_WIN32_THREADS
581
#if !defined(HAVE_COMPILER_TLS)
582
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
583
typedef struct _xmlGlobalStateCleanupHelperParams {
584
    HANDLE thread;
585
    void *memory;
586
} xmlGlobalStateCleanupHelperParams;
587
588
static void XMLCDECL
589
xmlGlobalStateCleanupHelper(void *p)
590
{
591
    xmlGlobalStateCleanupHelperParams *params =
592
        (xmlGlobalStateCleanupHelperParams *) p;
593
    WaitForSingleObject(params->thread, INFINITE);
594
    CloseHandle(params->thread);
595
    xmlFreeGlobalState(params->memory);
596
    free(params);
597
    _endthread();
598
}
599
#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
600
601
typedef struct _xmlGlobalStateCleanupHelperParams {
602
    void *memory;
603
    struct _xmlGlobalStateCleanupHelperParams *prev;
604
    struct _xmlGlobalStateCleanupHelperParams *next;
605
} xmlGlobalStateCleanupHelperParams;
606
607
static xmlGlobalStateCleanupHelperParams *cleanup_helpers_head = NULL;
608
static CRITICAL_SECTION cleanup_helpers_cs;
609
610
#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
611
#endif /* HAVE_COMPILER_TLS */
612
#endif /* HAVE_WIN32_THREADS */
613
614
#if defined HAVE_BEOS_THREADS
615
616
/**
617
 * xmlGlobalStateCleanup:
618
 * @data: unused parameter
619
 *
620
 * Used for Beos only
621
 */
622
void
623
xmlGlobalStateCleanup(void *data)
624
{
625
    void *globalval = tls_get(globalkey);
626
627
    if (globalval != NULL)
628
        xmlFreeGlobalState(globalval);
629
}
630
#endif
631
632
/**
633
 * xmlGetGlobalState:
634
 *
635
 * xmlGetGlobalState() is called to retrieve the global state for a thread.
636
 *
637
 * Returns the thread global state or NULL in case of error
638
 */
639
xmlGlobalStatePtr
640
xmlGetGlobalState(void)
641
0
{
642
0
#ifdef HAVE_PTHREAD_H
643
0
    xmlGlobalState *globalval;
644
645
0
    if (libxml_is_threaded == 0)
646
0
        return (NULL);
647
648
0
    pthread_once(&once_control, xmlOnceInit);
649
650
0
    if ((globalval = (xmlGlobalState *)
651
0
         pthread_getspecific(globalkey)) == NULL) {
652
0
        xmlGlobalState *tsd = xmlNewGlobalState();
653
0
  if (tsd == NULL)
654
0
      return(NULL);
655
656
0
        pthread_setspecific(globalkey, tsd);
657
0
        return (tsd);
658
0
    }
659
0
    return (globalval);
660
#elif defined HAVE_WIN32_THREADS
661
#if defined(HAVE_COMPILER_TLS)
662
    if (!tlstate_inited) {
663
        tlstate_inited = 1;
664
        xmlInitializeGlobalState(&tlstate);
665
    }
666
    return &tlstate;
667
#else /* HAVE_COMPILER_TLS */
668
    xmlGlobalState *globalval;
669
    xmlGlobalStateCleanupHelperParams *p;
670
671
    xmlOnceInit();
672
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
673
    globalval = (xmlGlobalState *) TlsGetValue(globalkey);
674
#else
675
    p = (xmlGlobalStateCleanupHelperParams *) TlsGetValue(globalkey);
676
    globalval = (xmlGlobalState *) (p ? p->memory : NULL);
677
#endif
678
    if (globalval == NULL) {
679
        xmlGlobalState *tsd = xmlNewGlobalState();
680
681
        if (tsd == NULL)
682
      return(NULL);
683
        p = (xmlGlobalStateCleanupHelperParams *)
684
            malloc(sizeof(xmlGlobalStateCleanupHelperParams));
685
  if (p == NULL) {
686
            xmlGenericError(xmlGenericErrorContext,
687
                            "xmlGetGlobalState: out of memory\n");
688
            xmlFreeGlobalState(tsd);
689
      return(NULL);
690
  }
691
        p->memory = tsd;
692
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
693
        DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
694
                        GetCurrentProcess(), &p->thread, 0, TRUE,
695
                        DUPLICATE_SAME_ACCESS);
696
        TlsSetValue(globalkey, tsd);
697
        _beginthread(xmlGlobalStateCleanupHelper, 0, p);
698
#else
699
        EnterCriticalSection(&cleanup_helpers_cs);
700
        if (cleanup_helpers_head != NULL) {
701
            cleanup_helpers_head->prev = p;
702
        }
703
        p->next = cleanup_helpers_head;
704
        p->prev = NULL;
705
        cleanup_helpers_head = p;
706
        TlsSetValue(globalkey, p);
707
        LeaveCriticalSection(&cleanup_helpers_cs);
708
#endif
709
710
        return (tsd);
711
    }
712
    return (globalval);
713
#endif /* HAVE_COMPILER_TLS */
714
#elif defined HAVE_BEOS_THREADS
715
    xmlGlobalState *globalval;
716
717
    xmlOnceInit();
718
719
    if ((globalval = (xmlGlobalState *) tls_get(globalkey)) == NULL) {
720
        xmlGlobalState *tsd = xmlNewGlobalState();
721
  if (tsd == NULL)
722
      return (NULL);
723
724
        tls_set(globalkey, tsd);
725
        on_exit_thread(xmlGlobalStateCleanup, NULL);
726
        return (tsd);
727
    }
728
    return (globalval);
729
#else
730
    return (NULL);
731
#endif
732
0
}
733
734
/************************************************************************
735
 *                  *
736
 *      Library wide thread interfaces      *
737
 *                  *
738
 ************************************************************************/
739
740
/**
741
 * xmlGetThreadId:
742
 *
743
 * xmlGetThreadId() find the current thread ID number
744
 * Note that this is likely to be broken on some platforms using pthreads
745
 * as the specification doesn't mandate pthread_t to be an integer type
746
 *
747
 * Returns the current thread ID number
748
 */
749
int
750
xmlGetThreadId(void)
751
0
{
752
0
#ifdef HAVE_PTHREAD_H
753
0
    pthread_t id;
754
0
    int ret;
755
756
0
    if (libxml_is_threaded == 0)
757
0
        return (0);
758
0
    id = pthread_self();
759
    /* horrible but preserves compat, see warning above */
760
0
    memcpy(&ret, &id, sizeof(ret));
761
0
    return (ret);
762
#elif defined HAVE_WIN32_THREADS
763
    return GetCurrentThreadId();
764
#elif defined HAVE_BEOS_THREADS
765
    return find_thread(NULL);
766
#else
767
    return ((int) 0);
768
#endif
769
0
}
770
771
/**
772
 * xmlIsMainThread:
773
 *
774
 * xmlIsMainThread() check whether the current thread is the main thread.
775
 *
776
 * Returns 1 if the current thread is the main thread, 0 otherwise
777
 */
778
int
779
xmlIsMainThread(void)
780
6.93M
{
781
6.93M
#ifdef HAVE_PTHREAD_H
782
6.93M
    if (libxml_is_threaded == -1)
783
0
        xmlInitThreads();
784
6.93M
    if (libxml_is_threaded == 0)
785
0
        return (1);
786
6.93M
    pthread_once(&once_control, xmlOnceInit);
787
#elif defined HAVE_WIN32_THREADS
788
    xmlOnceInit();
789
#elif defined HAVE_BEOS_THREADS
790
    xmlOnceInit();
791
#endif
792
793
#ifdef DEBUG_THREADS
794
    xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
795
#endif
796
6.93M
#ifdef HAVE_PTHREAD_H
797
6.93M
    return (pthread_equal(mainthread,pthread_self()));
798
#elif defined HAVE_WIN32_THREADS
799
    return (mainthread == GetCurrentThreadId());
800
#elif defined HAVE_BEOS_THREADS
801
    return (mainthread == find_thread(NULL));
802
#else
803
    return (1);
804
#endif
805
6.93M
}
806
807
/**
808
 * xmlLockLibrary:
809
 *
810
 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
811
 * library.
812
 */
813
void
814
xmlLockLibrary(void)
815
0
{
816
#ifdef DEBUG_THREADS
817
    xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
818
#endif
819
0
    xmlRMutexLock(xmlLibraryLock);
820
0
}
821
822
/**
823
 * xmlUnlockLibrary:
824
 *
825
 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
826
 * library.
827
 */
828
void
829
xmlUnlockLibrary(void)
830
0
{
831
#ifdef DEBUG_THREADS
832
    xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
833
#endif
834
0
    xmlRMutexUnlock(xmlLibraryLock);
835
0
}
836
837
/**
838
 * xmlInitThreads:
839
 *
840
 * DEPRECATED: This function will be made private. Call xmlInitParser to
841
 * initialize the library.
842
 *
843
 * xmlInitThreads() is used to to initialize all the thread related
844
 * data of the libxml2 library.
845
 */
846
void
847
xmlInitThreads(void)
848
1
{
849
1
#ifdef HAVE_PTHREAD_H
850
1
#ifdef XML_PTHREAD_WEAK
851
1
    if (libxml_is_threaded == -1) {
852
1
        if ((pthread_once != NULL) &&
853
1
            (pthread_getspecific != NULL) &&
854
1
            (pthread_setspecific != NULL) &&
855
1
            (pthread_key_create != NULL) &&
856
1
            (pthread_key_delete != NULL) &&
857
1
            (pthread_mutex_init != NULL) &&
858
1
            (pthread_mutex_destroy != NULL) &&
859
1
            (pthread_mutex_lock != NULL) &&
860
1
            (pthread_mutex_unlock != NULL) &&
861
1
            (pthread_cond_init != NULL) &&
862
1
            (pthread_cond_destroy != NULL) &&
863
1
            (pthread_cond_wait != NULL) &&
864
1
            (pthread_equal != NULL) &&
865
1
            (pthread_self != NULL) &&
866
1
            (pthread_cond_signal != NULL)) {
867
1
            libxml_is_threaded = 1;
868
869
/* fprintf(stderr, "Running multithreaded\n"); */
870
1
        } else {
871
872
/* fprintf(stderr, "Running without multithread\n"); */
873
0
            libxml_is_threaded = 0;
874
0
        }
875
1
    }
876
1
#endif /* XML_PTHREAD_WEAK */
877
1
#endif
878
1
}
879
880
/**
881
 * xmlCleanupThreads:
882
 *
883
 * DEPRECATED: This function will be made private. Call xmlCleanupParser
884
 * to free global state but see the warnings there. xmlCleanupParser
885
 * should be only called once at program exit. In most cases, you don't
886
 * have call cleanup functions at all.
887
 *
888
 * xmlCleanupThreads() is used to to cleanup all the thread related
889
 * data of the libxml2 library once processing has ended.
890
 *
891
 * WARNING: if your application is multithreaded or has plugin support
892
 *          calling this may crash the application if another thread or
893
 *          a plugin is still using libxml2. It's sometimes very hard to
894
 *          guess if libxml2 is in use in the application, some libraries
895
 *          or plugins may use it without notice. In case of doubt abstain
896
 *          from calling this function or do it just before calling exit()
897
 *          to avoid leak reports from valgrind !
898
 */
899
void
900
xmlCleanupThreads(void)
901
0
{
902
#ifdef DEBUG_THREADS
903
    xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
904
#endif
905
0
#ifdef HAVE_PTHREAD_H
906
0
    if (libxml_is_threaded != 0)
907
0
        pthread_key_delete(globalkey);
908
0
    once_control = once_control_init;
909
#elif defined(HAVE_WIN32_THREADS)
910
#if !defined(HAVE_COMPILER_TLS)
911
    if (globalkey != TLS_OUT_OF_INDEXES) {
912
#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
913
        xmlGlobalStateCleanupHelperParams *p;
914
915
        EnterCriticalSection(&cleanup_helpers_cs);
916
        p = cleanup_helpers_head;
917
        while (p != NULL) {
918
            xmlGlobalStateCleanupHelperParams *temp = p;
919
920
            p = p->next;
921
            xmlFreeGlobalState(temp->memory);
922
            free(temp);
923
        }
924
        cleanup_helpers_head = 0;
925
        LeaveCriticalSection(&cleanup_helpers_cs);
926
#endif
927
        TlsFree(globalkey);
928
        globalkey = TLS_OUT_OF_INDEXES;
929
    }
930
#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
931
    DeleteCriticalSection(&cleanup_helpers_cs);
932
#endif
933
#endif
934
    run_once.done = 0;
935
    run_once.control = 0;
936
#endif
937
0
}
938
939
#ifdef LIBXML_THREAD_ENABLED
940
941
/**
942
 * xmlOnceInit
943
 *
944
 * xmlOnceInit() is used to initialize the value of mainthread for use
945
 * in other routines. This function should only be called using
946
 * pthread_once() in association with the once_control variable to ensure
947
 * that the function is only called once. See man pthread_once for more
948
 * details.
949
 */
950
static void
951
xmlOnceInit(void)
952
1
{
953
1
#ifdef HAVE_PTHREAD_H
954
1
    (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
955
1
    mainthread = pthread_self();
956
1
    __xmlInitializeDict();
957
#elif defined(HAVE_WIN32_THREADS)
958
    if (!run_once.done) {
959
        if (InterlockedIncrement(&run_once.control) == 1) {
960
#if !defined(HAVE_COMPILER_TLS)
961
#if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
962
            InitializeCriticalSection(&cleanup_helpers_cs);
963
#endif
964
            globalkey = TlsAlloc();
965
#endif
966
            mainthread = GetCurrentThreadId();
967
      __xmlInitializeDict();
968
            run_once.done = 1;
969
        } else {
970
            /* Another thread is working; give up our slice and
971
             * wait until they're done. */
972
            while (!run_once.done)
973
                Sleep(0);
974
        }
975
    }
976
#elif defined HAVE_BEOS_THREADS
977
    if (atomic_add(&run_once_init, 1) == 0) {
978
        globalkey = tls_allocate();
979
        tls_set(globalkey, NULL);
980
        mainthread = find_thread(NULL);
981
  __xmlInitializeDict();
982
    } else
983
        atomic_add(&run_once_init, -1);
984
#endif
985
1
}
986
#endif
987
988
/**
989
 * DllMain:
990
 * @hinstDLL: handle to DLL instance
991
 * @fdwReason: Reason code for entry
992
 * @lpvReserved: generic pointer (depends upon reason code)
993
 *
994
 * Entry point for Windows library. It is being used to free thread-specific
995
 * storage.
996
 *
997
 * Returns TRUE always
998
 */
999
#ifdef HAVE_PTHREAD_H
1000
#elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
1001
#if defined(LIBXML_STATIC_FOR_DLL)
1002
int XMLCALL
1003
xmlDllMain(ATTRIBUTE_UNUSED void *hinstDLL, unsigned long fdwReason,
1004
           ATTRIBUTE_UNUSED void *lpvReserved)
1005
#else
1006
/* declare to avoid "no previous prototype for 'DllMain'" warning */
1007
/* Note that we do NOT want to include this function declaration in
1008
   a public header because it's meant to be called by Windows itself,
1009
   not a program that uses this library.  This also has to be exported. */
1010
1011
XMLPUBFUN BOOL WINAPI
1012
DllMain (HINSTANCE hinstDLL,
1013
         DWORD     fdwReason,
1014
         LPVOID    lpvReserved);
1015
1016
BOOL WINAPI
1017
DllMain(ATTRIBUTE_UNUSED HINSTANCE hinstDLL, DWORD fdwReason,
1018
        ATTRIBUTE_UNUSED LPVOID lpvReserved)
1019
#endif
1020
{
1021
    switch (fdwReason) {
1022
        case DLL_THREAD_DETACH:
1023
            if (globalkey != TLS_OUT_OF_INDEXES) {
1024
                xmlGlobalState *globalval = NULL;
1025
                xmlGlobalStateCleanupHelperParams *p =
1026
                    (xmlGlobalStateCleanupHelperParams *)
1027
                    TlsGetValue(globalkey);
1028
                globalval = (xmlGlobalState *) (p ? p->memory : NULL);
1029
                if (globalval) {
1030
                    xmlFreeGlobalState(globalval);
1031
                    TlsSetValue(globalkey, NULL);
1032
                }
1033
                if (p) {
1034
                    EnterCriticalSection(&cleanup_helpers_cs);
1035
                    if (p == cleanup_helpers_head)
1036
                        cleanup_helpers_head = p->next;
1037
                    else
1038
                        p->prev->next = p->next;
1039
                    if (p->next != NULL)
1040
                        p->next->prev = p->prev;
1041
                    LeaveCriticalSection(&cleanup_helpers_cs);
1042
                    free(p);
1043
                }
1044
            }
1045
            break;
1046
    }
1047
    return TRUE;
1048
}
1049
#endif