summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/util/smb_threads.c64
-rw-r--r--lib/util/smb_threads.h22
-rw-r--r--lib/util/smb_threads_internal.h2
3 files changed, 66 insertions, 22 deletions
diff --git a/lib/util/smb_threads.c b/lib/util/smb_threads.c
index 1998211d40..8cddbf0176 100644
--- a/lib/util/smb_threads.c
+++ b/lib/util/smb_threads.c
@@ -40,6 +40,13 @@ const struct smb_thread_functions *global_tfp;
void **global_lock_array;
/*********************************************************
+ Mutex used for our internal "once" function
+*********************************************************/
+
+void *once_mutex = NULL;
+
+
+/*********************************************************
Function to set the locking primitives used by libsmbclient.
*********************************************************/
@@ -80,9 +87,64 @@ int smb_thread_set_functions(const struct smb_thread_functions *tf)
SAFE_FREE(name);
}
+ /* Create the mutex we'll use for our "once" function */
+ if (SMB_THREAD_CREATE_MUTEX("smb_once", once_mutex) != 0) {
+ smb_panic("smb_thread_set_functions: failed to create 'once' mutex");
+ }
+
return 0;
}
+/*******************************************************************
+ Call a function only once. We implement this ourselves
+ using our own mutex rather than using the thread implementation's
+ *_once() function because each implementation has its own
+ type for the variable which keeps track of whether the function
+ has been called, and there's no easy way to allocate the correct
+ size variable in code internal to Samba without knowing the
+ implementation's "once" type.
+********************************************************************/
+void smb_thread_once(smb_thread_once_t *ponce, void (*init_fn)(void))
+{
+ int ret;
+ int need_func_call;
+
+ /* Lock our "once" mutex in order to test and initialize ponce */
+ if ((ret = SMB_THREAD_LOCK(once_mutex, SMB_THREAD_LOCK)) != 0) {
+ DEBUG(0, ("error locking 'once': %d\n", ret));
+ }
+
+ /* Store whether we're going to need to issue the function call */
+ need_func_call = ! *ponce;
+
+ /*
+ * See if another thread got here after we tested it initially but
+ * before we got our lock.
+ */
+ if (need_func_call) {
+ /*
+ * Nope, we still need to issue the call. Set the "once"
+ * variable to true now so we can unlock the mutex. (We don't
+ * want to leave it locked during the call to the
+ * initialization function in case there's yet another "once"
+ * function needed to be called from therein.)
+ */
+ *ponce = true;
+ }
+
+ /* Unlock the mutex */
+ if ((ret = SMB_THREAD_LOCK(once_mutex, SMB_THREAD_UNLOCK)) != 0) {
+ DEBUG(0, ("error unlocking 'once': %d\n", ret));
+ }
+
+ /* Finally, if we need to call the user-provided function, ... */
+ if (need_func_call) {
+ /* ... then do so now. */
+ (*init_fn)();
+ }
+}
+
+
#if 0
/* Test. - pthread implementations. */
#include <pthread.h>
@@ -128,7 +190,7 @@ int test_threads(void)
if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_LOCK)) != 0) {
printf("lock error: %d\n", ret);
}
- if ((SMB_THREAD_LOCK(plock, SMB_THREAD_UNLOCK)) != 0) {
+ if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_UNLOCK)) != 0) {
printf("unlock error: %d\n", ret);
}
SMB_THREAD_DESTROY_MUTEX(plock);
diff --git a/lib/util/smb_threads.h b/lib/util/smb_threads.h
index 4443c3eae4..f1a39a6e28 100644
--- a/lib/util/smb_threads.h
+++ b/lib/util/smb_threads.h
@@ -20,20 +20,10 @@
#ifndef _smb_threads_h_
#define _smb_threads_h_
-/* Data types needed for smb_thread_once call. */
-
-#if defined(HAVE_PTHREAD_H)
-#include <pthread.h>
-#define smb_thread_once_t pthread_once_t
-#define SMB_THREAD_ONCE_INIT PTHREAD_ONCE_INIT
-#define SMB_THREAD_ONCE_IS_INITIALIZED(val) (true)
-#define SMB_THREAD_ONCE_INITIALIZE(val)
-#else
-#define smb_thread_once_t bool
+typedef bool smb_thread_once_t;
#define SMB_THREAD_ONCE_INIT false
#define SMB_THREAD_ONCE_IS_INITIALIZED(val) ((val) == true)
#define SMB_THREAD_ONCE_INITIALIZE(val) ((val) = true)
-#endif
enum smb_thread_lock_type {
SMB_THREAD_LOCK = 1,
@@ -50,9 +40,6 @@ struct smb_thread_functions {
int (*lock_mutex)(void *plock, enum smb_thread_lock_type lock_type,
const char *location);
- /* Once initialization. */
- int (*smb_thread_once)(smb_thread_once_t *p_once, void (*init_fn)(void));
-
/* Thread local storage. */
int (*create_tls)(const char *keyname,
void **ppkey,
@@ -64,6 +51,7 @@ struct smb_thread_functions {
};
int smb_thread_set_functions(const struct smb_thread_functions *tf);
+void smb_thread_once(smb_thread_once_t *ponce, void (*init_fn)(void));
extern const struct smb_thread_functions *global_tfp;
@@ -97,11 +85,6 @@ static int smb_lock_pthread(void *plock, enum smb_thread_lock_type lock_type, co
} \
} \
\
-static int smb_thread_once_pthread(smb_thread_once_t *p_once, void (*init_fn)(void)) \
-{ \
- return pthread_once(p_once, init_fn); \
-} \
- \
static int smb_create_tls_pthread(const char *keyname, void **ppkey, const char *location) \
{ \
int ret; \
@@ -142,7 +125,6 @@ static const struct smb_thread_functions (tf) = { \
smb_create_mutex_pthread, \
smb_destroy_mutex_pthread, \
smb_lock_pthread, \
- smb_thread_once_pthread, \
smb_create_tls_pthread, \
smb_destroy_tls_pthread, \
smb_set_tls_pthread, \
diff --git a/lib/util/smb_threads_internal.h b/lib/util/smb_threads_internal.h
index b7e862af72..0260934e15 100644
--- a/lib/util/smb_threads_internal.h
+++ b/lib/util/smb_threads_internal.h
@@ -34,7 +34,7 @@
(global_tfp ? global_tfp->lock_mutex((plock), (type), __location__) : 0)
#define SMB_THREAD_ONCE(ponce, init_fn) \
- (global_tfp ? global_tfp->smb_thread_once((ponce), (init_fn)) : ((init_fn()), 0))
+ (global_tfp ? smb_thread_once((ponce), (init_fn)) : ((init_fn()), 0))
#define SMB_THREAD_CREATE_TLS(keyname, key) \
(global_tfp ? global_tfp->create_tls((keyname), &(key), __location__) : 0)