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:
40
dict.c
40
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);
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
|
Reference in New Issue
Block a user