summaryrefslogtreecommitdiff
path: root/lib/util/smb_threads.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/util/smb_threads.c')
-rw-r--r--lib/util/smb_threads.c64
1 files changed, 63 insertions, 1 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);