Tuesday, December 24, 2013

libsmbclient3 and multithreading

If you want to use libsmbclient3 in process with many threads you are out of luck.
The first problem is talloc_stack.c in libsmbclient is not thread safe. Easy to fix
diff --git a/lib/util/talloc_stack.c b/lib/util/talloc_stack.c
index 8e559cc..b88962b 100644
--- a/lib/util/talloc_stack.c
+++ b/lib/util/talloc_stack.c
@@ -39,6 +39,11 @@
 
 #include "includes.h"
 
+
+#include <pthread.h>
+static pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER;
+
+
 struct talloc_stackframe {
     int talloc_stacksize;
     int talloc_stack_arraysize;
@@ -82,7 +87,12 @@ static struct talloc_stackframe *talloc_stackframe_create(void)
         smb_panic("talloc_stackframe_init malloc failed");
     }
 
-    SMB_THREAD_ONCE(&ts_initialized, talloc_stackframe_init, NULL);
+    SMB_THREAD_LOCK(&mutex_lock);
+    if (!ts_initialized)
+        talloc_stackframe_init(NULL);
+    ts_initialized = true;
+    SMB_THREAD_UNLOCK(&mutex_lock);
+    //SMB_THREAD_ONCE(&ts_initialized, talloc_stackframe_init, NULL);
 
     if (SMB_THREAD_SET_TLS(global_ts, ts)) {
         smb_panic("talloc_stackframe_init set_tls failed");
@@ -118,6 +128,7 @@ static int talloc_pop(TALLOC_CTX *frame)
 static TALLOC_CTX *talloc_stackframe_internal(size_t poolsize)
 {
     TALLOC_CTX **tmp, *top, *parent;
+    if (global_ts == NULL) talloc_stackframe_init(NULL);
     struct talloc_stackframe *ts =
         (struct talloc_stackframe *)SMB_THREAD_GET_TLS(global_ts);
Second problem. Methods set_global_myname() and set_global_myworkgroup() in source3/lib/util_names.c are not thread safe too.
diff --git a/source3/lib/util_names.c b/source3/lib/util_names.c
index bd6e5c1..1d8a96e 100644
--- a/source3/lib/util_names.c
+++ b/source3/lib/util_names.c
@@ -27,17 +27,24 @@
 static char *smb_myname;
 static char *smb_myworkgroup;
 
+#include <pthread.h>
+static pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER;
+
 /***********************************************************************
  Allocate and set myname. Ensure upper case.
 ***********************************************************************/
 
 bool set_global_myname(const char *myname)
 {
+    SMB_THREAD_LOCK(&mutex_lock);
     SAFE_FREE(smb_myname);
     smb_myname = SMB_STRDUP(myname);
-    if (!smb_myname)
+    if (!smb_myname) {
+        SMB_THREAD_UNLOCK(&mutex_lock);
         return False;
+    }
     strupper_m(smb_myname);
+    SMB_THREAD_UNLOCK(&mutex_lock);
     return True;
 }
 
@@ -52,11 +59,15 @@ const char *global_myname(void)
 
 bool set_global_myworkgroup(const char *myworkgroup)
 {
+    SMB_THREAD_LOCK(&mutex_lock);
     SAFE_FREE(smb_myworkgroup);
     smb_myworkgroup = SMB_STRDUP(myworkgroup);
-    if (!smb_myworkgroup)
+    if (!smb_myworkgroup) {
+        SMB_THREAD_UNLOCK(&mutex_lock);
         return False;
+    }
     strupper_m(smb_myworkgroup);
+    SMB_THREAD_UNLOCK(&mutex_lock);
     return True;
 }
What you still need to know about libsmbclient3 and multithreading? Each context (SMBCCTX) must be used only by one thread at the same time. All resources (open files and directories) are bound to specific context and one cannot use it in another.

No comments:

Post a Comment