2001-10-12 21:29:10 +04:00
/**
2008-04-11 16:58:43 +04:00
* threads . c : set of generic threading related routines
2001-10-12 21:29:10 +04:00
*
* See Copyright for the status of this software .
*
* Gary Pennington < Gary . Pennington @ uk . sun . com >
* daniel @ veillard . com
*/
2002-03-18 22:37:11 +03:00
# define IN_LIBXML
2001-10-12 21:29:10 +04:00
# 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>
2009-10-01 02:13:07 +04:00
# elif defined HAVE_WIN32_THREADS
2017-10-09 01:20:01 +03:00
# define WIN32_LEAN_AND_MEAN
2002-01-13 16:35:00 +03:00
# include <windows.h>
2002-10-31 18:58:42 +03:00
# ifndef HAVE_COMPILER_TLS
2002-01-13 16:35:00 +03:00
# include <process.h>
# endif
# endif
2001-10-12 21:29:10 +04:00
2003-10-29 16:39:15 +03:00
# ifdef HAVE_BEOS_THREADS
# include <OS.h>
# include <TLS.h>
# endif
2001-10-12 21:29:10 +04:00
# if defined(SOLARIS)
# include <note.h>
# endif
2001-10-14 13:56:15 +04:00
/* #define DEBUG_THREADS */
2001-10-12 21:29:10 +04:00
2005-05-04 13:18:00 +04:00
# ifdef HAVE_PTHREAD_H
2017-11-27 16:20:31 +03:00
# if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 303) && \
defined ( __GLIBC__ ) & & defined ( __linux__ )
2005-05-04 13:18:00 +04:00
static int libxml_is_threaded = - 1 ;
2017-11-27 16:20:31 +03:00
# define XML_PTHREAD_WEAK
2017-06-17 16:05:34 +03:00
# pragma weak pthread_once
# pragma weak pthread_getspecific
# pragma weak pthread_setspecific
# pragma weak pthread_key_create
# pragma weak pthread_key_delete
# pragma weak pthread_mutex_init
# pragma weak pthread_mutex_destroy
# pragma weak pthread_mutex_lock
# pragma weak pthread_mutex_unlock
# pragma weak pthread_cond_init
# pragma weak pthread_cond_destroy
# pragma weak pthread_cond_wait
# pragma weak pthread_equal
# pragma weak pthread_self
# pragma weak pthread_key_create
# pragma weak pthread_key_delete
# pragma weak pthread_cond_signal
2017-11-27 16:20:31 +03:00
# else /* __GNUC__, __GLIBC__, __linux__ */
static int libxml_is_threaded = 1 ;
# endif /* __GNUC__, __GLIBC__, __linux__ */
2005-05-04 13:18:00 +04:00
# endif /* HAVE_PTHREAD_H */
2001-10-12 21:29:10 +04:00
/*
* 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 ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
HANDLE mutex ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
sem_id sem ;
thread_id tid ;
2001-10-12 21:29:10 +04:00
# else
int empty ;
# endif
} ;
/*
* xmlRMutex are reentrant mutual exception locks
*/
struct _xmlRMutex {
# ifdef HAVE_PTHREAD_H
pthread_mutex_t lock ;
2008-03-18 11:24:25 +03:00
unsigned int held ;
unsigned int waiters ;
pthread_t tid ;
pthread_cond_t cv ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
CRITICAL_SECTION cs ;
unsigned int count ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
xmlMutexPtr lock ;
thread_id tid ;
int32 count ;
2001-10-12 21:29:10 +04:00
# else
int empty ;
# endif
} ;
2008-03-18 11:24:25 +03:00
2001-10-12 21:29:10 +04:00
/*
* This module still has some internal static data .
* - xmlLibraryLock a global lock
* - globalkey used for per - thread data
*/
2001-10-14 13:56:15 +04:00
2001-10-12 21:29:10 +04:00
# ifdef HAVE_PTHREAD_H
2008-03-18 11:24:25 +03:00
static pthread_key_t globalkey ;
static pthread_t mainthread ;
2001-12-06 17:08:31 +03:00
static pthread_once_t once_control = PTHREAD_ONCE_INIT ;
2012-09-12 19:34:53 +04:00
static pthread_once_t once_control_init = PTHREAD_ONCE_INIT ;
2007-02-12 20:31:53 +03:00
static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
# if defined(HAVE_COMPILER_TLS)
static __declspec ( thread ) xmlGlobalState tlstate ;
static __declspec ( thread ) int tlstate_inited = 0 ;
# else /* HAVE_COMPILER_TLS */
2003-05-17 14:55:15 +04:00
static DWORD globalkey = TLS_OUT_OF_INDEXES ;
2002-10-31 18:58:42 +03:00
# endif /* HAVE_COMPILER_TLS */
2002-01-13 16:35:00 +03:00
static DWORD mainthread ;
2008-03-18 11:24:25 +03:00
static struct {
2005-02-25 10:31:49 +03:00
DWORD done ;
2017-10-09 17:50:57 +03:00
LONG control ;
2008-03-18 11:24:25 +03:00
} run_once = { 0 , 0 } ;
2007-02-12 20:31:53 +03:00
static volatile LPCRITICAL_SECTION global_init_lock = NULL ;
2008-03-18 11:24:25 +03:00
2003-10-29 16:39:15 +03:00
/* endif HAVE_WIN32_THREADS */
# elif defined HAVE_BEOS_THREADS
int32 globalkey = 0 ;
thread_id mainthread = 0 ;
int32 run_once_init = 0 ;
2007-02-12 20:31:53 +03:00
static int32 global_init_lock = - 1 ;
static vint32 global_init_count = 0 ;
2003-10-29 16:39:15 +03:00
# endif
2002-10-31 18:58:42 +03:00
2008-03-18 11:24:25 +03:00
static xmlRMutexPtr xmlLibraryLock = NULL ;
2003-09-29 17:20:24 +04:00
# ifdef LIBXML_THREAD_ENABLED
2001-12-06 17:08:31 +03:00
static void xmlOnceInit ( void ) ;
2003-09-29 17:20:24 +04:00
# endif
2001-10-12 21:29:10 +04:00
/**
2002-12-10 18:19:08 +03:00
* xmlNewMutex :
2001-10-12 21:29:10 +04:00
*
* 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
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded ! = 0 )
2008-03-18 11:24:25 +03:00
pthread_mutex_init ( & tok - > lock , NULL ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
tok - > mutex = CreateMutex ( NULL , FALSE , NULL ) ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
if ( ( tok - > sem = create_sem ( 1 , " xmlMutex " ) ) < B_OK ) {
free ( tok ) ;
return NULL ;
}
tok - > tid = - 1 ;
2001-10-12 21:29:10 +04:00
# endif
return ( tok ) ;
}
/**
* xmlFreeMutex :
* @ tok : the simple mutex
*
* xmlFreeMutex ( ) is used to reclaim resources associated with a libxml2 token
* struct .
*/
void
xmlFreeMutex ( xmlMutexPtr tok )
{
2008-03-18 11:24:25 +03:00
if ( tok = = NULL )
return ;
2003-07-08 18:03:36 +04:00
2001-10-12 21:29:10 +04:00
# ifdef HAVE_PTHREAD_H
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded ! = 0 )
2008-03-18 11:24:25 +03:00
pthread_mutex_destroy ( & tok - > lock ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
CloseHandle ( tok - > mutex ) ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
delete_sem ( tok - > sem ) ;
2001-10-12 21:29:10 +04:00
# endif
free ( tok ) ;
}
/**
* xmlMutexLock :
* @ tok : the simple mutex
*
* xmlMutexLock ( ) is used to lock a libxml2 token .
*/
void
2003-08-08 18:00:28 +04:00
xmlMutexLock ( xmlMutexPtr tok )
2001-10-12 21:29:10 +04:00
{
2003-08-08 18:00:28 +04:00
if ( tok = = NULL )
return ;
2001-10-12 21:29:10 +04:00
# ifdef HAVE_PTHREAD_H
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded ! = 0 )
2008-03-18 11:24:25 +03:00
pthread_mutex_lock ( & tok - > lock ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
WaitForSingleObject ( tok - > mutex , INFINITE ) ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
if ( acquire_sem ( tok - > sem ) ! = B_NO_ERROR ) {
2003-10-29 16:39:15 +03:00
# ifdef DEBUG_THREADS
2008-03-18 11:24:25 +03:00
xmlGenericError ( xmlGenericErrorContext ,
" xmlMutexLock():BeOS:Couldn't aquire semaphore \n " ) ;
2003-10-29 16:39:15 +03:00
# endif
2008-03-18 11:24:25 +03:00
}
tok - > tid = find_thread ( NULL ) ;
2001-10-12 21:29:10 +04:00
# endif
}
/**
* xmlMutexUnlock :
* @ tok : the simple mutex
*
* xmlMutexUnlock ( ) is used to unlock a libxml2 token .
*/
void
2003-08-28 12:03:23 +04:00
xmlMutexUnlock ( xmlMutexPtr tok )
2001-10-12 21:29:10 +04:00
{
2003-08-28 12:03:23 +04:00
if ( tok = = NULL )
return ;
2001-10-12 21:29:10 +04:00
# ifdef HAVE_PTHREAD_H
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded ! = 0 )
2008-03-18 11:24:25 +03:00
pthread_mutex_unlock ( & tok - > lock ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
ReleaseMutex ( tok - > mutex ) ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
if ( tok - > tid = = find_thread ( NULL ) ) {
tok - > tid = - 1 ;
release_sem ( tok - > sem ) ;
}
2001-10-12 21:29:10 +04:00
# endif
}
/**
2002-12-10 18:19:08 +03:00
* xmlNewRMutex :
2001-10-12 21:29:10 +04:00
*
* 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
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded ! = 0 ) {
2008-03-18 11:24:25 +03:00
pthread_mutex_init ( & tok - > lock , NULL ) ;
tok - > held = 0 ;
tok - > waiters = 0 ;
pthread_cond_init ( & tok - > cv , NULL ) ;
2005-05-04 13:18:00 +04:00
}
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
InitializeCriticalSection ( & tok - > cs ) ;
tok - > count = 0 ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
if ( ( tok - > lock = xmlNewMutex ( ) ) = = NULL ) {
free ( tok ) ;
return NULL ;
}
tok - > count = 0 ;
2001-10-12 21:29:10 +04:00
# endif
return ( tok ) ;
}
/**
2002-12-10 18:19:08 +03:00
* xmlFreeRMutex :
2001-10-12 21:29:10 +04:00
* @ tok : the reentrant mutex
*
* xmlRFreeMutex ( ) is used to reclaim resources associated with a
* reentrant mutex .
*/
void
2002-02-10 16:20:39 +03:00
xmlFreeRMutex ( xmlRMutexPtr tok ATTRIBUTE_UNUSED )
2001-10-12 21:29:10 +04:00
{
2005-05-04 13:18:00 +04:00
if ( tok = = NULL )
return ;
2001-10-12 21:29:10 +04:00
# ifdef HAVE_PTHREAD_H
2006-06-29 15:50:18 +04:00
if ( libxml_is_threaded ! = 0 ) {
2008-03-18 11:24:25 +03:00
pthread_mutex_destroy ( & tok - > lock ) ;
pthread_cond_destroy ( & tok - > cv ) ;
2006-06-29 15:50:18 +04:00
}
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
DeleteCriticalSection ( & tok - > cs ) ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
xmlFreeMutex ( tok - > lock ) ;
2001-10-12 21:29:10 +04:00
# endif
free ( tok ) ;
}
/**
* xmlRMutexLock :
* @ tok : the reentrant mutex
*
* xmlRMutexLock ( ) is used to lock a libxml2 token_r .
*/
void
2003-09-12 03:35:09 +04:00
xmlRMutexLock ( xmlRMutexPtr tok )
2001-10-12 21:29:10 +04:00
{
2003-09-12 03:35:09 +04:00
if ( tok = = NULL )
return ;
2001-10-12 21:29:10 +04:00
# ifdef HAVE_PTHREAD_H
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded = = 0 )
return ;
2001-10-12 21:29:10 +04:00
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 ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
EnterCriticalSection ( & tok - > cs ) ;
2014-10-13 11:03:58 +04:00
tok - > count + + ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
if ( tok - > lock - > tid = = find_thread ( NULL ) ) {
tok - > count + + ;
return ;
} else {
xmlMutexLock ( tok - > lock ) ;
tok - > count = 1 ;
}
2001-10-12 21:29:10 +04:00
# endif
}
/**
* xmlRMutexUnlock :
* @ tok : the reentrant mutex
*
* xmlRMutexUnlock ( ) is used to unlock a libxml2 token_r .
*/
void
2002-02-10 16:20:39 +03:00
xmlRMutexUnlock ( xmlRMutexPtr tok ATTRIBUTE_UNUSED )
2001-10-12 21:29:10 +04:00
{
2003-09-12 03:35:09 +04:00
if ( tok = = NULL )
return ;
2001-10-12 21:29:10 +04:00
# ifdef HAVE_PTHREAD_H
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded = = 0 )
return ;
2008-03-18 11:24:25 +03:00
2001-10-12 21:29:10 +04:00
pthread_mutex_lock ( & tok - > lock ) ;
tok - > held - - ;
if ( tok - > held = = 0 ) {
if ( tok - > waiters )
pthread_cond_signal ( & tok - > cv ) ;
2009-09-10 19:46:07 +04:00
memset ( & tok - > tid , 0 , sizeof ( tok - > tid ) ) ;
2001-10-12 21:29:10 +04:00
}
pthread_mutex_unlock ( & tok - > lock ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2014-10-13 11:03:58 +04:00
if ( tok - > count > 0 ) {
tok - > count - - ;
2015-03-03 14:40:06 +03:00
LeaveCriticalSection ( & tok - > cs ) ;
2014-10-13 11:03:58 +04:00
}
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
if ( tok - > lock - > tid = = find_thread ( NULL ) ) {
tok - > count - - ;
if ( tok - > count = = 0 ) {
xmlMutexUnlock ( tok - > lock ) ;
}
return ;
}
2001-10-12 21:29:10 +04:00
# endif
}
2007-02-12 20:31:53 +03:00
/**
* 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. */
2017-11-27 16:20:31 +03:00
# ifdef XML_PTHREAD_WEAK
if ( pthread_mutex_lock = = NULL )
return ;
# endif /* XML_PTHREAD_WEAK */
pthread_mutex_lock ( & global_init_lock ) ;
2007-02-12 20:31:53 +03:00
# elif defined HAVE_WIN32_THREADS
LPCRITICAL_SECTION cs ;
/* Create a new critical section */
if ( global_init_lock = = NULL ) {
2008-03-18 11:24:25 +03:00
cs = malloc ( sizeof ( CRITICAL_SECTION ) ) ;
if ( cs = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlGlobalInitMutexLock: out of memory \n " ) ;
return ;
}
InitializeCriticalSection ( cs ) ;
2007-02-12 20:31:53 +03:00
2008-03-18 11:24:25 +03:00
/* Swap it into the global_init_lock */
2007-06-08 23:36:04 +04:00
# ifdef InterlockedCompareExchangePointer
2017-10-09 17:50:57 +03:00
InterlockedCompareExchangePointer ( ( void * * ) & global_init_lock ,
cs , NULL ) ;
2008-03-18 11:24:25 +03:00
# else /* Use older void* version */
InterlockedCompareExchange ( ( void * * ) & global_init_lock ,
( void * ) cs , NULL ) ;
2007-06-08 23:36:04 +04:00
# endif /* InterlockedCompareExchangePointer */
2007-02-12 20:31:53 +03:00
2008-03-18 11:24:25 +03:00
/* 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 ) {
DeleteCriticalSection ( cs ) ;
free ( cs ) ;
}
2007-02-12 20:31:53 +03:00
}
/* Lock the chosen critical section */
EnterCriticalSection ( global_init_lock ) ;
# elif defined HAVE_BEOS_THREADS
int32 sem ;
/* Allocate a new semaphore */
sem = create_sem ( 1 , " xmlGlobalinitMutex " ) ;
while ( global_init_lock = = - 1 ) {
2008-03-18 11:24:25 +03:00
if ( atomic_add ( & global_init_count , 1 ) = = 0 ) {
global_init_lock = sem ;
} else {
snooze ( 1 ) ;
atomic_add ( & global_init_count , - 1 ) ;
}
2007-02-12 20:31:53 +03:00
}
/* 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 )
2008-03-18 11:24:25 +03:00
delete_sem ( sem ) ;
2007-02-12 20:31:53 +03:00
/* Acquire the chosen semaphore */
if ( acquire_sem ( global_init_lock ) ! = B_NO_ERROR ) {
# ifdef DEBUG_THREADS
2008-03-18 11:24:25 +03:00
xmlGenericError ( xmlGenericErrorContext ,
" xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore \n " ) ;
2007-02-12 20:31:53 +03:00
# endif
}
# endif
}
void
__xmlGlobalInitMutexUnlock ( void )
{
# ifdef HAVE_PTHREAD_H
2017-11-27 16:20:31 +03:00
# ifdef XML_PTHREAD_WEAK
if ( pthread_mutex_unlock = = NULL )
return ;
# endif /* XML_PTHREAD_WEAK */
pthread_mutex_unlock ( & global_init_lock ) ;
2007-02-12 20:31:53 +03:00
# elif defined HAVE_WIN32_THREADS
2008-03-24 14:12:55 +03:00
if ( global_init_lock ! = NULL ) {
LeaveCriticalSection ( global_init_lock ) ;
}
2007-02-12 20:31:53 +03:00
# elif defined HAVE_BEOS_THREADS
release_sem ( global_init_lock ) ;
# endif
}
2007-11-16 13:54:59 +03:00
/**
* xmlGlobalInitMutexDestroy
*
* Makes sure that the global initialization mutex is destroyed before
* application termination .
*/
2008-03-18 11:24:25 +03:00
void
__xmlGlobalInitMutexDestroy ( void )
2007-11-16 13:54:59 +03:00
{
2009-09-10 19:46:07 +04:00
# ifdef HAVE_PTHREAD_H
# elif defined HAVE_WIN32_THREADS
2008-03-18 11:24:25 +03:00
if ( global_init_lock ! = NULL ) {
DeleteCriticalSection ( global_init_lock ) ;
free ( global_init_lock ) ;
global_init_lock = NULL ;
2007-11-16 13:54:59 +03:00
}
# endif
}
2001-10-12 21:29:10 +04:00
/************************************************************************
* *
* Per thread global state handling *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-31 20:52:43 +03:00
# ifdef LIBXML_THREAD_ENABLED
2004-10-22 17:16:10 +04:00
# ifdef xmlLastError
# undef xmlLastError
# endif
2008-03-18 11:24:25 +03:00
2001-10-12 21:29:10 +04:00
/**
* 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 )
{
2004-10-22 17:16:10 +04:00
xmlGlobalState * gs = ( xmlGlobalState * ) state ;
/* free any memory allocated in the thread's xmlLastError */
xmlResetError ( & ( gs - > xmlLastError ) ) ;
2001-10-12 21:29:10 +04:00
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
2001-12-31 19:16:02 +03:00
* of libxml2 to pre - thread - safe behaviour .
2001-10-12 21:29:10 +04:00
*
* Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
*/
static xmlGlobalStatePtr
xmlNewGlobalState ( void )
{
xmlGlobalState * gs ;
2008-03-18 11:24:25 +03:00
2001-10-12 21:29:10 +04:00
gs = malloc ( sizeof ( xmlGlobalState ) ) ;
2008-03-18 11:24:25 +03:00
if ( gs = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlGetGlobalState: out of memory \n " ) ;
return ( NULL ) ;
}
2001-10-12 21:29:10 +04:00
2002-11-22 08:07:29 +03:00
memset ( gs , 0 , sizeof ( xmlGlobalState ) ) ;
2001-10-12 21:29:10 +04:00
xmlInitializeGlobalState ( gs ) ;
return ( gs ) ;
}
2001-10-31 20:52:43 +03:00
# endif /* LIBXML_THREAD_ENABLED */
2001-10-12 21:29:10 +04:00
2009-09-10 19:46:07 +04:00
# ifdef HAVE_PTHREAD_H
2009-10-01 02:13:07 +04:00
# elif defined HAVE_WIN32_THREADS
2003-10-08 01:25:12 +04:00
# if !defined(HAVE_COMPILER_TLS)
# if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
2008-03-18 11:24:25 +03:00
typedef struct _xmlGlobalStateCleanupHelperParams {
2002-10-31 18:58:42 +03:00
HANDLE thread ;
void * memory ;
2002-01-13 16:35:00 +03:00
} xmlGlobalStateCleanupHelperParams ;
2008-03-18 11:24:25 +03:00
static void XMLCDECL
xmlGlobalStateCleanupHelper ( void * p )
2002-01-13 16:35:00 +03:00
{
2008-03-18 11:24:25 +03:00
xmlGlobalStateCleanupHelperParams * params =
( xmlGlobalStateCleanupHelperParams * ) p ;
2002-10-31 18:58:42 +03:00
WaitForSingleObject ( params - > thread , INFINITE ) ;
CloseHandle ( params - > thread ) ;
xmlFreeGlobalState ( params - > memory ) ;
free ( params ) ;
_endthread ( ) ;
2002-01-13 16:35:00 +03:00
}
2003-10-08 01:25:12 +04:00
# else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
2008-03-18 11:24:25 +03:00
typedef struct _xmlGlobalStateCleanupHelperParams {
2003-10-08 01:25:12 +04:00
void * memory ;
2008-03-18 11:24:25 +03:00
struct _xmlGlobalStateCleanupHelperParams * prev ;
struct _xmlGlobalStateCleanupHelperParams * next ;
2003-10-08 01:25:12 +04:00
} xmlGlobalStateCleanupHelperParams ;
2008-03-18 11:24:25 +03:00
static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL ;
2003-10-08 01:25:12 +04:00
static CRITICAL_SECTION cleanup_helpers_cs ;
# endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
# endif /* HAVE_COMPILER_TLS */
2002-01-13 16:35:00 +03:00
# endif /* HAVE_WIN32_THREADS */
2003-10-29 16:39:15 +03:00
# if defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
2003-11-18 09:54:40 +03:00
/**
* xmlGlobalStateCleanup :
* @ data : unused parameter
*
* Used for Beos only
*/
2008-03-18 11:24:25 +03:00
void
xmlGlobalStateCleanup ( void * data )
2003-10-29 16:39:15 +03:00
{
2008-03-18 11:24:25 +03:00
void * globalval = tls_get ( globalkey ) ;
if ( globalval ! = NULL )
xmlFreeGlobalState ( globalval ) ;
2003-10-29 16:39:15 +03:00
}
# endif
2002-12-10 18:19:08 +03:00
/**
* xmlGetGlobalState :
*
* xmlGetGlobalState ( ) is called to retrieve the global state for a thread .
*
* Returns the thread global state or NULL in case of error
*/
2001-10-12 21:29:10 +04:00
xmlGlobalStatePtr
xmlGetGlobalState ( void )
{
# ifdef HAVE_PTHREAD_H
xmlGlobalState * globalval ;
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded = = 0 )
2008-03-18 11:24:25 +03:00
return ( NULL ) ;
2005-05-04 13:18:00 +04:00
2001-12-06 17:08:31 +03:00
pthread_once ( & once_control , xmlOnceInit ) ;
2001-10-12 21:29:10 +04:00
if ( ( globalval = ( xmlGlobalState * )
2008-03-18 11:24:25 +03:00
pthread_getspecific ( globalkey ) ) = = NULL ) {
2001-10-12 21:29:10 +04:00
xmlGlobalState * tsd = xmlNewGlobalState ( ) ;
2008-03-24 14:12:55 +03:00
if ( tsd = = NULL )
return ( NULL ) ;
2001-10-12 21:29:10 +04:00
pthread_setspecific ( globalkey , tsd ) ;
return ( tsd ) ;
2001-10-14 13:56:15 +04:00
}
return ( globalval ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
# if defined(HAVE_COMPILER_TLS)
if ( ! tlstate_inited ) {
2008-03-18 11:24:25 +03:00
tlstate_inited = 1 ;
xmlInitializeGlobalState ( & tlstate ) ;
2002-10-31 18:58:42 +03:00
}
return & tlstate ;
# else /* HAVE_COMPILER_TLS */
xmlGlobalState * globalval ;
2008-03-18 11:24:25 +03:00
xmlGlobalStateCleanupHelperParams * p ;
2002-10-31 18:58:42 +03:00
2005-02-24 18:38:52 +03:00
xmlOnceInit ( ) ;
2003-10-08 01:25:12 +04:00
# if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
2008-03-18 11:24:25 +03:00
globalval = ( xmlGlobalState * ) TlsGetValue ( globalkey ) ;
2003-10-08 01:25:12 +04:00
# else
2008-03-18 11:24:25 +03:00
p = ( xmlGlobalStateCleanupHelperParams * ) TlsGetValue ( globalkey ) ;
globalval = ( xmlGlobalState * ) ( p ? p - > memory : NULL ) ;
2003-10-08 01:25:12 +04:00
# endif
if ( globalval = = NULL ) {
2008-03-18 11:24:25 +03:00
xmlGlobalState * tsd = xmlNewGlobalState ( ) ;
if ( tsd = = NULL )
return ( NULL ) ;
p = ( xmlGlobalStateCleanupHelperParams * )
malloc ( sizeof ( xmlGlobalStateCleanupHelperParams ) ) ;
if ( p = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlGetGlobalState: out of memory \n " ) ;
2009-01-18 17:57:04 +03:00
xmlFreeGlobalState ( tsd ) ;
2008-03-18 11:24:25 +03:00
return ( NULL ) ;
}
p - > memory = tsd ;
2003-10-08 01:25:12 +04:00
# if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
2008-03-18 11:24:25 +03:00
DuplicateHandle ( GetCurrentProcess ( ) , GetCurrentThread ( ) ,
GetCurrentProcess ( ) , & p - > thread , 0 , TRUE ,
DUPLICATE_SAME_ACCESS ) ;
TlsSetValue ( globalkey , tsd ) ;
_beginthread ( xmlGlobalStateCleanupHelper , 0 , p ) ;
2003-10-08 01:25:12 +04:00
# else
2008-03-18 11:24:25 +03:00
EnterCriticalSection ( & cleanup_helpers_cs ) ;
2003-10-08 01:25:12 +04:00
if ( cleanup_helpers_head ! = NULL ) {
cleanup_helpers_head - > prev = p ;
}
2008-03-18 11:24:25 +03:00
p - > next = cleanup_helpers_head ;
p - > prev = NULL ;
cleanup_helpers_head = p ;
TlsSetValue ( globalkey , p ) ;
LeaveCriticalSection ( & cleanup_helpers_cs ) ;
2003-05-17 14:55:15 +04:00
# endif
2002-10-31 18:58:42 +03:00
2008-03-18 11:24:25 +03:00
return ( tsd ) ;
2002-10-31 18:58:42 +03:00
}
return ( globalval ) ;
# endif /* HAVE_COMPILER_TLS */
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
xmlGlobalState * globalval ;
xmlOnceInit ( ) ;
2008-03-24 14:12:55 +03:00
if ( ( globalval = ( xmlGlobalState * ) tls_get ( globalkey ) ) = = NULL ) {
2003-10-29 16:39:15 +03:00
xmlGlobalState * tsd = xmlNewGlobalState ( ) ;
2008-03-24 14:12:55 +03:00
if ( tsd = = NULL )
return ( NULL ) ;
2003-10-29 16:39:15 +03:00
tls_set ( globalkey , tsd ) ;
on_exit_thread ( xmlGlobalStateCleanup , NULL ) ;
return ( tsd ) ;
}
return ( globalval ) ;
2001-10-14 13:56:15 +04:00
# else
2008-03-18 11:24:25 +03:00
return ( NULL ) ;
2001-10-12 21:29:10 +04:00
# endif
}
/************************************************************************
* *
* Library wide thread interfaces *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-17 19:58:35 +04:00
/**
* xmlGetThreadId :
*
* xmlGetThreadId ( ) find the current thread ID number
2009-09-10 19:46:07 +04:00
* Note that this is likely to be broken on some platforms using pthreads
* as the specification doesn ' t mandate pthread_t to be an integer type
2001-10-17 19:58:35 +04:00
*
* Returns the current thread ID number
*/
int
xmlGetThreadId ( void )
{
# ifdef HAVE_PTHREAD_H
2009-09-10 19:46:07 +04:00
pthread_t id ;
int ret ;
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded = = 0 )
2008-03-18 11:24:25 +03:00
return ( 0 ) ;
2009-09-10 19:46:07 +04:00
id = pthread_self ( ) ;
/* horrible but preserves compat, see warning above */
memcpy ( & ret , & id , sizeof ( ret ) ) ;
return ( ret ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 18:58:42 +03:00
return GetCurrentThreadId ( ) ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
return find_thread ( NULL ) ;
2001-10-17 19:58:35 +04:00
# else
2008-03-18 11:24:25 +03:00
return ( ( int ) 0 ) ;
2001-10-17 19:58:35 +04:00
# endif
}
2001-10-14 13:56:15 +04:00
/**
* xmlIsMainThread :
*
2001-12-31 19:16:02 +03:00
* xmlIsMainThread ( ) check whether the current thread is the main thread .
2001-10-14 13:56:15 +04:00
*
* Returns 1 if the current thread is the main thread , 0 otherwise
*/
int
xmlIsMainThread ( void )
{
2001-12-06 17:08:31 +03:00
# ifdef HAVE_PTHREAD_H
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded = = - 1 )
xmlInitThreads ( ) ;
if ( libxml_is_threaded = = 0 )
2008-03-18 11:24:25 +03:00
return ( 1 ) ;
2001-12-06 17:08:31 +03:00
pthread_once ( & once_control , xmlOnceInit ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2008-03-18 11:24:25 +03:00
xmlOnceInit ( ) ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2005-02-24 18:38:52 +03:00
xmlOnceInit ( ) ;
2001-12-06 17:08:31 +03:00
# endif
2008-03-18 11:24:25 +03:00
2001-10-14 13:56:15 +04:00
# ifdef DEBUG_THREADS
xmlGenericError ( xmlGenericErrorContext , " xmlIsMainThread() \n " ) ;
# endif
# ifdef HAVE_PTHREAD_H
2009-09-10 19:46:07 +04:00
return ( pthread_equal ( mainthread , pthread_self ( ) ) ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2008-03-18 11:24:25 +03:00
return ( mainthread = = GetCurrentThreadId ( ) ) ;
2003-10-29 16:39:15 +03:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
return ( mainthread = = find_thread ( NULL ) ) ;
2001-10-14 13:56:15 +04:00
# else
2008-03-18 11:24:25 +03:00
return ( 1 ) ;
2001-10-14 13:56:15 +04:00
# endif
}
2001-10-12 21:29:10 +04:00
/**
* xmlLockLibrary :
*
* xmlLockLibrary ( ) is used to take out a re - entrant lock on the libxml2
* library .
*/
void
xmlLockLibrary ( void )
{
2001-10-14 13:56:15 +04:00
# ifdef DEBUG_THREADS
xmlGenericError ( xmlGenericErrorContext , " xmlLockLibrary() \n " ) ;
# endif
2001-10-12 21:29:10 +04:00
xmlRMutexLock ( xmlLibraryLock ) ;
}
/**
* xmlUnlockLibrary :
*
* xmlUnlockLibrary ( ) is used to release a re - entrant lock on the libxml2
* library .
*/
void
xmlUnlockLibrary ( void )
{
2001-10-14 13:56:15 +04:00
# ifdef DEBUG_THREADS
xmlGenericError ( xmlGenericErrorContext , " xmlUnlockLibrary() \n " ) ;
# endif
2001-10-12 21:29:10 +04:00
xmlRMutexUnlock ( xmlLibraryLock ) ;
}
/**
* xmlInitThreads :
*
* xmlInitThreads ( ) is used to to initialize all the thread related
* data of the libxml2 library .
*/
void
xmlInitThreads ( void )
{
2005-05-04 13:18:00 +04:00
# ifdef HAVE_PTHREAD_H
2017-11-27 16:20:31 +03:00
# ifdef XML_PTHREAD_WEAK
2005-05-04 13:18:00 +04:00
if ( libxml_is_threaded = = - 1 ) {
if ( ( pthread_once ! = NULL ) & &
2008-03-18 11:24:25 +03:00
( pthread_getspecific ! = NULL ) & &
( pthread_setspecific ! = NULL ) & &
( pthread_key_create ! = NULL ) & &
2009-01-18 18:41:30 +03:00
( pthread_key_delete ! = NULL ) & &
2008-03-18 11:24:25 +03:00
( pthread_mutex_init ! = NULL ) & &
( pthread_mutex_destroy ! = NULL ) & &
( pthread_mutex_lock ! = NULL ) & &
( pthread_mutex_unlock ! = NULL ) & &
( pthread_cond_init ! = NULL ) & &
2008-08-27 15:45:41 +04:00
( pthread_cond_destroy ! = NULL ) & &
( pthread_cond_wait ! = NULL ) & &
2008-03-18 11:24:25 +03:00
( pthread_equal ! = NULL ) & &
( pthread_self ! = NULL ) & &
( pthread_cond_signal ! = NULL ) ) {
libxml_is_threaded = 1 ;
2005-05-04 13:18:00 +04:00
/* fprintf(stderr, "Running multithreaded\n"); */
2008-03-18 11:24:25 +03:00
} else {
2005-05-04 13:18:00 +04:00
/* fprintf(stderr, "Running without multithread\n"); */
2008-03-18 11:24:25 +03:00
libxml_is_threaded = 0 ;
}
2005-05-04 13:18:00 +04:00
}
2017-11-27 16:20:31 +03:00
# endif /* XML_PTHREAD_WEAK */
2009-09-10 19:46:07 +04:00
# elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
InitializeCriticalSection ( & cleanup_helpers_cs ) ;
2005-05-04 13:18:00 +04:00
# endif
2001-10-12 21:29:10 +04:00
}
/**
* xmlCleanupThreads :
*
* xmlCleanupThreads ( ) is used to to cleanup all the thread related
* data of the libxml2 library once processing has ended .
2009-02-21 12:22:04 +03:00
*
* WARNING : if your application is multithreaded or has plugin support
* calling this may crash the application if another thread or
* a plugin is still using libxml2 . It ' s sometimes very hard to
* guess if libxml2 is in use in the application , some libraries
* or plugins may use it without notice . In case of doubt abstain
* from calling this function or do it just before calling exit ( )
* to avoid leak reports from valgrind !
2001-10-12 21:29:10 +04:00
*/
void
xmlCleanupThreads ( void )
{
2001-10-14 13:56:15 +04:00
# ifdef DEBUG_THREADS
xmlGenericError ( xmlGenericErrorContext , " xmlCleanupThreads() \n " ) ;
# endif
2009-09-10 19:46:07 +04:00
# ifdef HAVE_PTHREAD_H
2017-11-27 16:20:31 +03:00
if ( libxml_is_threaded ! = 0 )
2009-09-10 19:46:07 +04:00
pthread_key_delete ( globalkey ) ;
2012-09-12 19:34:53 +04:00
once_control = once_control_init ;
2009-09-10 19:46:07 +04:00
# elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
2003-10-08 01:25:12 +04:00
if ( globalkey ! = TLS_OUT_OF_INDEXES ) {
2008-03-18 11:24:25 +03:00
xmlGlobalStateCleanupHelperParams * p ;
EnterCriticalSection ( & cleanup_helpers_cs ) ;
p = cleanup_helpers_head ;
while ( p ! = NULL ) {
xmlGlobalStateCleanupHelperParams * temp = p ;
p = p - > next ;
xmlFreeGlobalState ( temp - > memory ) ;
free ( temp ) ;
}
cleanup_helpers_head = 0 ;
LeaveCriticalSection ( & cleanup_helpers_cs ) ;
TlsFree ( globalkey ) ;
globalkey = TLS_OUT_OF_INDEXES ;
2003-10-08 01:25:12 +04:00
}
DeleteCriticalSection ( & cleanup_helpers_cs ) ;
# endif
2001-12-06 17:08:31 +03:00
}
2001-10-14 13:56:15 +04:00
2003-09-29 17:20:24 +04:00
# ifdef LIBXML_THREAD_ENABLED
2008-03-18 11:24:25 +03:00
2001-12-06 17:08:31 +03:00
/**
* 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
2008-03-18 11:24:25 +03:00
xmlOnceInit ( void )
{
2001-12-06 17:08:31 +03:00
# ifdef HAVE_PTHREAD_H
2002-10-31 18:58:42 +03:00
( void ) pthread_key_create ( & globalkey , xmlFreeGlobalState ) ;
2001-12-06 17:08:31 +03:00
mainthread = pthread_self ( ) ;
2013-04-05 19:10:41 +04:00
__xmlInitializeDict ( ) ;
2009-09-10 19:46:07 +04:00
# elif defined(HAVE_WIN32_THREADS)
2005-02-24 18:38:52 +03:00
if ( ! run_once . done ) {
2008-03-18 11:24:25 +03:00
if ( InterlockedIncrement ( & run_once . control ) = = 1 ) {
2002-10-31 18:58:42 +03:00
# if !defined(HAVE_COMPILER_TLS)
2005-02-24 18:38:52 +03:00
globalkey = TlsAlloc ( ) ;
2002-10-31 18:58:42 +03:00
# endif
2005-02-24 18:38:52 +03:00
mainthread = GetCurrentThreadId ( ) ;
2013-04-05 19:10:41 +04:00
__xmlInitializeDict ( ) ;
2005-02-24 18:38:52 +03:00
run_once . done = 1 ;
2008-03-18 11:24:25 +03:00
} else {
2005-02-24 18:38:52 +03:00
/* Another thread is working; give up our slice and
* wait until they ' re done . */
while ( ! run_once . done )
Sleep ( 0 ) ;
}
}
2009-10-01 02:13:07 +04:00
# elif defined HAVE_BEOS_THREADS
2008-03-18 11:24:25 +03:00
if ( atomic_add ( & run_once_init , 1 ) = = 0 ) {
globalkey = tls_allocate ( ) ;
tls_set ( globalkey , NULL ) ;
mainthread = find_thread ( NULL ) ;
2013-04-05 19:10:41 +04:00
__xmlInitializeDict ( ) ;
2008-03-18 11:24:25 +03:00
} else
atomic_add ( & run_once_init , - 1 ) ;
2003-10-29 16:39:15 +03:00
# endif
2001-10-12 21:29:10 +04:00
}
2003-09-29 17:20:24 +04:00
# endif
2003-05-17 14:55:15 +04:00
/**
2003-08-15 11:27:40 +04:00
* DllMain :
* @ hinstDLL : handle to DLL instance
* @ fdwReason : Reason code for entry
* @ lpvReserved : generic pointer ( depends upon reason code )
2003-05-17 14:55:15 +04:00
*
* Entry point for Windows library . It is being used to free thread - specific
* storage .
2003-08-15 11:27:40 +04:00
*
* Returns TRUE always
2003-05-17 14:55:15 +04:00
*/
2009-09-10 19:46:07 +04:00
# ifdef HAVE_PTHREAD_H
# elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
2003-10-08 01:25:12 +04:00
# if defined(LIBXML_STATIC_FOR_DLL)
2017-10-21 15:04:20 +03:00
int XMLCALL
xmlDllMain ( ATTRIBUTE_UNUSED void * hinstDLL , unsigned long fdwReason ,
ATTRIBUTE_UNUSED void * lpvReserved )
2003-10-08 01:25:12 +04:00
# else
2017-10-21 15:09:16 +03:00
/* declare to avoid "no previous prototype for 'DllMain'" warning */
/* Note that we do NOT want to include this function declaration in
a public header because it ' s meant to be called by Windows itself ,
not a program that uses this library . This also has to be exported . */
XMLPUBFUN BOOL WINAPI
DllMain ( HINSTANCE hinstDLL ,
DWORD fdwReason ,
LPVOID lpvReserved ) ;
2008-03-18 11:24:25 +03:00
BOOL WINAPI
2017-10-09 17:50:57 +03:00
DllMain ( ATTRIBUTE_UNUSED HINSTANCE hinstDLL , DWORD fdwReason ,
ATTRIBUTE_UNUSED LPVOID lpvReserved )
2003-10-08 01:25:12 +04:00
# endif
2003-05-17 14:55:15 +04:00
{
2008-03-18 11:24:25 +03:00
switch ( fdwReason ) {
case DLL_THREAD_DETACH :
if ( globalkey ! = TLS_OUT_OF_INDEXES ) {
xmlGlobalState * globalval = NULL ;
xmlGlobalStateCleanupHelperParams * p =
( xmlGlobalStateCleanupHelperParams * )
TlsGetValue ( globalkey ) ;
globalval = ( xmlGlobalState * ) ( p ? p - > memory : NULL ) ;
if ( globalval ) {
xmlFreeGlobalState ( globalval ) ;
TlsSetValue ( globalkey , NULL ) ;
}
if ( p ) {
EnterCriticalSection ( & cleanup_helpers_cs ) ;
if ( p = = cleanup_helpers_head )
cleanup_helpers_head = p - > next ;
else
p - > prev - > next = p - > next ;
if ( p - > next ! = NULL )
p - > next - > prev = p - > prev ;
LeaveCriticalSection ( & cleanup_helpers_cs ) ;
free ( p ) ;
}
2003-10-08 01:25:12 +04:00
}
2008-03-18 11:24:25 +03:00
break ;
2003-05-17 14:55:15 +04:00
}
return TRUE ;
}
# endif
2005-04-01 17:11:58 +04:00
# define bottom_threads
# include "elfgcchack.h"