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 : 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 : 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
|