2001-10-12 17:29:10 +00:00
/**
2008-04-11 12:58:43 +00:00
* threads . c : set of generic threading related routines
2001-10-12 17:29:10 +00:00
*
* See Copyright for the status of this software .
*
* Gary Pennington < Gary . Pennington @ uk . sun . com >
* daniel @ veillard . com
*/
2002-03-18 19:37:11 +00:00
# define IN_LIBXML
2001-10-12 17:29:10 +00:00
# include "libxml.h"
# include <string.h>
2022-03-02 00:29:17 +01:00
# include <stdlib.h>
2001-10-12 17:29:10 +00:00
# include <libxml/threads.h>
# include <libxml/globals.h>
2022-09-04 01:49:41 +02:00
# ifdef LIBXML_THREAD_ENABLED
# ifdef HAVE_PTHREAD_H
# include <pthread.h>
# define HAVE_POSIX_THREADS
# elif defined(_WIN32)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# ifndef HAVE_COMPILER_TLS
# include <process.h>
# endif
# define HAVE_WIN32_THREADS
# endif
2002-01-13 13:35:00 +00:00
# endif
2001-10-12 17:29:10 +00:00
# if defined(SOLARIS)
# include <note.h>
# endif
2022-08-26 01:22:33 +02:00
# include "private/dict.h"
# include "private/threads.h"
2001-10-14 09:56:15 +00:00
/* #define DEBUG_THREADS */
2001-10-12 17:29:10 +00:00
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2005-05-04 09:18:00 +00:00
2022-09-04 00:49:36 +02:00
# if defined(__GNUC__) && defined(__linux__)
2017-11-27 14:20:31 +01:00
2005-05-04 09:18:00 +00:00
static int libxml_is_threaded = - 1 ;
2017-11-27 14:20:31 +01:00
# define XML_PTHREAD_WEAK
2022-03-18 15:46:30 +01:00
# pragma weak pthread_once
2017-06-17 15:05:34 +02:00
# pragma weak pthread_getspecific
2022-03-18 15:46:30 +01:00
# pragma weak pthread_setspecific
2017-06-17 15:05:34 +02:00
# pragma weak pthread_key_create
# pragma weak pthread_key_delete
2022-03-06 19:26:24 +01:00
# pragma weak pthread_mutex_init
2022-03-18 15:46:30 +01:00
# pragma weak pthread_mutex_destroy
2017-06-17 15:05:34 +02:00
# pragma weak pthread_mutex_lock
# pragma weak pthread_mutex_unlock
2022-03-18 15:46:30 +01:00
# pragma weak pthread_cond_init
# pragma weak pthread_cond_destroy
# pragma weak pthread_cond_wait
# pragma weak pthread_equal
2017-06-17 15:05:34 +02:00
# pragma weak pthread_self
2022-03-18 15:46:30 +01:00
# pragma weak pthread_key_create
# pragma weak pthread_key_delete
# pragma weak pthread_cond_signal
2017-11-27 14:20:31 +01:00
# else /* __GNUC__, __GLIBC__, __linux__ */
static int libxml_is_threaded = 1 ;
# endif /* __GNUC__, __GLIBC__, __linux__ */
2022-09-04 01:49:41 +02:00
# endif /* HAVE_POSIX_THREADS */
2005-05-04 09:18:00 +00:00
2001-10-12 17:29:10 +00:00
/*
* TODO : this module still uses malloc / free and not xmlMalloc / xmlFree
2019-09-30 17:04:54 +02:00
* to avoid some craziness since xmlMalloc / xmlFree may actually
2001-10-12 17:29:10 +00:00
* be hosted on allocated blocks needing them for the allocation . . .
*/
/*
* xmlMutex are a simple mutual exception locks
*/
struct _xmlMutex {
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2001-10-12 17:29:10 +00:00
pthread_mutex_t lock ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 15:12:08 +01:00
CRITICAL_SECTION cs ;
2001-10-12 17:29:10 +00:00
# else
int empty ;
# endif
} ;
/*
* xmlRMutex are reentrant mutual exception locks
*/
struct _xmlRMutex {
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2001-10-12 17:29:10 +00:00
pthread_mutex_t lock ;
2022-03-18 15:46:30 +01:00
unsigned int held ;
unsigned int waiters ;
pthread_t tid ;
pthread_cond_t cv ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 15:58:42 +00:00
CRITICAL_SECTION cs ;
2001-10-12 17:29:10 +00:00
# else
int empty ;
# endif
} ;
2008-03-18 08:24:25 +00:00
2001-10-12 17:29:10 +00:00
/*
* This module still has some internal static data .
* - xmlLibraryLock a global lock
* - globalkey used for per - thread data
*/
2001-10-14 09:56:15 +00:00
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2008-03-18 08:24:25 +00:00
static pthread_key_t globalkey ;
static pthread_t mainthread ;
2001-12-06 14:08:31 +00:00
static pthread_once_t once_control = PTHREAD_ONCE_INIT ;
2012-09-12 17:34:53 +02:00
static pthread_once_t once_control_init = PTHREAD_ONCE_INIT ;
2007-02-12 17:31:53 +00:00
static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 15:58:42 +00: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 10:55:15 +00:00
static DWORD globalkey = TLS_OUT_OF_INDEXES ;
2002-10-31 15:58:42 +00:00
# endif /* HAVE_COMPILER_TLS */
2002-01-13 13:35:00 +00:00
static DWORD mainthread ;
2008-03-18 08:24:25 +00:00
static struct {
2005-02-25 07:31:49 +00:00
DWORD done ;
2017-10-09 16:50:57 +02:00
LONG control ;
2008-03-18 08:24:25 +00:00
} run_once = { 0 , 0 } ;
2007-02-12 17:31:53 +00:00
static volatile LPCRITICAL_SECTION global_init_lock = NULL ;
2003-10-29 13:39:15 +00:00
# endif
2002-10-31 15:58:42 +00:00
2008-03-18 08:24:25 +00:00
static xmlRMutexPtr xmlLibraryLock = NULL ;
2003-09-29 13:20:24 +00:00
# ifdef LIBXML_THREAD_ENABLED
2001-12-06 14:08:31 +00:00
static void xmlOnceInit ( void ) ;
2003-09-29 13:20:24 +00:00
# endif
2001-10-12 17:29:10 +00:00
/**
2002-12-10 15:19:08 +00:00
* xmlNewMutex :
2001-10-12 17:29:10 +00: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 ) ;
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded ! = 0 )
2008-03-18 08:24:25 +00:00
pthread_mutex_init ( & tok - > lock , NULL ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 15:12:08 +01:00
InitializeCriticalSection ( & tok - > cs ) ;
2001-10-12 17:29:10 +00: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 08:24:25 +00:00
if ( tok = = NULL )
return ;
2003-07-08 14:03:36 +00:00
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded ! = 0 )
2008-03-18 08:24:25 +00:00
pthread_mutex_destroy ( & tok - > lock ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 15:12:08 +01:00
DeleteCriticalSection ( & tok - > cs ) ;
2001-10-12 17:29:10 +00:00
# endif
free ( tok ) ;
}
/**
* xmlMutexLock :
* @ tok : the simple mutex
*
* xmlMutexLock ( ) is used to lock a libxml2 token .
*/
void
2003-08-08 14:00:28 +00:00
xmlMutexLock ( xmlMutexPtr tok )
2001-10-12 17:29:10 +00:00
{
2003-08-08 14:00:28 +00:00
if ( tok = = NULL )
return ;
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded ! = 0 )
2008-03-18 08:24:25 +00:00
pthread_mutex_lock ( & tok - > lock ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 15:12:08 +01:00
EnterCriticalSection ( & tok - > cs ) ;
2001-10-12 17:29:10 +00:00
# endif
}
/**
* xmlMutexUnlock :
* @ tok : the simple mutex
*
* xmlMutexUnlock ( ) is used to unlock a libxml2 token .
*/
void
2003-08-28 08:03:23 +00:00
xmlMutexUnlock ( xmlMutexPtr tok )
2001-10-12 17:29:10 +00:00
{
2003-08-28 08:03:23 +00:00
if ( tok = = NULL )
return ;
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded ! = 0 )
2008-03-18 08:24:25 +00:00
pthread_mutex_unlock ( & tok - > lock ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 15:12:08 +01:00
LeaveCriticalSection ( & tok - > cs ) ;
2001-10-12 17:29:10 +00:00
# endif
}
/**
2002-12-10 15:19:08 +00:00
* xmlNewRMutex :
2001-10-12 17:29:10 +00: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 ) ;
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded ! = 0 ) {
2022-03-18 15:46:30 +01:00
pthread_mutex_init ( & tok - > lock , NULL ) ;
tok - > held = 0 ;
tok - > waiters = 0 ;
pthread_cond_init ( & tok - > cv , NULL ) ;
2005-05-04 09:18:00 +00:00
}
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 15:58:42 +00:00
InitializeCriticalSection ( & tok - > cs ) ;
2001-10-12 17:29:10 +00:00
# endif
return ( tok ) ;
}
/**
2002-12-10 15:19:08 +00:00
* xmlFreeRMutex :
2001-10-12 17:29:10 +00:00
* @ tok : the reentrant mutex
*
* xmlRFreeMutex ( ) is used to reclaim resources associated with a
* reentrant mutex .
*/
void
2002-02-10 13:20:39 +00:00
xmlFreeRMutex ( xmlRMutexPtr tok ATTRIBUTE_UNUSED )
2001-10-12 17:29:10 +00:00
{
2005-05-04 09:18:00 +00:00
if ( tok = = NULL )
return ;
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2006-06-29 11:50:18 +00:00
if ( libxml_is_threaded ! = 0 ) {
2008-03-18 08:24:25 +00:00
pthread_mutex_destroy ( & tok - > lock ) ;
2022-03-18 15:46:30 +01:00
pthread_cond_destroy ( & tok - > cv ) ;
2006-06-29 11:50:18 +00:00
}
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 15:58:42 +00:00
DeleteCriticalSection ( & tok - > cs ) ;
2001-10-12 17:29:10 +00:00
# endif
free ( tok ) ;
}
/**
* xmlRMutexLock :
* @ tok : the reentrant mutex
*
* xmlRMutexLock ( ) is used to lock a libxml2 token_r .
*/
void
2003-09-11 23:35:09 +00:00
xmlRMutexLock ( xmlRMutexPtr tok )
2001-10-12 17:29:10 +00:00
{
2003-09-11 23:35:09 +00:00
if ( tok = = NULL )
return ;
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2022-03-18 15:46:30 +01:00
if ( libxml_is_threaded = = 0 )
return ;
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 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 15:58:42 +00:00
EnterCriticalSection ( & tok - > cs ) ;
2001-10-12 17:29:10 +00:00
# endif
}
/**
* xmlRMutexUnlock :
* @ tok : the reentrant mutex
*
* xmlRMutexUnlock ( ) is used to unlock a libxml2 token_r .
*/
void
2002-02-10 13:20:39 +00:00
xmlRMutexUnlock ( xmlRMutexPtr tok ATTRIBUTE_UNUSED )
2001-10-12 17:29:10 +00:00
{
2003-09-11 23:35:09 +00:00
if ( tok = = NULL )
return ;
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2022-03-18 15:46:30 +01:00
if ( libxml_is_threaded = = 0 )
return ;
pthread_mutex_lock ( & tok - > lock ) ;
tok - > held - - ;
if ( tok - > held = = 0 ) {
if ( tok - > waiters )
pthread_cond_signal ( & tok - > cv ) ;
memset ( & tok - > tid , 0 , sizeof ( tok - > tid ) ) ;
}
pthread_mutex_unlock ( & tok - > lock ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 15:12:08 +01:00
LeaveCriticalSection ( & tok - > cs ) ;
2001-10-12 17:29:10 +00:00
# endif
}
2007-02-12 17:31:53 +00: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. */
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2007-02-12 17:31:53 +00:00
/* The mutex is statically initialized, so we just lock it. */
2017-11-27 14:20:31 +01:00
# ifdef XML_PTHREAD_WEAK
if ( pthread_mutex_lock = = NULL )
return ;
# endif /* XML_PTHREAD_WEAK */
pthread_mutex_lock ( & global_init_lock ) ;
2007-02-12 17:31:53 +00:00
# elif defined HAVE_WIN32_THREADS
LPCRITICAL_SECTION cs ;
/* Create a new critical section */
if ( global_init_lock = = NULL ) {
2008-03-18 08:24:25 +00:00
cs = malloc ( sizeof ( CRITICAL_SECTION ) ) ;
if ( cs = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlGlobalInitMutexLock: out of memory \n " ) ;
return ;
}
InitializeCriticalSection ( cs ) ;
2007-02-12 17:31:53 +00:00
2008-03-18 08:24:25 +00:00
/* Swap it into the global_init_lock */
2007-06-08 19:36:04 +00:00
# ifdef InterlockedCompareExchangePointer
2017-10-09 16:50:57 +02:00
InterlockedCompareExchangePointer ( ( void * * ) & global_init_lock ,
cs , NULL ) ;
2008-03-18 08:24:25 +00:00
# else /* Use older void* version */
InterlockedCompareExchange ( ( void * * ) & global_init_lock ,
( void * ) cs , NULL ) ;
2007-06-08 19:36:04 +00:00
# endif /* InterlockedCompareExchangePointer */
2007-02-12 17:31:53 +00:00
2008-03-18 08:24:25 +00: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 17:31:53 +00:00
}
/* Lock the chosen critical section */
EnterCriticalSection ( global_init_lock ) ;
# endif
}
void
__xmlGlobalInitMutexUnlock ( void )
{
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2017-11-27 14:20:31 +01:00
# ifdef XML_PTHREAD_WEAK
if ( pthread_mutex_unlock = = NULL )
return ;
# endif /* XML_PTHREAD_WEAK */
pthread_mutex_unlock ( & global_init_lock ) ;
2007-02-12 17:31:53 +00:00
# elif defined HAVE_WIN32_THREADS
2008-03-24 11:12:55 +00:00
if ( global_init_lock ! = NULL ) {
LeaveCriticalSection ( global_init_lock ) ;
}
2007-02-12 17:31:53 +00:00
# endif
}
2007-11-16 10:54:59 +00:00
/**
* xmlGlobalInitMutexDestroy
*
* Makes sure that the global initialization mutex is destroyed before
* application termination .
*/
2008-03-18 08:24:25 +00:00
void
__xmlGlobalInitMutexDestroy ( void )
2007-11-16 10:54:59 +00:00
{
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2009-09-10 17:46:07 +02:00
# elif defined HAVE_WIN32_THREADS
2008-03-18 08:24:25 +00:00
if ( global_init_lock ! = NULL ) {
DeleteCriticalSection ( global_init_lock ) ;
free ( global_init_lock ) ;
global_init_lock = NULL ;
2007-11-16 10:54:59 +00:00
}
# endif
}
2001-10-12 17:29:10 +00:00
/************************************************************************
* *
* Per thread global state handling *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-31 17:52:43 +00:00
# ifdef LIBXML_THREAD_ENABLED
2004-10-22 13:16:10 +00:00
# ifdef xmlLastError
# undef xmlLastError
# endif
2008-03-18 08:24:25 +00:00
2001-10-12 17:29:10 +00: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 13:16:10 +00:00
xmlGlobalState * gs = ( xmlGlobalState * ) state ;
/* free any memory allocated in the thread's xmlLastError */
xmlResetError ( & ( gs - > xmlLastError ) ) ;
2001-10-12 17:29:10 +00: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 16:16:02 +00:00
* of libxml2 to pre - thread - safe behaviour .
2001-10-12 17:29:10 +00:00
*
* Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
*/
static xmlGlobalStatePtr
xmlNewGlobalState ( void )
{
xmlGlobalState * gs ;
2008-03-18 08:24:25 +00:00
2001-10-12 17:29:10 +00:00
gs = malloc ( sizeof ( xmlGlobalState ) ) ;
2008-03-18 08:24:25 +00:00
if ( gs = = NULL ) {
xmlGenericError ( xmlGenericErrorContext ,
" xmlGetGlobalState: out of memory \n " ) ;
return ( NULL ) ;
}
2001-10-12 17:29:10 +00:00
2002-11-22 05:07:29 +00:00
memset ( gs , 0 , sizeof ( xmlGlobalState ) ) ;
2001-10-12 17:29:10 +00:00
xmlInitializeGlobalState ( gs ) ;
return ( gs ) ;
}
2001-10-31 17:52:43 +00:00
# endif /* LIBXML_THREAD_ENABLED */
2001-10-12 17:29:10 +00:00
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2009-10-01 00:13:07 +02:00
# elif defined HAVE_WIN32_THREADS
2003-10-07 21:25:12 +00:00
# if !defined(HAVE_COMPILER_TLS)
# if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
2008-03-18 08:24:25 +00:00
typedef struct _xmlGlobalStateCleanupHelperParams {
2002-10-31 15:58:42 +00:00
HANDLE thread ;
void * memory ;
2002-01-13 13:35:00 +00:00
} xmlGlobalStateCleanupHelperParams ;
2008-03-18 08:24:25 +00:00
static void XMLCDECL
xmlGlobalStateCleanupHelper ( void * p )
2002-01-13 13:35:00 +00:00
{
2008-03-18 08:24:25 +00:00
xmlGlobalStateCleanupHelperParams * params =
( xmlGlobalStateCleanupHelperParams * ) p ;
2002-10-31 15:58:42 +00:00
WaitForSingleObject ( params - > thread , INFINITE ) ;
CloseHandle ( params - > thread ) ;
xmlFreeGlobalState ( params - > memory ) ;
free ( params ) ;
_endthread ( ) ;
2002-01-13 13:35:00 +00:00
}
2003-10-07 21:25:12 +00:00
# else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
2008-03-18 08:24:25 +00:00
typedef struct _xmlGlobalStateCleanupHelperParams {
2003-10-07 21:25:12 +00:00
void * memory ;
2008-03-18 08:24:25 +00:00
struct _xmlGlobalStateCleanupHelperParams * prev ;
struct _xmlGlobalStateCleanupHelperParams * next ;
2003-10-07 21:25:12 +00:00
} xmlGlobalStateCleanupHelperParams ;
2008-03-18 08:24:25 +00:00
static xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL ;
2003-10-07 21:25:12 +00:00
static CRITICAL_SECTION cleanup_helpers_cs ;
# endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
# endif /* HAVE_COMPILER_TLS */
2002-01-13 13:35:00 +00:00
# endif /* HAVE_WIN32_THREADS */
2002-12-10 15:19:08 +00: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 17:29:10 +00:00
xmlGlobalStatePtr
xmlGetGlobalState ( void )
{
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2001-10-12 17:29:10 +00:00
xmlGlobalState * globalval ;
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded = = 0 )
2008-03-18 08:24:25 +00:00
return ( NULL ) ;
2005-05-04 09:18:00 +00:00
2001-12-06 14:08:31 +00:00
pthread_once ( & once_control , xmlOnceInit ) ;
2001-10-12 17:29:10 +00:00
if ( ( globalval = ( xmlGlobalState * )
2008-03-18 08:24:25 +00:00
pthread_getspecific ( globalkey ) ) = = NULL ) {
2001-10-12 17:29:10 +00:00
xmlGlobalState * tsd = xmlNewGlobalState ( ) ;
2008-03-24 11:12:55 +00:00
if ( tsd = = NULL )
return ( NULL ) ;
2001-10-12 17:29:10 +00:00
pthread_setspecific ( globalkey , tsd ) ;
return ( tsd ) ;
2001-10-14 09:56:15 +00:00
}
return ( globalval ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 15:58:42 +00:00
# if defined(HAVE_COMPILER_TLS)
if ( ! tlstate_inited ) {
2008-03-18 08:24:25 +00:00
tlstate_inited = 1 ;
xmlInitializeGlobalState ( & tlstate ) ;
2002-10-31 15:58:42 +00:00
}
return & tlstate ;
# else /* HAVE_COMPILER_TLS */
xmlGlobalState * globalval ;
2008-03-18 08:24:25 +00:00
xmlGlobalStateCleanupHelperParams * p ;
2002-10-31 15:58:42 +00:00
2005-02-24 15:38:52 +00:00
xmlOnceInit ( ) ;
2003-10-07 21:25:12 +00:00
# if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
2008-03-18 08:24:25 +00:00
globalval = ( xmlGlobalState * ) TlsGetValue ( globalkey ) ;
2003-10-07 21:25:12 +00:00
# else
2008-03-18 08:24:25 +00:00
p = ( xmlGlobalStateCleanupHelperParams * ) TlsGetValue ( globalkey ) ;
globalval = ( xmlGlobalState * ) ( p ? p - > memory : NULL ) ;
2003-10-07 21:25:12 +00:00
# endif
if ( globalval = = NULL ) {
2008-03-18 08:24:25 +00: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 14:57:04 +00:00
xmlFreeGlobalState ( tsd ) ;
2008-03-18 08:24:25 +00:00
return ( NULL ) ;
}
p - > memory = tsd ;
2003-10-07 21:25:12 +00:00
# if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
2008-03-18 08:24:25 +00:00
DuplicateHandle ( GetCurrentProcess ( ) , GetCurrentThread ( ) ,
GetCurrentProcess ( ) , & p - > thread , 0 , TRUE ,
DUPLICATE_SAME_ACCESS ) ;
TlsSetValue ( globalkey , tsd ) ;
_beginthread ( xmlGlobalStateCleanupHelper , 0 , p ) ;
2003-10-07 21:25:12 +00:00
# else
2008-03-18 08:24:25 +00:00
EnterCriticalSection ( & cleanup_helpers_cs ) ;
2003-10-07 21:25:12 +00:00
if ( cleanup_helpers_head ! = NULL ) {
cleanup_helpers_head - > prev = p ;
}
2008-03-18 08:24:25 +00:00
p - > next = cleanup_helpers_head ;
p - > prev = NULL ;
cleanup_helpers_head = p ;
TlsSetValue ( globalkey , p ) ;
LeaveCriticalSection ( & cleanup_helpers_cs ) ;
2003-05-17 10:55:15 +00:00
# endif
2002-10-31 15:58:42 +00:00
2008-03-18 08:24:25 +00:00
return ( tsd ) ;
2002-10-31 15:58:42 +00:00
}
return ( globalval ) ;
# endif /* HAVE_COMPILER_TLS */
2001-10-14 09:56:15 +00:00
# else
2008-03-18 08:24:25 +00:00
return ( NULL ) ;
2001-10-12 17:29:10 +00:00
# endif
}
/************************************************************************
* *
* Library wide thread interfaces *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-17 15:58:35 +00:00
/**
* xmlGetThreadId :
*
* xmlGetThreadId ( ) find the current thread ID number
2009-09-10 17:46:07 +02: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 15:58:35 +00:00
*
* Returns the current thread ID number
*/
int
xmlGetThreadId ( void )
{
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2009-09-10 17:46:07 +02:00
pthread_t id ;
int ret ;
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded = = 0 )
2008-03-18 08:24:25 +00:00
return ( 0 ) ;
2009-09-10 17:46:07 +02:00
id = pthread_self ( ) ;
/* horrible but preserves compat, see warning above */
memcpy ( & ret , & id , sizeof ( ret ) ) ;
return ( ret ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2002-10-31 15:58:42 +00:00
return GetCurrentThreadId ( ) ;
2001-10-17 15:58:35 +00:00
# else
2008-03-18 08:24:25 +00:00
return ( ( int ) 0 ) ;
2001-10-17 15:58:35 +00:00
# endif
}
2001-10-14 09:56:15 +00:00
/**
* xmlIsMainThread :
*
2001-12-31 16:16:02 +00:00
* xmlIsMainThread ( ) check whether the current thread is the main thread .
2001-10-14 09:56:15 +00:00
*
* Returns 1 if the current thread is the main thread , 0 otherwise
*/
int
xmlIsMainThread ( void )
{
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded = = - 1 )
xmlInitThreads ( ) ;
if ( libxml_is_threaded = = 0 )
2008-03-18 08:24:25 +00:00
return ( 1 ) ;
2001-12-06 14:08:31 +00:00
pthread_once ( & once_control , xmlOnceInit ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2008-03-18 08:24:25 +00:00
xmlOnceInit ( ) ;
2001-12-06 14:08:31 +00:00
# endif
2008-03-18 08:24:25 +00:00
2001-10-14 09:56:15 +00:00
# ifdef DEBUG_THREADS
xmlGenericError ( xmlGenericErrorContext , " xmlIsMainThread() \n " ) ;
# endif
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2009-09-10 17:46:07 +02:00
return ( pthread_equal ( mainthread , pthread_self ( ) ) ) ;
2002-01-13 13:35:00 +00:00
# elif defined HAVE_WIN32_THREADS
2008-03-18 08:24:25 +00:00
return ( mainthread = = GetCurrentThreadId ( ) ) ;
2001-10-14 09:56:15 +00:00
# else
2008-03-18 08:24:25 +00:00
return ( 1 ) ;
2001-10-14 09:56:15 +00:00
# endif
}
2001-10-12 17:29:10 +00:00
/**
* xmlLockLibrary :
*
* xmlLockLibrary ( ) is used to take out a re - entrant lock on the libxml2
* library .
*/
void
xmlLockLibrary ( void )
{
2001-10-14 09:56:15 +00:00
# ifdef DEBUG_THREADS
xmlGenericError ( xmlGenericErrorContext , " xmlLockLibrary() \n " ) ;
# endif
2001-10-12 17:29:10 +00:00
xmlRMutexLock ( xmlLibraryLock ) ;
}
/**
* xmlUnlockLibrary :
*
* xmlUnlockLibrary ( ) is used to release a re - entrant lock on the libxml2
* library .
*/
void
xmlUnlockLibrary ( void )
{
2001-10-14 09:56:15 +00:00
# ifdef DEBUG_THREADS
xmlGenericError ( xmlGenericErrorContext , " xmlUnlockLibrary() \n " ) ;
# endif
2001-10-12 17:29:10 +00:00
xmlRMutexUnlock ( xmlLibraryLock ) ;
}
/**
* xmlInitThreads :
*
2022-03-06 13:55:48 +01:00
* DEPRECATED : This function will be made private . Call xmlInitParser to
* initialize the library .
*
2001-10-12 17:29:10 +00:00
* xmlInitThreads ( ) is used to to initialize all the thread related
* data of the libxml2 library .
*/
void
xmlInitThreads ( void )
{
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2017-11-27 14:20:31 +01:00
# ifdef XML_PTHREAD_WEAK
2005-05-04 09:18:00 +00:00
if ( libxml_is_threaded = = - 1 ) {
if ( ( pthread_once ! = NULL ) & &
2008-03-18 08:24:25 +00:00
( pthread_getspecific ! = NULL ) & &
( pthread_setspecific ! = NULL ) & &
( pthread_key_create ! = NULL ) & &
2009-01-18 15:41:30 +00:00
( pthread_key_delete ! = NULL ) & &
2008-03-18 08:24:25 +00:00
( pthread_mutex_init ! = NULL ) & &
( pthread_mutex_destroy ! = NULL ) & &
( pthread_mutex_lock ! = NULL ) & &
( pthread_mutex_unlock ! = NULL ) & &
2022-03-18 15:46:30 +01:00
( pthread_cond_init ! = NULL ) & &
( pthread_cond_destroy ! = NULL ) & &
( pthread_cond_wait ! = NULL ) & &
2022-10-24 20:24:17 +02:00
/*
* pthread_equal can be inline , resuting in - Waddress warnings .
* Let ' s assume it ' s available if all the other functions are .
*/
/* (pthread_equal != NULL) && */
2022-03-18 15:46:30 +01:00
( pthread_self ! = NULL ) & &
( pthread_cond_signal ! = NULL ) ) {
2008-03-18 08:24:25 +00:00
libxml_is_threaded = 1 ;
2005-05-04 09:18:00 +00:00
/* fprintf(stderr, "Running multithreaded\n"); */
2008-03-18 08:24:25 +00:00
} else {
2005-05-04 09:18:00 +00:00
/* fprintf(stderr, "Running without multithread\n"); */
2008-03-18 08:24:25 +00:00
libxml_is_threaded = 0 ;
}
2005-05-04 09:18:00 +00:00
}
2017-11-27 14:20:31 +01:00
# endif /* XML_PTHREAD_WEAK */
2005-05-04 09:18:00 +00:00
# endif
2001-10-12 17:29:10 +00:00
}
/**
* xmlCleanupThreads :
*
2022-03-06 13:55:48 +01:00
* DEPRECATED : This function will be made private . Call xmlCleanupParser
* to free global state but see the warnings there . xmlCleanupParser
* should be only called once at program exit . In most cases , you don ' t
* have call cleanup functions at all .
*
2001-10-12 17:29:10 +00:00
* xmlCleanupThreads ( ) is used to to cleanup all the thread related
* data of the libxml2 library once processing has ended .
2009-02-21 09:22:04 +00: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 17:29:10 +00:00
*/
void
xmlCleanupThreads ( void )
{
2001-10-14 09:56:15 +00:00
# ifdef DEBUG_THREADS
xmlGenericError ( xmlGenericErrorContext , " xmlCleanupThreads() \n " ) ;
# endif
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2017-11-27 14:20:31 +01:00
if ( libxml_is_threaded ! = 0 )
2009-09-10 17:46:07 +02:00
pthread_key_delete ( globalkey ) ;
2012-09-12 17:34:53 +02:00
once_control = once_control_init ;
2022-06-15 17:25:03 +02:00
# elif defined(HAVE_WIN32_THREADS)
# if !defined(HAVE_COMPILER_TLS)
2003-10-07 21:25:12 +00:00
if ( globalkey ! = TLS_OUT_OF_INDEXES ) {
2022-06-15 17:25:03 +02:00
# if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
2008-03-18 08:24:25 +00: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 ) ;
2022-06-15 17:25:03 +02:00
# endif
2008-03-18 08:24:25 +00:00
TlsFree ( globalkey ) ;
globalkey = TLS_OUT_OF_INDEXES ;
2003-10-07 21:25:12 +00:00
}
2022-06-15 17:25:03 +02:00
# if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
2003-10-07 21:25:12 +00:00
DeleteCriticalSection ( & cleanup_helpers_cs ) ;
2022-06-15 17:25:03 +02:00
# endif
# endif
2022-06-14 18:38:12 +02:00
run_once . done = 0 ;
run_once . control = 0 ;
2003-10-07 21:25:12 +00:00
# endif
2001-12-06 14:08:31 +00:00
}
2001-10-14 09:56:15 +00:00
2003-09-29 13:20:24 +00:00
# ifdef LIBXML_THREAD_ENABLED
2008-03-18 08:24:25 +00:00
2001-12-06 14:08:31 +00: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 08:24:25 +00:00
xmlOnceInit ( void )
{
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2002-10-31 15:58:42 +00:00
( void ) pthread_key_create ( & globalkey , xmlFreeGlobalState ) ;
2001-12-06 14:08:31 +00:00
mainthread = pthread_self ( ) ;
2013-04-05 23:10:41 +08:00
__xmlInitializeDict ( ) ;
2009-09-10 17:46:07 +02:00
# elif defined(HAVE_WIN32_THREADS)
2005-02-24 15:38:52 +00:00
if ( ! run_once . done ) {
2008-03-18 08:24:25 +00:00
if ( InterlockedIncrement ( & run_once . control ) = = 1 ) {
2002-10-31 15:58:42 +00:00
# if !defined(HAVE_COMPILER_TLS)
2020-01-13 18:28:34 -06:00
# if !defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL)
InitializeCriticalSection ( & cleanup_helpers_cs ) ;
# endif
2005-02-24 15:38:52 +00:00
globalkey = TlsAlloc ( ) ;
2002-10-31 15:58:42 +00:00
# endif
2005-02-24 15:38:52 +00:00
mainthread = GetCurrentThreadId ( ) ;
2013-04-05 23:10:41 +08:00
__xmlInitializeDict ( ) ;
2005-02-24 15:38:52 +00:00
run_once . done = 1 ;
2008-03-18 08:24:25 +00:00
} else {
2005-02-24 15:38:52 +00:00
/* Another thread is working; give up our slice and
* wait until they ' re done . */
while ( ! run_once . done )
Sleep ( 0 ) ;
}
}
2003-10-29 13:39:15 +00:00
# endif
2001-10-12 17:29:10 +00:00
}
2003-09-29 13:20:24 +00:00
# endif
2003-05-17 10:55:15 +00:00
/**
2003-08-15 07:27:40 +00:00
* DllMain :
* @ hinstDLL : handle to DLL instance
* @ fdwReason : Reason code for entry
* @ lpvReserved : generic pointer ( depends upon reason code )
2003-05-17 10:55:15 +00:00
*
* Entry point for Windows library . It is being used to free thread - specific
* storage .
2003-08-15 07:27:40 +00:00
*
* Returns TRUE always
2003-05-17 10:55:15 +00:00
*/
2022-09-04 01:49:41 +02:00
# ifdef HAVE_POSIX_THREADS
2009-09-10 17:46:07 +02:00
# elif defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
2003-10-07 21:25:12 +00:00
# if defined(LIBXML_STATIC_FOR_DLL)
2017-10-21 14:04:20 +02:00
int XMLCALL
xmlDllMain ( ATTRIBUTE_UNUSED void * hinstDLL , unsigned long fdwReason ,
ATTRIBUTE_UNUSED void * lpvReserved )
2003-10-07 21:25:12 +00:00
# else
2017-10-21 14:09:16 +02: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 08:24:25 +00:00
BOOL WINAPI
2017-10-09 16:50:57 +02:00
DllMain ( ATTRIBUTE_UNUSED HINSTANCE hinstDLL , DWORD fdwReason ,
ATTRIBUTE_UNUSED LPVOID lpvReserved )
2003-10-07 21:25:12 +00:00
# endif
2003-05-17 10:55:15 +00:00
{
2008-03-18 08:24:25 +00: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-07 21:25:12 +00:00
}
2008-03-18 08:24:25 +00:00
break ;
2003-05-17 10:55:15 +00:00
}
return TRUE ;
}
# endif