2 Unix SMB/CIFS implementation.
3 SMB client library implementation (thread interface functions).
4 Copyright (C) Jeremy Allison, 2009.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * This code is based in the ideas in openssl
22 * but somewhat simpler and expended to include
23 * thread local storage.
27 #include "smb_threads.h"
29 /*********************************************************
30 Functions to vector the locking primitives used internally
32 *********************************************************/
34 const struct smb_thread_functions *global_tfp;
36 /*********************************************************
38 *********************************************************/
40 void **global_lock_array;
42 /*********************************************************
43 Mutex used for our internal "once" function
44 *********************************************************/
46 void *once_mutex = NULL;
49 /*********************************************************
50 Function to set the locking primitives used by libsmbclient.
51 *********************************************************/
53 int smb_thread_set_functions(const struct smb_thread_functions *tf)
59 #if defined(PARANOID_MALLOC_CHECKER)
65 /* Here we initialize any static locks we're using. */
66 global_lock_array = (void **)malloc(sizeof(void *) *NUM_GLOBAL_LOCKS);
68 #if defined(PARANOID_MALLOC_CHECKER)
69 #define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
72 if (global_lock_array == NULL) {
76 for (i = 0; i < NUM_GLOBAL_LOCKS; i++) {
78 if (asprintf(&name, "global_lock_%d", i) == -1) {
79 SAFE_FREE(global_lock_array);
82 if (global_tfp->create_mutex(name,
83 &global_lock_array[i],
85 smb_panic("smb_thread_set_functions: create mutexes failed");
90 /* Create the mutex we'll use for our "once" function */
91 if (SMB_THREAD_CREATE_MUTEX("smb_once", once_mutex) != 0) {
92 smb_panic("smb_thread_set_functions: failed to create 'once' mutex");
98 /*******************************************************************
99 Call a function only once. We implement this ourselves
100 using our own mutex rather than using the thread implementation's
101 *_once() function because each implementation has its own
102 type for the variable which keeps track of whether the function
103 has been called, and there's no easy way to allocate the correct
104 size variable in code internal to Samba without knowing the
105 implementation's "once" type.
106 ********************************************************************/
107 void smb_thread_once(smb_thread_once_t *ponce, void (*init_fn)(void))
112 /* Lock our "once" mutex in order to test and initialize ponce */
113 if ((ret = SMB_THREAD_LOCK(once_mutex, SMB_THREAD_LOCK)) != 0) {
114 DEBUG(0, ("error locking 'once': %d\n", ret));
117 /* Store whether we're going to need to issue the function call */
118 need_func_call = ! *ponce;
121 * See if another thread got here after we tested it initially but
122 * before we got our lock.
124 if (need_func_call) {
126 * Nope, we still need to issue the call. Set the "once"
127 * variable to true now so we can unlock the mutex. (We don't
128 * want to leave it locked during the call to the
129 * initialization function in case there's yet another "once"
130 * function needed to be called from therein.)
135 /* Unlock the mutex */
136 if ((ret = SMB_THREAD_LOCK(once_mutex, SMB_THREAD_UNLOCK)) != 0) {
137 DEBUG(0, ("error unlocking 'once': %d\n", ret));
140 /* Finally, if we need to call the user-provided function, ... */
141 if (need_func_call) {
142 /* ... then do so now. */
149 /* Test. - pthread implementations. */
156 SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION(tf);
158 static smb_thread_once_t ot = SMB_THREAD_ONCE_INIT;
161 static void init_fn(void)
166 /* Non-thread safe init case. */
173 if ((ret = SMB_THREAD_CREATE_TLS("test_tls", pkey)) != 0) {
174 printf("Create tls once error: %d\n", ret);
179 int test_threads(void)
183 smb_thread_set_functions(&tf);
185 SMB_THREAD_ONCE(&ot, init_fn);
187 if ((ret = SMB_THREAD_CREATE_MUTEX("test", plock)) != 0) {
188 printf("Create lock error: %d\n", ret);
190 if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_LOCK)) != 0) {
191 printf("lock error: %d\n", ret);
193 if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_UNLOCK)) != 0) {
194 printf("unlock error: %d\n", ret);
196 SMB_THREAD_DESTROY_MUTEX(plock);
197 SMB_THREAD_DESTROY_TLS(pkey);