38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * threads.c: set of generic threading related routines
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * See Copyright for the status of this software.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Gary Pennington <Gary.Pennington@uk.sun.com>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * daniel@veillard.com
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/* #define DEBUG_THREADS */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncextern int pthread_once (pthread_once_t *__once_control,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void (*__init_routine) (void))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncextern void *pthread_getspecific (pthread_key_t __key)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncextern int pthread_setspecific (pthread_key_t __key,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncextern int pthread_key_create (pthread_key_t *__key,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void (*__destr_function) (void *))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* linux */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* __GNUC__ */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* HAVE_PTHREAD_H */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * TODO: this module still uses malloc/free and not xmlMalloc/xmlFree
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * to avoid some crazyness since xmlMalloc/xmlFree may actually
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * be hosted on allocated blocks needing them for the allocation ...
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlMutex are a simple mutual exception locks
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlRMutex are reentrant mutual exception locks
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync unsigned int count;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * This module still has some internal static data.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * - xmlLibraryLock a global lock
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * - globalkey used for per-thread data
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstatic pthread_once_t once_control = PTHREAD_ONCE_INIT;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstatic pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#else /* HAVE_COMPILER_TLS */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* HAVE_COMPILER_TLS */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstatic struct
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstatic volatile LPCRITICAL_SECTION global_init_lock = NULL;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/* endif HAVE_WIN32_THREADS */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstatic void xmlOnceInit(void);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlNewMutex:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlNewMutex() is used to allocate a libxml2 token struct for use in
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * synchronizing access to data.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Returns a new simple mutex pointer or NULL in case of error
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if ((tok->sem = create_sem(1, "xmlMutex")) < B_OK) {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlFreeMutex:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @tok: the simple mutex
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlFreeMutex() is used to reclaim resources associated with a libxml2 token
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlMutexLock:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @tok: the simple mutex
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlMutexLock() is used to lock a libxml2 token.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync xmlGenericError(xmlGenericErrorContext, "xmlMutexLock():BeOS:Couldn't aquire semaphore\n");
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlMutexUnlock:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @tok: the simple mutex
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlMutexUnlock() is used to unlock a libxml2 token.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlNewRMutex:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlRNewMutex() is used to allocate a reentrant mutex for use in
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * synchronizing access to data. token_r is a re-entrant lock and thus useful
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * for synchronizing access to data structures that may be manipulated in a
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * recursive fashion.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Returns the new reentrant mutex pointer or NULL in case of error
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlFreeRMutex:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @tok: the reentrant mutex
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlRFreeMutex() is used to reclaim resources associated with a
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * reentrant mutex.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlRMutexLock:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @tok: the reentrant mutex
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlRMutexLock() is used to lock a libxml2 token_r.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlRMutexUnlock:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @tok: the reentrant mutex
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlRMutexUnlock() is used to unlock a libxml2 token_r.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlGlobalInitMutexLock
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Makes sure that the global initialization mutex is initialized and
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * locks it.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Make sure the global init lock is initialized and then lock it. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* The mutex is statically initialized, so we just lock it. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Create a new critical section */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Swap it into the global_init_lock */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync InterlockedCompareExchangePointer(&global_init_lock, cs, NULL);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#else /* Use older void* version */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync InterlockedCompareExchange((void **)&global_init_lock, (void *)cs, NULL);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* InterlockedCompareExchangePointer */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* If another thread successfully recorded its critical
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * section in the global_init_lock then discard the one
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * allocated by this thread. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Lock the chosen critical section */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Allocate a new semaphore */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* If another thread successfully recorded its critical
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * section in the global_init_lock then discard the one
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * allocated by this thread. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Acquire the chosen semaphore */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync xmlGenericError(xmlGenericErrorContext, "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlGlobalInitMutexDestroy
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Makes sure that the global initialization mutex is destroyed before
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * application termination.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/************************************************************************
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Per thread global state handling *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ************************************************************************/
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlFreeGlobalState:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @state: a thread global state
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlFreeGlobalState() is called when a thread terminates with a non-NULL
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * global state. It is is used here to reclaim memory resources.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* free any memory allocated in the thread's xmlLastError */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlNewGlobalState:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlNewGlobalState() allocates a global state. This structure is used to
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * hold all data for use by a thread when supporting backwards compatibility
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * of libxml2 to pre-thread-safe behaviour.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Returns the newly allocated xmlGlobalStatePtr or NULL in case of error
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* LIBXML_THREAD_ENABLED */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstatic void XMLCDECL xmlGlobalStateCleanupHelper (void *p)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync xmlGlobalStateCleanupHelperParams *params = (xmlGlobalStateCleanupHelperParams *) p;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#else /* LIBXML_STATIC && !LIBXML_STATIC_FOR_DLL */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstatic xmlGlobalStateCleanupHelperParams * cleanup_helpers_head = NULL;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* LIBXMLSTATIC && !LIBXML_STATIC_FOR_DLL */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* HAVE_COMPILER_TLS */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* HAVE_WIN32_THREADS */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlGlobalStateCleanup:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @data: unused parameter
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Used for Beos only
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlGetGlobalState:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlGetGlobalState() is called to retrieve the global state for a thread.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Returns the thread global state or NULL in case of error
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#else /* HAVE_COMPILER_TLS */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync globalval = (xmlGlobalState *)TlsGetValue(globalkey);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync p = (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync globalval = (xmlGlobalState *)(p ? p->memory : NULL);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync p = (xmlGlobalStateCleanupHelperParams *) malloc(sizeof(xmlGlobalStateCleanupHelperParams));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#if defined(LIBXML_STATIC) && !defined(LIBXML_STATIC_FOR_DLL)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync GetCurrentProcess(), &p->thread, 0, TRUE, DUPLICATE_SAME_ACCESS);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif /* HAVE_COMPILER_TLS */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/************************************************************************
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Library wide thread interfaces *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ************************************************************************/
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlGetThreadId:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlGetThreadId() find the current thread ID number
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Returns the current thread ID number
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return((int) pthread_self());
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return((int) 0);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlIsMainThread:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlIsMainThread() check whether the current thread is the main thread.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Returns 1 if the current thread is the main thread, 0 otherwise
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync xmlGenericError(xmlGenericErrorContext, "xmlIsMainThread()\n");
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlLockLibrary:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlLockLibrary() is used to take out a re-entrant lock on the libxml2
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync xmlGenericError(xmlGenericErrorContext, "xmlLockLibrary()\n");
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlUnlockLibrary:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlUnlockLibrary() is used to release a re-entrant lock on the libxml2
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync xmlGenericError(xmlGenericErrorContext, "xmlUnlockLibrary()\n");
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlInitThreads:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlInitThreads() is used to to initialize all the thread related
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * data of the libxml2 library.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync xmlGenericError(xmlGenericErrorContext, "xmlInitThreads()\n");
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/* fprintf(stderr, "Running multithreaded\n"); */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/* fprintf(stderr, "Running without multithread\n"); */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlCleanupThreads:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlCleanupThreads() is used to to cleanup all the thread related
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * data of the libxml2 library once processing has ended.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync xmlGenericError(xmlGenericErrorContext, "xmlCleanupThreads()\n");
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync while (p != NULL) {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlOnceInit
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * xmlOnceInit() is used to initialize the value of mainthread for use
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * in other routines. This function should only be called using
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * pthread_once() in association with the once_control variable to ensure
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * that the function is only called once. See man pthread_once for more
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync (void) pthread_key_create(&globalkey, xmlFreeGlobalState);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Another thread is working; give up our slice and
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * wait until they're done. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @hinstDLL: handle to DLL instance
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @fdwReason: Reason code for entry
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @lpvReserved: generic pointer (depends upon reason code)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Entry point for Windows library. It is being used to free thread-specific
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Returns TRUE always
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#if defined(HAVE_WIN32_THREADS) && !defined(HAVE_COMPILER_TLS) && (!defined(LIBXML_STATIC) || defined(LIBXML_STATIC_FOR_DLL))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncBOOL XMLCALL xmlDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncBOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync (xmlGlobalStateCleanupHelperParams*)TlsGetValue(globalkey);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync globalval = (xmlGlobalState *)(p ? p->memory : NULL);