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