Fix broken smb_thread_once function (again)
[Samba/gbeck.git] / lib / util / smb_threads.c
blobe2d01f775a4e0e7d09183fa704a2ff6d9001207e
1 /*
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.
26 #include "includes.h"
27 #include "smb_threads.h"
29 /*********************************************************
30 Functions to vector the locking primitives used internally
31 by libsmbclient.
32 *********************************************************/
34 const struct smb_thread_functions *global_tfp;
36 /*********************************************************
37 Dynamic lock array.
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)
55 int i;
57 global_tfp = tf;
59 #if defined(PARANOID_MALLOC_CHECKER)
60 #ifdef malloc
61 #undef malloc
62 #endif
63 #endif
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
70 #endif
72 if (global_lock_array == NULL) {
73 return ENOMEM;
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;
82 if (global_tfp->create_mutex(name,
83 &global_lock_array[i],
84 __location__)) {
85 smb_panic("smb_thread_set_functions: create mutexes failed");
87 SAFE_FREE(name);
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");
95 return 0;
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 ********************************************************************/
108 int smb_thread_once(smb_thread_once_t *ponce, void (*init_fn)(void))
110 int ret;
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 smb_panic("error locking 'once'");
118 * See if another thread got here after we tested it initially but
119 * before we got our lock.
121 if (! *ponce) {
122 /* Nope, we need to run the initialization function */
123 (*init_fn)();
125 /* Now we can indicate that the function has been run */
126 *ponce = true;
129 /* Unlock the mutex */
130 if ((ret = SMB_THREAD_LOCK(once_mutex, SMB_THREAD_UNLOCK)) != 0) {
131 smb_panic("error unlocking 'once'");
134 return 0;
138 #if 0
139 /* Test. - pthread implementations. */
140 #include <pthread.h>
142 #ifdef malloc
143 #undef malloc
144 #endif
146 SMB_THREADS_DEF_PTHREAD_IMPLEMENTATION(tf);
148 static smb_thread_once_t ot = SMB_THREAD_ONCE_INIT;
149 void *pkey = NULL;
151 static void init_fn(void)
153 int ret;
155 if (!global_tfp) {
156 /* Non-thread safe init case. */
157 if (ot) {
158 return;
160 ot = true;
163 if ((ret = SMB_THREAD_CREATE_TLS("test_tls", pkey)) != 0) {
164 printf("Create tls once error: %d\n", ret);
168 /* Test function. */
169 int test_threads(void)
171 int ret;
172 void *plock = NULL;
173 smb_thread_set_functions(&tf);
175 SMB_THREAD_ONCE(&ot, init_fn);
177 if ((ret = SMB_THREAD_CREATE_MUTEX("test", plock)) != 0) {
178 printf("Create lock error: %d\n", ret);
180 if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_LOCK)) != 0) {
181 printf("lock error: %d\n", ret);
183 if ((ret = SMB_THREAD_LOCK(plock, SMB_THREAD_UNLOCK)) != 0) {
184 printf("unlock error: %d\n", ret);
186 SMB_THREAD_DESTROY_MUTEX(plock);
187 SMB_THREAD_DESTROY_TLS(pkey);
189 return 0;
191 #endif