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