From d3434477e6d42432a0acf426fcfbe39eb11b1fd0 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sun, 10 May 2009 21:55:23 -0400 Subject: Replace external thread "once" with an internal implementation Jeremy, please check... - I'm in the process of providing an interface in libsmbclient to the recently-added threading capabilities. In the process, I discovered that different thread implementations have varying types for the variable passed to the thread_impl_once() function. pthreads, for example, uses type pthread_once_t. Since Samba needs to internally declare these variables, it would need to know the exact type required by each thread implementation's function. After considering multiple methods of obtaining an appropriately sized variable, I decided that for the basic "once" functionality required by Samba, it would be much simpler to just implement our own "once" functionality. We don't require cancellation points et all. This commit adds an smb_thread_once() function that is implemented using an internal mutex. The mutex itself uses the implementation's create_mutex function. This eliminates the need for the user to provide a smb_thread_once function pointer and the entire issue of that function's first parameter. Derrell --- lib/util/smb_threads.c | 64 ++++++++++++++++++++++++++++++++++++++++- lib/util/smb_threads.h | 22 ++------------ lib/util/smb_threads_internal.h | 2 +- 3 files changed, 66 insertions(+), 22 deletions(-) (limited to 'lib/util') 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 @@ -39,6 +39,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 @@ -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 -#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) -- cgit