Re: [xml] [patch] make libxml2 slightly more thread-friendly




Daniel Veillard writes:
  see libxml.h in same directory as the C sources, prefix the function names
by __ so even if it shows up in the shared object people are not tempted to
call them and dont export from include/libxml/*.h

Ah, I see it.  Thanks.


Hum, if you know you're in a specific environment where volatile is
expected then go ahead, just avoid it for the platform agnostic code
:-)

Ok, I've put the volatile qualifier back in.


Looks good except the __ renaming and include file.

Done.


Would you be so kind to make the last changes for the function name
and include, then I guess that should be commited,

Please see below.  Thanks again for your help.

Cheers,
-Ted


diff -Naurp libxml2-2.6.27.orig/libxml.h libxml2-2.6.27/libxml.h
--- libxml2-2.6.27.orig/libxml.h        2006-05-31 14:29:44.000000000 +0100
+++ libxml2-2.6.27/libxml.h     2007-02-12 16:32:17.000000000 +0000
@@ -64,6 +64,11 @@ void __xmlLoaderErr(void *ctx, const cha
 void __htmlParseContent(void *ctx);
 #endif
 
+/*
+ * internal global initialization critical section routines.
+ */
+void __xmlGlobalInitMutexLock(void);
+void __xmlGlobalInitMutexUnlock(void);
 
 #ifdef IN_LIBXML
 #ifdef __GNUC__
diff -Naurp libxml2-2.6.27.orig/parser.c libxml2-2.6.27/parser.c
--- libxml2-2.6.27.orig/parser.c        2006-10-17 15:28:27.000000000 +0100
+++ libxml2-2.6.27/parser.c     2007-02-12 16:35:39.000000000 +0000
@@ -12839,26 +12839,34 @@ xmlInitParser(void) {
     if (xmlParserInitialized != 0)
        return;
 
-    if ((xmlGenericError == xmlGenericErrorDefaultFunc) ||
-       (xmlGenericError == NULL))
-       initGenericErrorDefaultFunc(NULL);
-    xmlInitGlobals();
-    xmlInitThreads();
-    xmlInitMemory();
-    xmlInitCharEncodingHandlers();
-    xmlDefaultSAXHandlerInit();
-    xmlRegisterDefaultInputCallbacks();
+#ifdef LIBXML_THREAD_ENABLED
+    __xmlGlobalInitMutexLock();
+    if (xmlParserInitialized == 0) {
+#endif
+       if ((xmlGenericError == xmlGenericErrorDefaultFunc) ||
+           (xmlGenericError == NULL))
+           initGenericErrorDefaultFunc(NULL);
+       xmlInitGlobals();
+       xmlInitThreads();
+       xmlInitMemory();
+       xmlInitCharEncodingHandlers();
+       xmlDefaultSAXHandlerInit();
+       xmlRegisterDefaultInputCallbacks();
 #ifdef LIBXML_OUTPUT_ENABLED
-    xmlRegisterDefaultOutputCallbacks();
+       xmlRegisterDefaultOutputCallbacks();
 #endif /* LIBXML_OUTPUT_ENABLED */
 #ifdef LIBXML_HTML_ENABLED
-    htmlInitAutoClose();
-    htmlDefaultSAXHandlerInit();
+       htmlInitAutoClose();
+       htmlDefaultSAXHandlerInit();
 #endif
 #ifdef LIBXML_XPATH_ENABLED
-    xmlXPathInit();
+       xmlXPathInit();
+#endif
+       xmlParserInitialized = 1;
+#ifdef LIBXML_THREAD_ENABLED
+    }
+    __xmlGlobalInitMutexUnlock();
 #endif
-    xmlParserInitialized = 1;
 }
 
 /**
diff -Naurp libxml2-2.6.27.orig/threads.c libxml2-2.6.27/threads.c
--- libxml2-2.6.27.orig/threads.c       2006-06-26 13:16:03.000000000 +0100
+++ libxml2-2.6.27/threads.c    2007-02-12 16:38:20.000000000 +0000
@@ -139,6 +139,7 @@ struct _xmlRMutex {
 static pthread_key_t   globalkey;
 static pthread_t       mainthread;
 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+static pthread_mutex_t global_init_lock = PTHREAD_MUTEX_INITIALIZER;
 #elif defined HAVE_WIN32_THREADS
 #if defined(HAVE_COMPILER_TLS)
 static __declspec(thread) xmlGlobalState tlstate;
@@ -152,11 +153,14 @@ static struct
     DWORD done;
     DWORD control;
 } run_once = { 0, 0 };
+static volatile LPCRITICAL_SECTION global_init_lock = NULL;
 /* endif HAVE_WIN32_THREADS */
 #elif defined HAVE_BEOS_THREADS
 int32 globalkey = 0;
 thread_id mainthread = 0;
 int32 run_once_init = 0;
