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>
2024-07-15 15:35:47 +03:00
# include <stdarg.h>
2022-03-02 02:29:17 +03:00
# include <stdlib.h>
2001-10-12 21:29:10 +04:00
# include <libxml/threads.h>
2023-09-18 01:54:39 +03:00
# include <libxml/parser.h>
2023-09-18 18:39:13 +03:00
# ifdef LIBXML_CATALOG_ENABLED
# include <libxml/catalog.h>
# endif
# ifdef LIBXML_SCHEMAS_ENABLED
# include <libxml/xmlschemastypes.h>
# include <libxml/relaxng.h>
# endif
2001-10-12 21:29:10 +04:00
# if defined(SOLARIS)
# include <note.h>
# endif
2024-06-15 21:34:07 +03:00
# include "private/cata.h"
2022-08-26 02:22:33 +03:00
# include "private/dict.h"
2023-09-18 18:39:13 +03:00
# include "private/enc.h"
2024-07-15 15:35:47 +03:00
# include "private/error.h"
2023-09-18 18:39:13 +03:00
# include "private/globals.h"
2023-12-20 22:11:09 +03:00
# include "private/io.h"
2023-09-18 18:39:13 +03:00
# include "private/memory.h"
2022-08-26 02:22:33 +03:00
# include "private/threads.h"
2023-09-18 18:39:13 +03:00
# include "private/xpath.h"
2022-08-26 02:22:33 +03:00
2001-10-12 21:29:10 +04:00
/*
* TODO : this module still uses malloc / free and not xmlMalloc / xmlFree
2019-09-30 18:04:54 +03:00
* to avoid some craziness since xmlMalloc / xmlFree may actually
2001-10-12 21:29:10 +04:00
* be hosted on allocated blocks needing them for the allocation . . .
*/
2024-07-16 02:12:21 +03:00
static xmlRMutex xmlLibraryLock ;
2008-03-18 11:24:25 +03:00
2022-11-24 22:54:18 +03:00
/**
* xmlInitMutex :
* @ mutex : the mutex
*
* Initialize a mutex .
*/
void
xmlInitMutex ( xmlMutexPtr mutex )
{
# ifdef HAVE_POSIX_THREADS
2024-06-16 22:52:12 +03:00
pthread_mutex_init ( & mutex - > lock , NULL ) ;
2022-11-24 22:54:18 +03:00
# elif defined HAVE_WIN32_THREADS
InitializeCriticalSection ( & mutex - > cs ) ;
# else
( void ) mutex ;
# 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 ;
2024-06-18 23:55:34 +03:00
tok = malloc ( sizeof ( xmlMutex ) ) ;
if ( tok = = NULL )
2001-10-12 21:29:10 +04:00
return ( NULL ) ;
2022-11-24 22:54:18 +03:00
xmlInitMutex ( tok ) ;
return ( tok ) ;
}
/**
* xmlCleanupMutex :
* @ mutex : the simple mutex
*
* Reclaim resources associated with a mutex .
*/
void
xmlCleanupMutex ( xmlMutexPtr mutex )
{
2022-09-04 02:49:41 +03:00
# ifdef HAVE_POSIX_THREADS
2024-06-16 22:52:12 +03:00
pthread_mutex_destroy ( & mutex - > lock ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2022-11-24 22:54:18 +03:00
DeleteCriticalSection ( & mutex - > cs ) ;
# else
( void ) mutex ;
2001-10-12 21:29:10 +04:00
# endif
}
/**
* xmlFreeMutex :
* @ tok : the simple mutex
*
2022-11-24 22:54:18 +03:00
* Free a mutex .
2001-10-12 21:29:10 +04:00
*/
void
xmlFreeMutex ( xmlMutexPtr tok )
{
2008-03-18 11:24:25 +03:00
if ( tok = = NULL )
return ;
2003-07-08 18:03:36 +04:00
2022-11-24 22:54:18 +03:00
xmlCleanupMutex ( tok ) ;
2001-10-12 21:29:10 +04:00
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 ;
2022-09-04 02:49:41 +03:00
# ifdef HAVE_POSIX_THREADS
2022-10-24 22:50:34 +03:00
/*
* This assumes that __libc_single_threaded won ' t change while the
* lock is held .
*/
2024-06-16 22:52:12 +03:00
pthread_mutex_lock ( & tok - > lock ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 17:12:08 +03:00
EnterCriticalSection ( & tok - > cs ) ;
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 ;
2022-09-04 02:49:41 +03:00
# ifdef HAVE_POSIX_THREADS
2024-06-16 22:52:12 +03:00
pthread_mutex_unlock ( & tok - > lock ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 17:12:08 +03:00
LeaveCriticalSection ( & tok - > cs ) ;
2001-10-12 21:29:10 +04:00
# endif
}
2024-07-16 02:12:21 +03:00
void
xmlInitRMutex ( xmlRMutexPtr tok ) {
( void ) tok ;
# ifdef HAVE_POSIX_THREADS
pthread_mutex_init ( & tok - > lock , NULL ) ;
tok - > held = 0 ;
tok - > waiters = 0 ;
pthread_cond_init ( & tok - > cv , NULL ) ;
# elif defined HAVE_WIN32_THREADS
InitializeCriticalSection ( & tok - > cs ) ;
# endif
}
2001-10-12 21:29:10 +04:00
/**
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 ;
2024-06-18 23:55:34 +03:00
tok = malloc ( sizeof ( xmlRMutex ) ) ;
if ( tok = = NULL )
2001-10-12 21:29:10 +04:00
return ( NULL ) ;
2024-07-16 02:12:21 +03:00
xmlInitRMutex ( tok ) ;
return ( tok ) ;
}
void
xmlCleanupRMutex ( xmlRMutexPtr tok ) {
( void ) tok ;
2022-09-04 02:49:41 +03:00
# ifdef HAVE_POSIX_THREADS
2024-07-16 02:12:21 +03:00
pthread_mutex_destroy ( & tok - > lock ) ;
pthread_cond_destroy ( & tok - > cv ) ;
2002-01-13 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2024-07-16 02:12:21 +03:00
DeleteCriticalSection ( & tok - > cs ) ;
2001-10-12 21:29:10 +04:00
# endif
}
/**
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
2024-07-16 02:12:21 +03:00
xmlFreeRMutex ( xmlRMutexPtr tok )
2001-10-12 21:29:10 +04:00
{
2005-05-04 13:18:00 +04:00
if ( tok = = NULL )
return ;
2024-07-16 02:12:21 +03:00
xmlCleanupRMutex ( tok ) ;
2001-10-12 21:29:10 +04:00
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 ;
2022-09-04 02:49:41 +03:00
# ifdef HAVE_POSIX_THREADS
2022-03-18 17:46:30 +03: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 ) ;
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 ;
2022-09-04 02:49:41 +03:00
# ifdef HAVE_POSIX_THREADS
2022-03-18 17:46:30 +03:00
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 16:35:00 +03:00
# elif defined HAVE_WIN32_THREADS
2022-03-06 17:12:08 +03:00
LeaveCriticalSection ( & tok - > cs ) ;
2001-10-12 21:29:10 +04:00
# endif
}
/************************************************************************
* *
* Library wide thread interfaces *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-17 19:58:35 +04:00
/**
* xmlGetThreadId :
*
2022-11-24 17:00:03 +03:00
* DEPRECATED : Internal function , do not use .
*
2001-10-17 19:58:35 +04:00
* 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 )
{
2022-09-04 02:49:41 +03:00
# ifdef HAVE_POSIX_THREADS
2009-09-10 19:46:07 +04:00
pthread_t id ;
int ret ;
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 ( ) ;
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-12 21:29:10 +04:00
/**
* xmlLockLibrary :
*
* xmlLockLibrary ( ) is used to take out a re - entrant lock on the libxml2
* library .
*/
void
xmlLockLibrary ( void )
{
2024-07-16 02:12:21 +03:00
xmlRMutexLock ( & xmlLibraryLock ) ;
2001-10-12 21:29:10 +04:00
}
/**
* xmlUnlockLibrary :
*
* xmlUnlockLibrary ( ) is used to release a re - entrant lock on the libxml2
* library .
*/
void
xmlUnlockLibrary ( void )
{
2024-07-16 02:12:21 +03:00
xmlRMutexUnlock ( & xmlLibraryLock ) ;
2001-10-12 21:29:10 +04:00
}
/**
* xmlInitThreads :
*
2022-11-25 14:06:27 +03:00
* DEPRECATED : Alias for xmlInitParser .
2001-10-12 21:29:10 +04:00
*/
void
xmlInitThreads ( void )
2022-11-25 14:06:27 +03:00
{
xmlInitParser ( ) ;
}
2023-09-18 18:39:13 +03:00
/**
* xmlCleanupThreads :
*
* DEPRECATED : This function is a no - op . 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 .
*/
void
xmlCleanupThreads ( void )
{
}
2024-07-16 02:12:21 +03:00
static void
xmlInitThreadsInternal ( void ) {
xmlInitRMutex ( & xmlLibraryLock ) ;
}
static void
xmlCleanupThreadsInternal ( void ) {
xmlCleanupRMutex ( & xmlLibraryLock ) ;
}
2023-09-18 18:39:13 +03:00
/************************************************************************
* *
* Library wide initialization *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int xmlParserInitialized = 0 ;
# ifdef HAVE_POSIX_THREADS
2024-07-16 00:50:08 +03:00
static pthread_once_t onceControl = PTHREAD_ONCE_INIT ;
2023-09-18 18:39:13 +03:00
# elif defined HAVE_WIN32_THREADS
2024-07-16 00:50:08 +03:00
static INIT_ONCE onceControl = INIT_ONCE_STATIC_INIT ;
# else
static int onceControl = 0 ;
2023-09-18 18:39:13 +03:00
# endif
static void
2024-07-16 00:50:08 +03:00
xmlInitParserInternal ( void ) {
/*
* Note that the initialization code must not make memory allocations .
*/
xmlInitRandom ( ) ; /* Required by xmlInitGlobalsInternal */
xmlInitMemoryInternal ( ) ;
2024-07-16 02:12:21 +03:00
xmlInitThreadsInternal ( ) ;
2024-07-16 00:50:08 +03:00
xmlInitGlobalsInternal ( ) ;
xmlInitDictInternal ( ) ;
xmlInitEncodingInternal ( ) ;
# if defined(LIBXML_XPATH_ENABLED)
xmlInitXPathInternal ( ) ;
# endif
xmlInitIOCallbacks ( ) ;
# ifdef LIBXML_CATALOG_ENABLED
xmlInitCatalogInternal ( ) ;
2005-05-04 13:18:00 +04:00
# endif
2024-07-16 00:50:08 +03:00
xmlParserInitialized = 1 ;
2001-10-12 21:29:10 +04:00
}
2024-07-16 00:50:08 +03:00
# if defined(HAVE_WIN32_THREADS)
2024-07-18 04:48:11 +03:00
static BOOL WINAPI
2024-07-16 00:50:08 +03:00
xmlInitParserWinWrapper ( INIT_ONCE * initOnce ATTRIBUTE_UNUSED ,
void * parameter ATTRIBUTE_UNUSED ,
void * * context ATTRIBUTE_UNUSED ) {
xmlInitParserInternal ( ) ;
return ( TRUE ) ;
2023-09-18 18:39:13 +03:00
}
2024-07-16 00:50:08 +03:00
# endif
2023-09-18 18:39:13 +03:00
/**
* xmlInitParser :
*
* Initialization function for the XML parser .
*
2024-07-16 00:23:06 +03:00
* For older versions , it ' s recommended to call this function once
* from the main thread before using the library in multithreaded
* programs .
*
* Since 2.14 .0 , there ' s no distinction between threads . It should
* be unnecessary to call this function .
2001-10-12 21:29:10 +04:00
*/
void
2023-09-18 18:39:13 +03:00
xmlInitParser ( void ) {
2024-07-16 00:50:08 +03:00
# ifdef HAVE_POSIX_THREADS
pthread_once ( & onceControl , xmlInitParserInternal ) ;
# elif defined(HAVE_WIN32_THREADS)
InitOnceExecuteOnce ( & onceControl , xmlInitParserWinWrapper , NULL , NULL ) ;
# else
if ( onceControl = = 0 ) {
xmlInitParserInternal ( ) ;
onceControl = 1 ;
2023-09-18 18:39:13 +03:00
}
2024-07-16 00:50:08 +03:00
# endif
2022-11-25 14:06:27 +03:00
}
/**
2023-09-18 18:39:13 +03:00
* xmlCleanupParser :
*
2024-07-16 00:50:08 +03:00
* This function is named somewhat misleadingly . It does not clean up
2024-07-16 00:23:06 +03:00
* parser state but global memory allocated by the library itself .
*
* Since 2.9 .11 , cleanup is performed automatically if a shared or
* dynamic libxml2 library is unloaded . This function should only
* be used to avoid false positives from memory leak checkers in
* static builds .
2022-11-25 14:06:27 +03:00
*
2024-07-16 00:23:06 +03:00
* WARNING : xmlCleanupParser assumes that all other threads that called
* libxml2 functions have terminated . No library calls must be made
* after calling this function . In general , THIS FUNCTION SHOULD ONLY
* BE CALLED RIGHT BEFORE THE WHOLE PROCESS EXITS .
2022-11-25 14:06:27 +03:00
*/
void
2023-09-18 18:39:13 +03:00
xmlCleanupParser ( void ) {
2024-07-16 00:23:06 +03:00
/*
* Unfortunately , some users call this function to fix memory
* leaks on unload with versions before 2.9 .11 . This can result
* in the library being reinitialized , so this use case must
* be supported .
*/
2023-09-18 18:39:13 +03:00
if ( ! xmlParserInitialized )
return ;
xmlCleanupCharEncodingHandlers ( ) ;
# ifdef LIBXML_CATALOG_ENABLED
xmlCatalogCleanup ( ) ;
2024-06-15 21:34:07 +03:00
xmlCleanupCatalogInternal ( ) ;
2023-09-18 18:39:13 +03:00
# endif
# ifdef LIBXML_SCHEMAS_ENABLED
xmlSchemaCleanupTypes ( ) ;
xmlRelaxNGCleanupTypes ( ) ;
# endif
xmlCleanupDictInternal ( ) ;
2023-09-16 20:08:10 +03:00
xmlCleanupRandom ( ) ;
2023-09-18 18:39:13 +03:00
xmlCleanupGlobalsInternal ( ) ;
2024-07-16 02:12:21 +03:00
xmlCleanupThreadsInternal ( ) ;
2024-07-16 00:50:08 +03:00
2023-09-18 18:39:13 +03:00
/*
2024-07-16 00:23:06 +03:00
* Must come after all cleanup functions that call xmlFree which
2024-07-16 00:50:08 +03:00
* uses xmlMemMutex in debug mode .
2023-09-18 18:39:13 +03:00
*/
xmlCleanupMemoryInternal ( ) ;
xmlParserInitialized = 0 ;
2024-07-16 00:50:08 +03:00
/*
* This is a bit sketchy but should make reinitialization work .
*/
# ifdef HAVE_POSIX_THREADS
{
pthread_once_t tmp = PTHREAD_ONCE_INIT ;
memcpy ( & onceControl , & tmp , sizeof ( tmp ) ) ;
}
# elif defined(HAVE_WIN32_THREADS)
{
INIT_ONCE tmp = INIT_ONCE_STATIC_INIT ;
memcpy ( & onceControl , & tmp , sizeof ( tmp ) ) ;
}
# else
onceControl = 0 ;
# endif
2001-10-12 21:29:10 +04:00
}
2003-05-17 14:55:15 +04:00
2024-06-25 23:14:47 +03:00
# if defined(HAVE_FUNC_ATTRIBUTE_DESTRUCTOR) && \
2023-10-18 21:06:35 +03:00
! defined ( LIBXML_THREAD_ALLOC_ENABLED ) & & \
! defined ( LIBXML_STATIC ) & & \
2023-09-18 18:39:13 +03:00
! defined ( _WIN32 )
static void
ATTRIBUTE_DESTRUCTOR
xmlDestructor ( void ) {
/*
* Calling custom deallocation functions in a destructor can cause
* problems , for example with Nokogiri .
*/
if ( xmlFree = = free )
xmlCleanupParser ( ) ;
}
# endif