diff options
-rw-r--r-- | lib/util/smb_threads.c | 64 | ||||
-rw-r--r-- | lib/util/smb_threads.h | 22 | ||||
-rw-r--r-- | lib/util/smb_threads_internal.h | 2 |
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) |