1
0
mirror of https://github.com/GNOME/libxml2.git synced 2025-10-14 02:58:39 +08:00

dict: Rework reference counting

Use C11 atomics if available. Otherwise, fall back to pthread mutex
inlined in xmlDict struct or Win32 atomics.

This should fix lock contention reported in #970.
This commit is contained in:
Nick Wellnhofer
2025-08-16 14:36:43 +02:00
parent 24caea6383
commit 18bbdb5117
4 changed files with 141 additions and 41 deletions

40
dict.c
View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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();