| 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 "includes.h"
|
|---|
| 27 | #include "smb_threads.h"
|
|---|
| 28 |
|
|---|
| 29 | /*********************************************************
|
|---|
| 30 | Functions to vector the locking primitives used internally
|
|---|
| 31 | by libsmbclient.
|
|---|
| 32 | *********************************************************/
|
|---|
| 33 |
|
|---|
| 34 | const struct smb_thread_functions *global_tfp;
|
|---|
| 35 |
|
|---|
| 36 | /*********************************************************
|
|---|
| 37 | Dynamic lock array.
|
|---|
| 38 | *********************************************************/
|
|---|
| 39 |
|
|---|
| 40 | void **global_lock_array;
|
|---|
| 41 |
|
|---|
| 42 | /*********************************************************
|
|---|
| 43 | Mutex used for our internal "once" function
|
|---|
| 44 | *********************************************************/
|
|---|
| 45 |
|
|---|
| 46 | static void *once_mutex = NULL;
|
|---|
| 47 |
|
|---|
| 48 |
|
|---|
| 49 | /*********************************************************
|
|---|
| 50 | Function to set the locking primitives used by libsmbclient.
|
|---|
| 51 | *********************************************************/
|
|---|
| 52 |
|
|---|
| 53 | int smb_thread_set_functions(const struct smb_thread_functions *tf)
|
|---|
| 54 | {
|
|---|
| 55 | int i;
|
|---|
| 56 |
|
|---|
| 57 | global_tfp = tf;
|
|---|
| 58 |
|
|---|
| 59 | #if defined(PARANOID_MALLOC_CHECKER)
|
|---|
| 60 | #ifdef malloc
|
|---|
| 61 | #undef malloc
|
|---|
| 62 | #endif
|
|---|
| 63 | #endif
|
|---|
| 64 |
|
|---|
| 65 | /* Here we initialize any static locks we're using. */
|
|---|
| 66 | global_lock_array = (void **)malloc(sizeof(void *) *NUM_GLOBAL_LOCKS);
|
|---|
| 67 |
|
|---|
| 68 | #if defined(PARANOID_MALLOC_CHECKER)
|
|---|
| 69 | #define malloc(s) __ERROR_DONT_USE_MALLOC_DIRECTLY
|
|---|
| 70 | #endif
|
|---|
| 71 |
|
|---|
| 72 | if (global_lock_array == NULL) {
|
|---|
| 73 | return ENOMEM;
|
|---|
| 74 | }
|
|---|
| 75 |
|
|---|
| 76 | for (i = 0; i < NUM_GLOBAL_LOCKS; i++) {
|
|---|
| 77 | char *name = NULL;
|
|---|
| 78 | if (asprintf(&name, "global_lock_%d", i) == -1) {
|
|---|
| 79 | SAFE_FREE(global_lock_array);
|
|---|
| 80 | return ENOMEM;
|
|---|
| 81 | }
|
|---|
| 82 | if (global_tfp->create_mutex(name,
|
|---|
| 83 | &global_lock_array[i],
|
|---|
| 84 | __location__)) {
|
|---|
| 85 | smb_panic("smb_thread_set_functions: create mutexes failed");
|
|---|
| 86 | }
|
|---|
| 87 | SAFE_FREE(name);
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 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");
|
|---|
| 93 | }
|
|---|
| 94 |
|
|---|
| 95 | return 0;
|
|---|
| 96 | }
|
|---|
| 97 |
|
|---|
| 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 |
|
|---|
| 108 | int smb_thread_once(smb_thread_once_t *ponce,
|
|---|
| 109 | void (*init_fn)(void *pdata),
|
|---|
| 110 | void *pdata)
|
|---|
| 111 | {
|
|---|
| 112 | int ret;
|
|---|
| 113 |
|
|---|
| 114 | /* Lock our "once" mutex in order to test and initialize ponce */
|
|---|
| 115 | if (SMB_THREAD_LOCK(once_mutex) != 0) {
|
|---|
| 116 | smb_panic("error locking 'once'");
|
|---|
| 117 | }
|
|---|
| 118 |
|
|---|
| 119 | /* Keep track of whether we ran their init function */
|
|---|
| 120 | ret = ! *ponce;
|
|---|
| 121 |
|
|---|
| 122 | /*
|
|---|
| 123 | * See if another thread got here after we tested it initially but
|
|---|
| 124 | * before we got our lock.
|
|---|
| 125 | */
|
|---|
| 126 | if (! *ponce) {
|
|---|
| 127 | /* Nope, we need to run the initialization function */
|
|---|
| 128 | (*init_fn)(pdata);
|
|---|
| 129 |
|
|---|
| 130 | /* Now we can indicate that the function has been run */
|
|---|
| 131 | *ponce = true;
|
|---|
| 132 | }
|
|---|
| 133 |
|
|---|
| 134 | /* Unlock the mutex */
|
|---|
| 135 | if (SMB_THREAD_UNLOCK(once_mutex) != 0) {
|
|---|
| 136 | smb_panic("error unlocking 'once'");
|
|---|
| 137 | }
|
|---|
| 138 |
|
|---|
| 139 | /*
|
|---|
| 140 | * Tell 'em whether we ran their init function. If they passed a data
|
|---|
| 141 | * pointer to the init function and the init function could change
|
|---|
| 142 | * something in the pointed-to data, this will tell them whether that
|
|---|
| 143 | * data is valid or not.
|
|---|
| 144 | */
|
|---|
| 145 | return ret;
|
|---|
| 146 | }
|
|---|
| 147 |
|
|---|
| 148 |
|
|---|
| 149 | #if 0
|
|---|
| 150 | /* Test. - pthread implementations. */
|
|---|
| 151 | #include <pthread.h>
|
|---|
| 152 |
|
|---|
| 153 | #ifdef malloc
|
|---|
| 154 | #undef malloc
|
|---|
| 155 | #endif
|
|---|
| 156 |
|
|---|
| 157 | SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION(tf);
|
|---|
| 158 |
|
|---|
| 159 | static smb_thread_once_t ot = SMB_THREAD_ONCE_INIT;
|
|---|
| 160 | void *pkey = NULL;
|
|---|
| 161 |
|
|---|
| 162 | static void init_fn(void)
|
|---|
| 163 | {
|
|---|
| 164 | int ret;
|
|---|
| 165 |
|
|---|
| 166 | if (!global_tfp) {
|
|---|
| 167 | /* Non-thread safe init case. */
|
|---|
| 168 | if (ot) {
|
|---|
| 169 | return;
|
|---|
| 170 | }
|
|---|
| 171 | ot = true;
|
|---|
| 172 | }
|
|---|
| 173 |
|
|---|
| 174 | if ((ret = SMB_THREAD_CREATE_TLS("test_tls", pkey)) != 0) {
|
|---|
| 175 | printf("Create tls once error: %d\n", ret);
|
|---|
| 176 | }
|
|---|
| 177 | }
|
|---|
| 178 |
|
|---|
| 179 | /* Test function. */
|
|---|
| 180 | int test_threads(void)
|
|---|
| 181 | {
|
|---|
| 182 | int ret;
|
|---|
| 183 | void *plock = NULL;
|
|---|
| 184 | smb_thread_set_functions(&tf);
|
|---|
| 185 |
|
|---|
| 186 | SMB_THREAD_ONCE(&ot, init_fn);
|
|---|
| 187 |
|
|---|
| 188 | if ((ret = SMB_THREAD_CREATE_MUTEX("test", plock)) != 0) {
|
|---|
| 189 | printf("Create lock error: %d\n", ret);
|
|---|
| 190 | }
|
|---|
| 191 | if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_LOCK)) != 0) {
|
|---|
| 192 | printf("lock error: %d\n", ret);
|
|---|
| 193 | }
|
|---|
| 194 | if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_UNLOCK)) != 0) {
|
|---|
| 195 | printf("unlock error: %d\n", ret);
|
|---|
| 196 | }
|
|---|
| 197 | SMB_THREAD_DESTROY_MUTEX(plock);
|
|---|
| 198 | SMB_THREAD_DESTROY_TLS(pkey);
|
|---|
| 199 |
|
|---|
| 200 | return 0;
|
|---|
| 201 | }
|
|---|
| 202 | #endif
|
|---|