Line data Source code
1 : /* 2 : Unix SMB/CIFS implementation. 3 : SMB client library implementation (thread interface functions). 4 : Copyright (C) Jeremy Allison, 2009. 5 : 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. 10 : 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. 15 : 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/>. 18 : */ 19 : 20 : /* 21 : * This code is based in the ideas in openssl 22 : * but somewhat simpler and expended to include 23 : * thread local storage. 24 : */ 25 : 26 : #include "replace.h" 27 : #include "smb_threads.h" 28 : #include "smb_threads_internal.h" 29 : #include "lib/util/debug.h" 30 : #include "lib/util/fault.h" 31 : #include "lib/util/memory.h" 32 : 33 : /********************************************************* 34 : Functions to vector the locking primitives used internally 35 : by libsmbclient. 36 : *********************************************************/ 37 : 38 : const struct smb_thread_functions *global_tfp; 39 : 40 : /********************************************************* 41 : Dynamic lock array. 42 : *********************************************************/ 43 : 44 : void **global_lock_array; 45 : 46 : /********************************************************* 47 : Mutex used for our internal "once" function 48 : *********************************************************/ 49 : 50 : static void *once_mutex = NULL; 51 : 52 : 53 : /********************************************************* 54 : Function to set the locking primitives used by libsmbclient. 55 : *********************************************************/ 56 : 57 0 : int smb_thread_set_functions(const struct smb_thread_functions *tf) 58 : { 59 0 : int i; 60 : 61 0 : global_tfp = tf; 62 : 63 : #if defined(PARANOID_MALLOC_CHECKER) 64 : #ifdef malloc 65 : #undef malloc 66 : #endif 67 : #endif 68 : 69 : /* Here we initialize any static locks we're using. */ 70 0 : global_lock_array = (void **)malloc(sizeof(void *) *NUM_GLOBAL_LOCKS); 71 : 72 : #if defined(PARANOID_MALLOC_CHECKER) 73 : #define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY 74 : #endif 75 : 76 0 : if (global_lock_array == NULL) { 77 0 : return ENOMEM; 78 : } 79 : 80 0 : for (i = 0; i < NUM_GLOBAL_LOCKS; i++) { 81 0 : char *name = NULL; 82 0 : if (asprintf(&name, "global_lock_%d", i) == -1) { 83 0 : SAFE_FREE(global_lock_array); 84 0 : return ENOMEM; 85 : } 86 0 : if (global_tfp->create_mutex(name, 87 0 : &global_lock_array[i], 88 : __location__)) { 89 0 : smb_panic("smb_thread_set_functions: create mutexes failed"); 90 : } 91 0 : SAFE_FREE(name); 92 : } 93 : 94 : /* Create the mutex we'll use for our "once" function */ 95 0 : if (SMB_THREAD_CREATE_MUTEX("smb_once", once_mutex) != 0) { 96 0 : smb_panic("smb_thread_set_functions: failed to create 'once' mutex"); 97 : } 98 : 99 0 : return 0; 100 : } 101 : 102 : /******************************************************************* 103 : Call a function only once. We implement this ourselves 104 : using our own mutex rather than using the thread implementation's 105 : *_once() function because each implementation has its own 106 : type for the variable which keeps track of whether the function 107 : has been called, and there's no easy way to allocate the correct 108 : size variable in code internal to Samba without knowing the 109 : implementation's "once" type. 110 : ********************************************************************/ 111 : 112 0 : int smb_thread_once(smb_thread_once_t *ponce, 113 : void (*init_fn)(void *pdata), 114 : void *pdata) 115 : { 116 0 : int ret; 117 : 118 : /* Lock our "once" mutex in order to test and initialize ponce */ 119 0 : if (SMB_THREAD_LOCK(once_mutex) != 0) { 120 0 : smb_panic("error locking 'once'"); 121 : } 122 : 123 : /* Keep track of whether we ran their init function */ 124 0 : ret = ! *ponce; 125 : 126 : /* 127 : * See if another thread got here after we tested it initially but 128 : * before we got our lock. 129 : */ 130 0 : if (! *ponce) { 131 : /* Nope, we need to run the initialization function */ 132 0 : (*init_fn)(pdata); 133 : 134 : /* Now we can indicate that the function has been run */ 135 0 : *ponce = true; 136 : } 137 : 138 : /* Unlock the mutex */ 139 0 : if (SMB_THREAD_UNLOCK(once_mutex) != 0) { 140 0 : smb_panic("error unlocking 'once'"); 141 : } 142 : 143 : /* 144 : * Tell 'em whether we ran their init function. If they passed a data 145 : * pointer to the init function and the init function could change 146 : * something in the pointed-to data, this will tell them whether that 147 : * data is valid or not. 148 : */ 149 0 : return ret; 150 : } 151 : 152 : 153 : #if 0 154 : /* Test. - pthread implementations. */ 155 : #include <pthread.h> 156 : 157 : #ifdef malloc 158 : #undef malloc 159 : #endif 160 : 161 : SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION(tf); 162 : 163 : static smb_thread_once_t ot = SMB_THREAD_ONCE_INIT; 164 : void *pkey = NULL; 165 : 166 : static void init_fn(void) 167 : { 168 : int ret; 169 : 170 : if (!global_tfp) { 171 : /* Non-thread safe init case. */ 172 : if (ot) { 173 : return; 174 : } 175 : ot = true; 176 : } 177 : 178 : if ((ret = SMB_THREAD_CREATE_TLS("test_tls", pkey)) != 0) { 179 : printf("Create tls once error: %d\n", ret); 180 : } 181 : } 182 : 183 : /* Test function. */ 184 : int test_threads(void) 185 : { 186 : int ret; 187 : void *plock = NULL; 188 : smb_thread_set_functions(&tf); 189 : 190 : SMB_THREAD_ONCE(&ot, init_fn); 191 : 192 : if ((ret = SMB_THREAD_CREATE_MUTEX("test", plock)) != 0) { 193 : printf("Create lock error: %d\n", ret); 194 : } 195 : if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_LOCK)) != 0) { 196 : printf("lock error: %d\n", ret); 197 : } 198 : if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_UNLOCK)) != 0) { 199 : printf("unlock error: %d\n", ret); 200 : } 201 : SMB_THREAD_DESTROY_MUTEX(plock); 202 : SMB_THREAD_DESTROY_TLS(pkey); 203 : 204 : return 0; 205 : } 206 : #endif