diff --git a/dict.c b/dict.c index fed3a0ac4..780765722 100644 --- a/dict.c +++ b/dict.c @@ -60,7 +60,7 @@ typedef xmlHashedString xmlDictEntry; * The entire dictionary */ struct _xmlDict { - int ref_counter; + xmlRefCount refCount; xmlDictEntry *table; size_t size; @@ -74,12 +74,6 @@ struct _xmlDict { size_t limit; }; -/* - * A mutex for modifying the reference counter for shared - * dictionaries. - */ -static xmlMutex xmlDictMutex; - /** * @deprecated Alias for #xmlInitParser. * @@ -91,14 +85,6 @@ xmlInitializeDict(void) { return(0); } -/** - * Initialize mutex. - */ -void -xmlInitDictInternal(void) { - xmlInitMutex(&xmlDictMutex); -} - /** * @deprecated This function is a no-op. Call #xmlCleanupParser * to free global state but see the warnings there. #xmlCleanupParser @@ -109,14 +95,6 @@ void xmlDictCleanup(void) { } -/** - * Free the dictionary mutex. - */ -void -xmlCleanupDictInternal(void) { - xmlCleanupMutex(&xmlDictMutex); -} - /* * @param dict the dictionary * @param name the name of the userdata @@ -258,7 +236,6 @@ xmlDictCreate(void) { dict = xmlMalloc(sizeof(xmlDict)); if (dict == NULL) return(NULL); - dict->ref_counter = 1; dict->limit = 0; dict->size = 0; @@ -270,6 +247,9 @@ xmlDictCreate(void) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION dict->seed = 0; #endif + + xmlRefCountInit(&dict->refCount); + return(dict); } @@ -303,9 +283,7 @@ xmlDictCreateSub(xmlDict *sub) { int xmlDictReference(xmlDict *dict) { if (dict == NULL) return -1; - xmlMutexLock(&xmlDictMutex); - dict->ref_counter++; - xmlMutexUnlock(&xmlDictMutex); + xmlRefCountInc(&dict->refCount); return(0); } @@ -323,14 +301,8 @@ xmlDictFree(xmlDict *dict) { return; /* decrement the counter, it may be shared by a parser and docs */ - xmlMutexLock(&xmlDictMutex); - dict->ref_counter--; - if (dict->ref_counter > 0) { - xmlMutexUnlock(&xmlDictMutex); + if (xmlRefCountDec(&dict->refCount) > 0) return; - } - - xmlMutexUnlock(&xmlDictMutex); if (dict->subdict != NULL) { xmlDictFree(dict->subdict); diff --git a/include/private/dict.h b/include/private/dict.h index 4f2edb85a..8fe474b7c 100644 --- a/include/private/dict.h +++ b/include/private/dict.h @@ -50,11 +50,6 @@ typedef struct { const xmlChar *name; } xmlHashedString; -XML_HIDDEN void -xmlInitDictInternal(void); -XML_HIDDEN void -xmlCleanupDictInternal(void); - XML_HIDDEN unsigned xmlDictComputeHash(const xmlDict *dict, const xmlChar *string); XML_HIDDEN unsigned diff --git a/include/private/threads.h b/include/private/threads.h index bb187869c..92a8a0291 100644 --- a/include/private/threads.h +++ b/include/private/threads.h @@ -48,6 +48,141 @@ struct _xmlRMutex { #endif }; +#if defined(LIBXML_THREAD_ENABLED) && \ + __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) + +/** Atomic reference count */ +typedef _Atomic size_t xmlRefCount; + +/** + * Initialize refcount. + * + * @param r refcount + */ +static XML_INLINE void +xmlRefCountInit(xmlRefCount *r) { + *r = 1; +} + +/** + * Increase refcount. + * + * @param r refcount + */ +static XML_INLINE void +xmlRefCountInc(xmlRefCount *r) { + *r += 1; +} + +/** + * Decrease refcount. + * + * @param r refcount + * @returns 0 if refcount reached zero, 1 otherwise + */ +static XML_INLINE int +xmlRefCountDec(xmlRefCount *r) { + return --*r > 0; +} + +#elif defined(HAVE_POSIX_THREADS) + +typedef struct { + pthread_mutex_t mutex; + size_t count; +} xmlRefCount; + +static XML_INLINE void +xmlRefCountInit(xmlRefCount *r) { + pthread_mutex_init(&r->mutex, NULL); + r->count = 1; +} + +static XML_INLINE void +xmlRefCountInc(xmlRefCount *r) { + pthread_mutex_lock(&r->mutex); + r->count += 1; + pthread_mutex_unlock(&r->mutex); +} + +static XML_INLINE int +xmlRefCountDec(xmlRefCount *r) { + size_t val; + + pthread_mutex_lock(&r->mutex); + val = --r->count; + pthread_mutex_unlock(&r->mutex); + + if (val > 0) + return 1; + + pthread_mutex_destroy(&r->mutex); + return 0; +} + +#elif defined(HAVE_WIN32_THREADS) + +#ifdef _WIN64 + +typedef __int64 xmlRefCount; + +static XML_INLINE void +xmlRefCountInit(xmlRefCount *r) { + *r = 1; +} + +static XML_INLINE void +xmlRefCountInc(xmlRefCount *r) { + InterlockedIncrement64(r); +} + +static XML_INLINE int +xmlRefCountDec(xmlRefCount *r) { + return InterlockedDecrement64(r) > 0; +} + +#else /* 32-bit */ + +typedef long xmlRefCount; + +static XML_INLINE void +xmlRefCountInit(xmlRefCount *r) { + *r = 1; +} + +static XML_INLINE void +xmlRefCountInc(xmlRefCount *r) { + InterlockedIncrement(r); +} + +static XML_INLINE int +xmlRefCountDec(xmlRefCount *r) { + return InterlockedDecrement(r) > 0; +} + +#endif + +#else /* no threads */ + +typedef size_t xmlRefCount; + +static XML_INLINE void +xmlRefCountInit(xmlRefCount *r) { + *r = 1; +} + +static XML_INLINE void +xmlRefCountInc(xmlRefCount *r) { + *r += 1; +} + +static XML_INLINE int +xmlRefCountDec(xmlRefCount *r) { + return --*r > 0; +} + +#endif + XML_HIDDEN void xmlInitMutex(xmlMutex *mutex); XML_HIDDEN void diff --git a/threads.c b/threads.c index c4fe93ae8..8958a4628 100644 --- a/threads.c +++ b/threads.c @@ -361,7 +361,6 @@ xmlInitParserInternal(void) { xmlInitMemoryInternal(); xmlInitThreadsInternal(); xmlInitGlobalsInternal(); - xmlInitDictInternal(); xmlInitEncodingInternal(); #if defined(LIBXML_XPATH_ENABLED) xmlInitXPathInternal(); @@ -470,7 +469,6 @@ xmlCleanupParser(void) { xmlCleanupRelaxNGInternal(); #endif - xmlCleanupDictInternal(); xmlCleanupRandom(); xmlCleanupGlobalsInternal(); xmlCleanupThreadsInternal();