diff options
author | Daniel Veillard <veillard@src.gnome.org> | 2001-10-12 17:29:10 +0000 |
---|---|---|
committer | Daniel Veillard <veillard@src.gnome.org> | 2001-10-12 17:29:10 +0000 |
commit | b847864fc2f7151c81e57d02ca3b523dc5d8cf72 (patch) | |
tree | 952b35d54d60dca532e75a840dff82592201b193 /threads.c | |
parent | b44025c72b7472971a061b022cfe422adc42715d (diff) | |
download | libxml2-b847864fc2f7151c81e57d02ca3b523dc5d8cf72.tar.gz |
started integrating the core of the thread support not activated yet but
* Makefile.am include/libxml/Makefile.am
include/libxml/globals.h globals.c include/libxml/threads.h
threads.c build_glob.py global.data xmlcatalog.c acconfig.h
configure.in: started integrating the core of the thread support
not activated yet but half integrated. The code should still
compile and work anyway.
Daniel
Diffstat (limited to 'threads.c')
-rw-r--r-- | threads.c | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/threads.c b/threads.c new file mode 100644 index 00000000..9b0a3464 --- /dev/null +++ b/threads.c @@ -0,0 +1,372 @@ +/** + * threads.c: set of generic threading related routines + * + * See Copyright for the status of this software. + * + * Gary Pennington <Gary.Pennington@uk.sun.com> + * daniel@veillard.com + */ + +#include "libxml.h" + +#include <string.h> + +#include <libxml/threads.h> +#include <libxml/globals.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#endif + +#if defined(SOLARIS) +#include <note.h> +#endif + + +/* + * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree + * to avoid some crazyness since xmlMalloc/xmlFree may actually + * be hosted on allocated blocks needing them for the allocation ... + */ + +/* + * xmlMutex are a simple mutual exception locks + */ +struct _xmlMutex { +#ifdef HAVE_PTHREAD_H + pthread_mutex_t lock; +#else + int empty; +#endif +}; + +/* + * xmlRMutex are reentrant mutual exception locks + */ +struct _xmlRMutex { +#ifdef HAVE_PTHREAD_H + pthread_mutex_t lock; + unsigned int held; + unsigned int waiters; + pthread_t tid; + pthread_cond_t cv; +#else + int empty; +#endif +}; +/* + * This module still has some internal static data. + * - xmlLibraryLock a global lock + * - globalkey used for per-thread data + * - keylock protecting globalkey + * - keyonce to mark initialization of globalkey + */ +#ifdef HAVE_PTHREAD_H +static pthread_mutex_t keylock; +static pthread_key_t globalkey; +static int keyonce = 0; +#endif +static xmlRMutexPtr xmlLibraryLock = NULL; + +#if defined(SOLARIS) +NOTE(DATA_READABLE_WITHOUT_LOCK(keyonce)) +#endif + +/** + * xmlMutexPtr: + * + * xmlNewMutex() is used to allocate a libxml2 token struct for use in + * synchronizing access to data. + * + * Returns a new simple mutex pointer or NULL in case of error + */ +xmlMutexPtr +xmlNewMutex(void) +{ + xmlMutexPtr tok; + + if ((tok = malloc(sizeof(xmlMutex))) == NULL) + return (NULL); +#ifdef HAVE_PTHREAD_H + pthread_mutex_init(&tok->lock, NULL); +#endif + return (tok); +} + +/** + * xmlFreeMutex: + * @tok: the simple mutex + * + * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token + * struct. + */ +void +xmlFreeMutex(xmlMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_destroy(&tok->lock); +#endif + free(tok); +} + +/** + * xmlMutexLock: + * @tok: the simple mutex + * + * xmlMutexLock() is used to lock a libxml2 token. + */ +void +xmlMutexLock(xmlMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_lock(&tok->lock); +#endif + +} + +/** + * xmlMutexUnlock: + * @tok: the simple mutex + * + * xmlMutexUnlock() is used to unlock a libxml2 token. + */ +void +xmlMutexUnlock(xmlMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_unlock(&tok->lock); +#endif +} + +/** + * xmlRNewMutex: + * + * xmlRNewMutex() is used to allocate a reentrant mutex for use in + * synchronizing access to data. token_r is a re-entrant lock and thus useful + * for synchronizing access to data structures that may be manipulated in a + * recursive fashion. + * + * Returns the new reentrant mutex pointer or NULL in case of error + */ +xmlRMutexPtr +xmlNewRMutex(void) +{ + xmlRMutexPtr tok; + + if ((tok = malloc(sizeof(xmlRMutex))) == NULL) + return (NULL); +#ifdef HAVE_PTHREAD_H + pthread_mutex_init(&tok->lock, NULL); + tok->held = 0; + tok->waiters = 0; +#endif + return (tok); +} + +/** + * xmlRFreeMutex: + * @tok: the reentrant mutex + * + * xmlRFreeMutex() is used to reclaim resources associated with a + * reentrant mutex. + */ +void +xmlFreeRMutex(xmlRMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_destroy(&tok->lock); +#endif + free(tok); +} + +/** + * xmlRMutexLock: + * @tok: the reentrant mutex + * + * xmlRMutexLock() is used to lock a libxml2 token_r. + */ +void +xmlRMutexLock(xmlRMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_lock(&tok->lock); + if (tok->held) { + if (pthread_equal(tok->tid, pthread_self())) { + tok->held++; + pthread_mutex_unlock(&tok->lock); + return; + } else { + tok->waiters++; + while (tok->held) + pthread_cond_wait(&tok->cv, &tok->lock); + tok->waiters--; + } + } + tok->tid = pthread_self(); + tok->held = 1; + pthread_mutex_unlock(&tok->lock); +#endif +} + +/** + * xmlRMutexUnlock: + * @tok: the reentrant mutex + * + * xmlRMutexUnlock() is used to unlock a libxml2 token_r. + */ +void +xmlRMutexUnlock(xmlRMutexPtr tok) +{ +#ifdef HAVE_PTHREAD_H + pthread_mutex_lock(&tok->lock); + tok->held--; + if (tok->held == 0) { + if (tok->waiters) + pthread_cond_signal(&tok->cv); + tok->tid = 0; + } + pthread_mutex_unlock(&tok->lock); +#endif +} + +/************************************************************************ + * * + * Per thread global state handling * + * * + ************************************************************************/ + +/** + * xmlFreeGlobalState: + * @state: a thread global state + * + * xmlFreeGlobalState() is called when a thread terminates with a non-NULL + * global state. It is is used here to reclaim memory resources. + */ +static void +xmlFreeGlobalState(void *state) +{ + free(state); +} + +/** + * xmlNewGlobalState: + * + * xmlNewGlobalState() allocates a global state. This structure is used to + * hold all data for use by a thread when supporting backwards compatibility + * of libmxml2 to pre-thread-safe behaviour. + * + * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error + */ +static xmlGlobalStatePtr +xmlNewGlobalState(void) +{ + xmlGlobalState *gs; + + gs = malloc(sizeof(xmlGlobalState)); + if (gs == NULL) + return(NULL); + + memset(gs, 0, sizeof(gs)); + xmlInitializeGlobalState(gs); + return (gs); +} + + +/** + * xmlGetGlobalState: + * + * xmlGetGlobalState() is called to retrieve the global state for a thread. + * keyonce will only be set once during a library invocation and is used + * to create globalkey, the key used to store each thread's TSD. + * + * Note: it should not be called for the "main" thread as this thread uses + * the existing global variables defined in the library. + * + * Returns the thread global state or NULL in case of error + */ +xmlGlobalStatePtr +xmlGetGlobalState(void) +{ +#ifdef HAVE_PTHREAD_H + xmlGlobalState *globalval; + + if (keyonce == 0) { + (void) pthread_mutex_lock(&keylock); + if (keyonce == 0) { + keyonce++; + (void) pthread_key_create(&globalkey, xmlFreeGlobalState); + } + (void) pthread_mutex_unlock(&keylock); + } + if ((globalval = (xmlGlobalState *) + pthread_getspecific(globalkey)) == NULL) { + xmlGlobalState *tsd = xmlNewGlobalState(); + + pthread_setspecific(globalkey, tsd); + return (tsd); + } else + return (globalval); +#endif +} + + +/************************************************************************ + * * + * Library wide thread interfaces * + * * + ************************************************************************/ + +/** + * xmlLockLibrary: + * + * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2 + * library. + */ +void +xmlLockLibrary(void) +{ + xmlRMutexLock(xmlLibraryLock); +} + +/** + * xmlUnlockLibrary: + * + * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2 + * library. + */ +void +xmlUnlockLibrary(void) +{ + xmlRMutexUnlock(xmlLibraryLock); +} + +/** + * xmlInitThreads: + * + * xmlInitThreads() is used to to initialize all the thread related + * data of the libxml2 library. + */ +void +xmlInitThreads(void) +{ +} + +/** + * xmlCleanupThreads: + * + * xmlCleanupThreads() is used to to cleanup all the thread related + * data of the libxml2 library once processing has ended. + */ +void +xmlCleanupThreads(void) +{ +} |