/**
* 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
*/
#define IN_LIBXML
#include "libxml.h"
#include <string.h>
#ifdef HAVE_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
#ifdef HAVE_WIN32_THREADS
#include <windows.h>
#ifndef HAVE_COMPILER_TLS
#include <process.h>
#endif
#endif
#ifdef HAVE_BEOS_THREADS
#include <OS.h>
#include <TLS.h>
#endif
#if defined(SOLARIS)
#include <note.h>
#endif
/* #define DEBUG_THREADS */
#ifdef HAVE_PTHREAD_H
#ifdef __GNUC__
#ifdef linux
void (*__init_routine) (void))
__attribute((weak));
__attribute((weak));
__attribute((weak));
void (*__destr_function) (void *))
__attribute((weak));
extern int pthread_mutex_init ()
__attribute((weak));
extern int pthread_mutex_destroy ()
__attribute((weak));
extern int pthread_mutex_lock ()
__attribute((weak));
extern int pthread_mutex_unlock ()
__attribute((weak));
extern int pthread_cond_init ()
__attribute((weak));
extern int pthread_equal ()
__attribute((weak));
extern pthread_t pthread_self ()
__attribute((weak));
extern int pthread_key_create ()
__attribute((weak));
extern int pthread_cond_signal ()
__attribute((weak));
#endif
#endif /* linux */
#endif /* __GNUC__ */
#endif /* HAVE_PTHREAD_H */
/*
* be hosted on allocated blocks needing them for the allocation ...
*/
/*
* xmlMutex are a simple mutual exception locks
*/
struct _xmlMutex {
#ifdef HAVE_PTHREAD_H
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
#else
int empty;
#endif
};
/*
* xmlRMutex are reentrant mutual exception locks
*/
struct _xmlRMutex {
#ifdef HAVE_PTHREAD_H
unsigned int held;
unsigned int waiters;
#elif defined HAVE_WIN32_THREADS
unsigned int count;
#elif defined HAVE_BEOS_THREADS
#else
int empty;
#endif
};
/*
* This module still has some internal static data.
* - xmlLibraryLock a global lock
* - globalkey used for per-thread data
*/
#ifdef HAVE_PTHREAD_H
#elif defined HAVE_WIN32_THREADS
#if defined(HAVE_COMPILER_TLS)
#else /* HAVE_COMPILER_TLS */
#endif /* HAVE_COMPILER_TLS */
static struct
{
} run_once = { 0, 0 };
/* endif HAVE_WIN32_THREADS */
#elif defined HAVE_BEOS_THREADS
#endif
#ifdef LIBXML_THREAD_ENABLED
static void xmlOnceInit(void);
#endif
/**
* xmlNewMutex:
*
* 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
*/
xmlNewMutex(void)
{
return (NULL);
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded != 0)
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
return NULL;
}
#endif
return (tok);
}
/**
* xmlFreeMutex:
* @tok: the simple mutex
*
* xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
* struct.
*/
void
{
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded != 0)
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
#endif
}
/**
* xmlMutexLock:
* @tok: the simple mutex
*
* xmlMutexLock() is used to lock a libxml2 token.
*/
void
{
return;
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded != 0)
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
#ifdef DEBUG_THREADS
exit();
#endif
}
#endif
}
/**
* xmlMutexUnlock:
* @tok: the simple mutex
*
* xmlMutexUnlock() is used to unlock a libxml2 token.
*/
void
{
return;
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded != 0)
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
}
#endif
}
/**
* xmlNewRMutex:
*
* 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
*/
xmlNewRMutex(void)
{
return (NULL);
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded != 0) {
}
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
return NULL;
}
#endif
return (tok);
}
/**
* xmlFreeRMutex:
* @tok: the reentrant mutex
*
* xmlRFreeMutex() is used to reclaim resources associated with a
* reentrant mutex.
*/
void
{
return;
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded != 0) {
}
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
#endif
}
/**
* xmlRMutexLock:
* @tok: the reentrant mutex
*
* xmlRMutexLock() is used to lock a libxml2 token_r.
*/
void
{
return;
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded == 0)
return;
return;
} else {
}
}
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
return;
} else {
}
#endif
}
/**
* xmlRMutexUnlock:
* @tok: the reentrant mutex
*
* xmlRMutexUnlock() is used to unlock a libxml2 token_r.
*/
void
{
return;
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded == 0)
return;
}
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
}
return;
}
#endif
}
/**
* xmlGlobalInitMutexLock
*
* Makes sure that the global initialization mutex is initialized and
* locks it.
*/
void
__xmlGlobalInitMutexLock(void)
{
/* Make sure the global init lock is initialized and then lock it. */
#ifdef HAVE_PTHREAD_H
/* The mutex is statically initialized, so we just lock it. */
#elif defined HAVE_WIN32_THREADS
/* Create a new critical section */
if (global_init_lock == NULL) {
/* Swap it into the global_init_lock */
#else /* Use older void* version */
#endif /* InterlockedCompareExchangePointer */
/* If another thread successfully recorded its critical
* section in the global_init_lock then discard the one
* allocated by this thread. */
if (global_init_lock != cs) {
}
}
/* Lock the chosen critical section */
#elif defined HAVE_BEOS_THREADS
/* Allocate a new semaphore */
while (global_init_lock == -1) {
} else {
snooze(1);
}
}
/* If another thread successfully recorded its critical
* section in the global_init_lock then discard the one
* allocated by this thread. */
if (global_init_lock != sem)
/* Acquire the chosen semaphore */
#ifdef DEBUG_THREADS
xmlGenericError(xmlGenericErrorContext, "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
exit();
#endif
}
#endif
}
void
{
#ifdef HAVE_PTHREAD_H
#elif defined HAVE_WIN32_THREADS
#elif defined HAVE_BEOS_THREADS
#endif
}
/**
* xmlGlobalInitMutexDestroy
*
* Makes sure that the global initialization mutex is destroyed before
* application termination.
*/
void __xmlGlobalInitMutexDestroy(void)
{
#if defined HAVE_WIN32_THREADS
if (global_init_lock != NULL)
{
}
#endif
}
/************************************************************************
* *
* Per thread global state handling *
* *
************************************************************************/
#ifdef LIBXML_THREAD_ENABLED
#ifdef xmlLastError
#endif
/**
* 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
{
/* free any memory allocated in the thread's xmlLastError */
}
/**
* xmlNewGlobalState:
*
* xmlNewGlobalState() allocates a global state. This structure is used to
* hold all data for use by a thread when supporting backwards compatibility
* of libxml2 to pre-thread-safe behaviour.
*
* Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
*/
static xmlGlobalStatePtr
xmlNewGlobalState(void)
{
return(NULL);
return (gs);
}
#endif /* LIBXML_THREAD_ENABLED */
#ifdef HAVE_WIN32_THREADS
#if !defined(HAVE_COMPILER_TLS)
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
typedef struct _xmlGlobalStateCleanupHelperParams
{
void *memory;
{
_endthread();
}
#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
typedef struct _xmlGlobalStateCleanupHelperParams
{
void *memory;
#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
#endif /* HAVE_COMPILER_TLS */
#endif /* HAVE_WIN32_THREADS */
#if defined HAVE_BEOS_THREADS
/**
* xmlGlobalStateCleanup:
* @data: unused parameter
*
* Used for Beos only
*/
{
}
#endif
/**
* xmlGetGlobalState:
*
* xmlGetGlobalState() is called to retrieve the global state for a thread.
*
* Returns the thread global state or NULL in case of error
*/
xmlGetGlobalState(void)
{
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded == 0)
return(NULL);
if ((globalval = (xmlGlobalState *)
return (tsd);
}
return (globalval);
#elif defined HAVE_WIN32_THREADS
#if defined(HAVE_COMPILER_TLS)
if (!tlstate_inited) {
tlstate_inited = 1;
}
return &tlstate;
#else /* HAVE_COMPILER_TLS */
xmlOnceInit();
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
#else
#endif
#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
#else
if (cleanup_helpers_head != NULL) {
cleanup_helpers_head->prev = p;
}
p->next = cleanup_helpers_head;
cleanup_helpers_head = p;
TlsSetValue(globalkey, p);
#endif
return (tsd);
}
return (globalval);
#endif /* HAVE_COMPILER_TLS */
#elif defined HAVE_BEOS_THREADS
xmlOnceInit();
if ((globalval = (xmlGlobalState *)
return (tsd);
}
return (globalval);
#else
return(NULL);
#endif
}
/************************************************************************
* *
* Library wide thread interfaces *
* *
************************************************************************/
/**
* xmlGetThreadId:
*
* xmlGetThreadId() find the current thread ID number
*
* Returns the current thread ID number
*/
int
xmlGetThreadId(void)
{
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded == 0)
return(0);
return((int) pthread_self());
#elif defined HAVE_WIN32_THREADS
return GetCurrentThreadId();
#elif defined HAVE_BEOS_THREADS
return find_thread(NULL);
#else
return((int) 0);
#endif
}
/**
* xmlIsMainThread:
*
* xmlIsMainThread() check whether the current thread is the main thread.
*
* Returns 1 if the current thread is the main thread, 0 otherwise
*/
int
xmlIsMainThread(void)
{
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded == -1)
if (libxml_is_threaded == 0)
return(1);
#elif defined HAVE_WIN32_THREADS
xmlOnceInit ();
#elif defined HAVE_BEOS_THREADS
xmlOnceInit();
#endif
#ifdef DEBUG_THREADS
#endif
#ifdef HAVE_PTHREAD_H
return(mainthread == pthread_self());
#elif defined HAVE_WIN32_THREADS
return(mainthread == GetCurrentThreadId ());
#elif defined HAVE_BEOS_THREADS
#else
return(1);
#endif
}
/**
* xmlLockLibrary:
*
* xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
* library.
*/
void
xmlLockLibrary(void)
{
#ifdef DEBUG_THREADS
#endif
}
/**
* xmlUnlockLibrary:
*
* xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
* library.
*/
void
xmlUnlockLibrary(void)
{
#ifdef DEBUG_THREADS
#endif
}
/**
* xmlInitThreads:
*
* xmlInitThreads() is used to to initialize all the thread related
* data of the libxml2 library.
*/
void
xmlInitThreads(void)
{
#ifdef DEBUG_THREADS
#endif
#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
#endif
#ifdef HAVE_PTHREAD_H
if (libxml_is_threaded == -1) {
if ((pthread_once != NULL) &&
(pthread_getspecific != NULL) &&
(pthread_setspecific != NULL) &&
(pthread_key_create != NULL) &&
(pthread_mutex_init != NULL) &&
(pthread_mutex_destroy != NULL) &&
(pthread_mutex_lock != NULL) &&
(pthread_mutex_unlock != NULL) &&
(pthread_cond_init != NULL) &&
(pthread_equal != NULL) &&
(pthread_self != NULL) &&
(pthread_key_create != NULL) &&
(pthread_cond_signal != NULL)) {
libxml_is_threaded = 1;
/* fprintf(stderr, "Running multithreaded\n"); */
} else {
/* fprintf(stderr, "Running without multithread\n"); */
libxml_is_threaded = 0;
}
}
#endif
}
/**
* xmlCleanupThreads:
*
* xmlCleanupThreads() is used to to cleanup all the thread related
* data of the libxml2 library once processing has ended.
*/
void
xmlCleanupThreads(void)
{
#ifdef DEBUG_THREADS
#endif
#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
if (globalkey != TLS_OUT_OF_INDEXES) {
p = cleanup_helpers_head;
while (p != NULL) {
p = p->next;
}
cleanup_helpers_head = 0;
}
#endif
}
#ifdef LIBXML_THREAD_ENABLED
/**
* xmlOnceInit
*
* xmlOnceInit() is used to initialize the value of mainthread for use
* in other routines. This function should only be called using
* pthread_once() in association with the once_control variable to ensure
* that the function is only called once. See man pthread_once for more
* details.
*/
static void
xmlOnceInit(void) {
#ifdef HAVE_PTHREAD_H
mainthread = pthread_self();
#endif
#if defined(HAVE_WIN32_THREADS)
{
#if !defined(HAVE_COMPILER_TLS)
#endif
}
else {
/* Another thread is working; give up our slice and
* wait until they're done. */
Sleep(0);
}
}
#endif
#ifdef HAVE_BEOS_THREADS
globalkey = tls_allocate();
} else
#endif
}
#endif
/**
* DllMain:
* @hinstDLL: handle to DLL instance
* @fdwReason: Reason code for entry
* @lpvReserved: generic pointer (depends upon reason code)
*
* Entry point for Windows library. It is being used to free thread-specific
* storage.
*
* Returns TRUE always
*/
#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
#if defined(LIBXML_STATIC_FOR_DLL)
#else
#endif
{
switch(fdwReason) {
case DLL_THREAD_DETACH:
if (globalkey != TLS_OUT_OF_INDEXES) {
if (globalval) {
}
if (p)
{
if (p == cleanup_helpers_head)
cleanup_helpers_head = p->next;
else
free(p);
}
}
break;
}
return TRUE;
}
#endif
#define bottom_threads
#include "elfgcchack.h"