+static int32 global_init_lock = -1;
+static vint32 global_init_count = 0;
 #endif
 
 static xmlRMutexPtr    xmlLibraryLock = NULL;
@@ -413,6 +417,85 @@ xmlRMutexUnlock(xmlRMutexPtr tok ATTRIBU
 #endif
 }
 
+/**
+ * xmlGlobalInitMutexLock
+ *
+ * Makes sure that the global initialization mutex is initialized and
+ * locks it.
+ */
+void
+__xmlGlobalInitMutexLock(void)
+{
+    /* Make sure the global init lock is initialized and then lock it. */
+#ifdef HAVE_PTHREAD_H
+    int err;
+
+    /* The mutex is statically initialized, so we just lock it. */
+    pthread_mutex_lock(&global_init_lock);
+#elif defined HAVE_WIN32_THREADS
+    LPCRITICAL_SECTION cs;
+
+    /* Create a new critical section */
+    if (global_init_lock == NULL) {
+       cs = malloc(sizeof(CRITICAL_SECTION));
+       InitializeCriticalSection(cs);
+
+       /* Swap it into the global_init_lock */
+       InterlockedCompareExchangePointer(&global_init_lock, cs, NULL);
+
+       /* If another thread successfully recorded its critical
+        * section in the global_init_lock then discard the one
+        * allocated by this thread. */
+       if (global_init_lock != cs) {
+           free(cs);
+       }
+    }
+
+    /* Lock the chosen critical section */
+    EnterCriticalSection(global_init_lock);
+#elif defined HAVE_BEOS_THREADS
+    int32 sem;
+
+    /* Allocate a new semaphore */
+    sem = create_sem(1, "xmlGlobalinitMutex");
+
+    while (global_init_lock == -1) {
+       if (atomic_add(&global_init_count, 1) == 0) {
+           global_init_lock = sem;
+       } else {
+           snooze(1);
+           atomic_add(&global_init_count, -1);
+       }
+    }
+
+    /* If another thread successfully recorded its critical
+     * section in the global_init_lock then discard the one
+     * allocated by this thread. */
+    if (global_init_lock != sem)
+       delete_sem(sem);
+
+    /* Acquire the chosen semaphore */
+    if (acquire_sem(global_init_lock) != B_NO_ERROR) {
+#ifdef DEBUG_THREADS
+       xmlGenericError(xmlGenericErrorContext, "xmlGlobalInitMutexLock():BeOS:Couldn't acquire semaphore\n");
+       exit();
+#endif
+    }
+#endif
+}
+
+void
+__xmlGlobalInitMutexUnlock(void)
+{
+#ifdef HAVE_PTHREAD_H
+    pthread_mutex_unlock(&global_init_lock);
+#elif defined HAVE_WIN32_THREADS
+    LeaveCriticalSection(global_init_lock);
+#elif defined HAVE_BEOS_THREADS
+    release_sem(global_init_lock);
+#endif
+}
+
 /************************************************************************
  *                                                                     *
  *                     Per thread global state handling                *



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]