2 * threads.c: set of generic threading related routines
4 * See Copyright for the status of this software.
6 * Gary Pennington <Gary.Pennington@uk.sun.com>
15 #include <libxml/threads.h>
16 #include <libxml/globals.h>
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
31 #ifdef HAVE_WIN32_THREADS
33 #ifndef HAVE_COMPILER_TLS
42 /* #define DEBUG_THREADS */
45 * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
46 * to avoid some crazyness since xmlMalloc/xmlFree may actually
47 * be hosted on allocated blocks needing them for the allocation ...
51 * xmlMutex are a simple mutual exception locks
56 #elif defined HAVE_WIN32_THREADS
64 * xmlRMutex are reentrant mutual exception locks
73 #elif defined HAVE_WIN32_THREADS
81 * This module still has some internal static data.
82 * - xmlLibraryLock a global lock
83 * - globalkey used for per-thread data
87 static pthread_key_t globalkey;
88 static pthread_t mainthread;
89 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
90 #elif defined HAVE_WIN32_THREADS
91 #if defined(HAVE_COMPILER_TLS)
92 static __declspec(thread) xmlGlobalState tlstate;
93 static __declspec(thread) int tlstate_inited = 0;
94 #else /* HAVE_COMPILER_TLS */
95 static DWORD globalkey = TLS_OUT_OF_INDEXES;
96 #endif /* HAVE_COMPILER_TLS */
97 static DWORD mainthread;
98 static int run_once_init = 1;
99 #endif /* HAVE_WIN32_THREADS */
101 static xmlRMutexPtr xmlLibraryLock = NULL;
102 static void xmlOnceInit(void);
107 * xmlNewMutex() is used to allocate a libxml2 token struct for use in
108 * synchronizing access to data.
110 * Returns a new simple mutex pointer or NULL in case of error
117 if ((tok = malloc(sizeof(xmlMutex))) == NULL)
119 #ifdef HAVE_PTHREAD_H
120 pthread_mutex_init(&tok->lock, NULL);
121 #elif defined HAVE_WIN32_THREADS
122 tok->mutex = CreateMutex(NULL, FALSE, NULL);
129 * @tok: the simple mutex
131 * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
135 xmlFreeMutex(xmlMutexPtr tok)
137 if (tok == NULL) return;
139 #ifdef HAVE_PTHREAD_H
140 pthread_mutex_destroy(&tok->lock);
141 #elif defined HAVE_WIN32_THREADS
142 CloseHandle(tok->mutex);
149 * @tok: the simple mutex
151 * xmlMutexLock() is used to lock a libxml2 token.
154 xmlMutexLock(xmlMutexPtr tok)
158 #ifdef HAVE_PTHREAD_H
159 pthread_mutex_lock(&tok->lock);
160 #elif defined HAVE_WIN32_THREADS
161 WaitForSingleObject(tok->mutex, INFINITE);
168 * @tok: the simple mutex
170 * xmlMutexUnlock() is used to unlock a libxml2 token.
173 xmlMutexUnlock(xmlMutexPtr tok ATTRIBUTE_UNUSED)
175 #ifdef HAVE_PTHREAD_H
176 pthread_mutex_unlock(&tok->lock);
177 #elif defined HAVE_WIN32_THREADS
178 ReleaseMutex(tok->mutex);
185 * xmlRNewMutex() is used to allocate a reentrant mutex for use in
186 * synchronizing access to data. token_r is a re-entrant lock and thus useful
187 * for synchronizing access to data structures that may be manipulated in a
190 * Returns the new reentrant mutex pointer or NULL in case of error
197 if ((tok = malloc(sizeof(xmlRMutex))) == NULL)
199 #ifdef HAVE_PTHREAD_H
200 pthread_mutex_init(&tok->lock, NULL);
203 pthread_cond_init(&tok->cv, NULL);
204 #elif defined HAVE_WIN32_THREADS
205 InitializeCriticalSection(&tok->cs);
213 * @tok: the reentrant mutex
215 * xmlRFreeMutex() is used to reclaim resources associated with a
219 xmlFreeRMutex(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
221 #ifdef HAVE_PTHREAD_H
222 pthread_mutex_destroy(&tok->lock);
223 #elif defined HAVE_WIN32_THREADS
224 DeleteCriticalSection(&tok->cs);
231 * @tok: the reentrant mutex
233 * xmlRMutexLock() is used to lock a libxml2 token_r.
236 xmlRMutexLock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
238 #ifdef HAVE_PTHREAD_H
239 pthread_mutex_lock(&tok->lock);
241 if (pthread_equal(tok->tid, pthread_self())) {
243 pthread_mutex_unlock(&tok->lock);
248 pthread_cond_wait(&tok->cv, &tok->lock);
252 tok->tid = pthread_self();
254 pthread_mutex_unlock(&tok->lock);
255 #elif defined HAVE_WIN32_THREADS
256 EnterCriticalSection(&tok->cs);
263 * @tok: the reentrant mutex
265 * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
268 xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBUTE_UNUSED)
270 #ifdef HAVE_PTHREAD_H
271 pthread_mutex_lock(&tok->lock);
273 if (tok->held == 0) {
275 pthread_cond_signal(&tok->cv);
278 pthread_mutex_unlock(&tok->lock);
279 #elif defined HAVE_WIN32_THREADS
281 LeaveCriticalSection(&tok->cs);
285 /************************************************************************
287 * Per thread global state handling *
289 ************************************************************************/
291 #ifdef LIBXML_THREAD_ENABLED
293 * xmlFreeGlobalState:
294 * @state: a thread global state
296 * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
297 * global state. It is is used here to reclaim memory resources.
300 xmlFreeGlobalState(void *state)
308 * xmlNewGlobalState() allocates a global state. This structure is used to
309 * hold all data for use by a thread when supporting backwards compatibility
310 * of libxml2 to pre-thread-safe behaviour.
312 * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
314 static xmlGlobalStatePtr
315 xmlNewGlobalState(void)
319 gs = malloc(sizeof(xmlGlobalState));
323 memset(gs, 0, sizeof(xmlGlobalState));
324 xmlInitializeGlobalState(gs);
327 #endif /* LIBXML_THREAD_ENABLED */
330 #ifdef HAVE_WIN32_THREADS
331 #if !defined(HAVE_COMPILER_TLS) && defined(LIBXML_STATIC)
332 typedef struct _xmlGlobalStateCleanupHelperParams
336 } xmlGlobalStateCleanupHelperParams;
338 static void xmlGlobalStateCleanupHelper (void *p)
340 xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
341 WaitForSingleObject(params->thread, INFINITE);
342 CloseHandle(params->thread);
343 xmlFreeGlobalState(params->memory);
347 #endif /* HAVE_COMPILER_TLS && LIBXML_STATIC */
348 #endif /* HAVE_WIN32_THREADS */
353 * xmlGetGlobalState() is called to retrieve the global state for a thread.
355 * Returns the thread global state or NULL in case of error
358 xmlGetGlobalState(void)
360 #ifdef HAVE_PTHREAD_H
361 xmlGlobalState *globalval;
363 pthread_once(&once_control, xmlOnceInit);
365 if ((globalval = (xmlGlobalState *)
366 pthread_getspecific(globalkey)) == NULL) {
367 xmlGlobalState *tsd = xmlNewGlobalState();
369 pthread_setspecific(globalkey, tsd);
373 #elif defined HAVE_WIN32_THREADS
374 #if defined(HAVE_COMPILER_TLS)
375 if (!tlstate_inited) {
377 xmlInitializeGlobalState(&tlstate);
380 #else /* HAVE_COMPILER_TLS */
381 xmlGlobalState *globalval;
387 if ((globalval = (xmlGlobalState *) TlsGetValue(globalkey)) == NULL) {
388 xmlGlobalState *tsd = xmlNewGlobalState();
389 #if defined(LIBXML_STATIC)
390 xmlGlobalStateCleanupHelperParams *p =
391 (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
393 DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
394 GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
396 TlsSetValue(globalkey, tsd);
397 #if defined(LIBXML_STATIC)
398 _beginthread(xmlGlobalStateCleanupHelper, 0, p);
404 #endif /* HAVE_COMPILER_TLS */
410 /************************************************************************
412 * Library wide thread interfaces *
414 ************************************************************************/
419 * xmlGetThreadId() find the current thread ID number
421 * Returns the current thread ID number
426 #ifdef HAVE_PTHREAD_H
427 return((int) pthread_self());
428 #elif defined HAVE_WIN32_THREADS
429 return GetCurrentThreadId();
438 * xmlIsMainThread() check whether the current thread is the main thread.
440 * Returns 1 if the current thread is the main thread, 0 otherwise
443 xmlIsMainThread(void)
445 #ifdef HAVE_PTHREAD_H
446 pthread_once(&once_control, xmlOnceInit);
447 #elif defined HAVE_WIN32_THREADS
455 xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
457 #ifdef HAVE_PTHREAD_H
458 return(mainthread == pthread_self());
459 #elif defined HAVE_WIN32_THREADS
460 return(mainthread == GetCurrentThreadId ());
469 * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
476 xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
478 xmlRMutexLock(xmlLibraryLock);
484 * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
488 xmlUnlockLibrary(void)
491 xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
493 xmlRMutexUnlock(xmlLibraryLock);
499 * xmlInitThreads() is used to to initialize all the thread related
500 * data of the libxml2 library.
506 xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
513 * xmlCleanupThreads() is used to to cleanup all the thread related
514 * data of the libxml2 library once processing has ended.
517 xmlCleanupThreads(void)
520 xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
527 * xmlOnceInit() is used to initialize the value of mainthread for use
528 * in other routines. This function should only be called using
529 * pthread_once() in association with the once_control variable to ensure
530 * that the function is only called once. See man pthread_once for more
535 #ifdef HAVE_PTHREAD_H
536 (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
537 mainthread = pthread_self();
540 #if defined(HAVE_WIN32_THREADS)
541 #if !defined(HAVE_COMPILER_TLS)
542 globalkey = TlsAlloc();
544 mainthread = GetCurrentThreadId();
551 * Entry point for Windows library. It is being used to free thread-specific
554 #if defined(HAVE_WIN32_THREADS) && !defined(LIBXML_STATIC)
555 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
558 case DLL_THREAD_DETACH:
559 if (globalkey != TLS_OUT_OF_INDEXES) {
560 xmlGlobalState *globalval = (xmlGlobalState *)TlsGetValue(globalkey);
562 xmlFreeGlobalState(globalval);
563 TlsSetValue(globalkey, NULL);
567 case DLL_PROCESS_DETACH:
568 if (globalkey != TLS_OUT_OF_INDEXES) {
570 globalkey = TLS_OUT_OF_INDEXES;