xref: /freebsd/contrib/unbound/util/locks.h (revision 5fa84c6ec176d186ddad25d31f8760e50f48157f)
1 /**
2  * util/locks.h - unbound locking primitives
3  *
4  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #ifndef UTIL_LOCKS_H
37 #define UTIL_LOCKS_H
38 
39 /**
40  * \file
41  * Locking primitives.
42  * If pthreads is available, these are used.
43  * If no locking exists, they do nothing.
44  *
45  * The idea is to have different sorts of locks for different tasks.
46  * This allows the locking code to be ported more easily.
47  *
48  * Types of locks that are supported.
49  *   o lock_rw: lock that has many readers and one writer (to a data entry).
50  *   o lock_basic: simple mutex. Blocking, one person has access only.
51  *     This lock is meant for non performance sensitive uses.
52  *   o lock_quick: speed lock. For performance sensitive locking of critical
53  *     sections. Could be implemented by a mutex or a spinlock.
54  *
55  * Also thread creation and deletion functions are defined here.
56  */
57 
58 /* if you define your own LOCKRET before including locks.h, you can get most
59  * locking functions without the dependency on log_err. */
60 #ifndef LOCKRET
61 #include "util/log.h"
62 /**
63  * The following macro is used to check the return value of the
64  * pthread calls. They return 0 on success and an errno on error.
65  * The errno is logged to the logfile with a descriptive comment.
66  */
67 #define LOCKRET(func) do {\
68 	int lockret_err;		\
69 	if( (lockret_err=(func)) != 0)		\
70 		log_err("%s at %d could not " #func ": %s", \
71 		__FILE__, __LINE__, strerror(lockret_err));	\
72  	} while(0)
73 #endif
74 
75 /** DEBUG: use thread debug whenever possible */
76 #if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS)
77 #  define USE_THREAD_DEBUG
78 #endif
79 
80 #ifdef USE_THREAD_DEBUG
81 /******************* THREAD DEBUG ************************/
82 /* (some) checking; to detect races and deadlocks. */
83 #include "testcode/checklocks.h"
84 
85 #else /* USE_THREAD_DEBUG */
86 #define lock_protect(lock, area, size) /* nop */
87 #define lock_unprotect(lock, area) /* nop */
88 #define lock_get_mem(lock) (0) /* nothing */
89 #define checklock_start() /* nop */
90 #define checklock_stop() /* nop */
91 #define checklock_set_output_name(name) /* nop */
92 
93 #ifdef HAVE_PTHREAD
94 #include <pthread.h>
95 
96 /******************* PTHREAD ************************/
97 
98 /** use pthread mutex for basic lock */
99 typedef pthread_mutex_t lock_basic_type;
100 /** small front for pthread init func, NULL is default attrs. */
101 #define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
102 #define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
103 #define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock))
104 #define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
105 
106 #ifndef HAVE_PTHREAD_RWLOCK_T
107 /** in case rwlocks are not supported, use a mutex. */
108 typedef pthread_mutex_t lock_rw_type;
109 #define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
110 #define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
111 #define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock))
112 #define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock))
113 #define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
114 #else /* HAVE_PTHREAD_RWLOCK_T */
115 /** we use the pthread rwlock */
116 typedef pthread_rwlock_t lock_rw_type;
117 /** small front for pthread init func, NULL is default attrs. */
118 #define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL))
119 #define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock))
120 #define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock))
121 #define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock))
122 #define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock))
123 #endif /* HAVE_PTHREAD_RWLOCK_T */
124 
125 #ifndef HAVE_PTHREAD_SPINLOCK_T
126 /** in case spinlocks are not supported, use a mutex. */
127 typedef pthread_mutex_t lock_quick_type;
128 /** small front for pthread init func, NULL is default attrs. */
129 #define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
130 #define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
131 #define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock))
132 #define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
133 
134 #else /* HAVE_PTHREAD_SPINLOCK_T */
135 /** use pthread spinlock for the quick lock */
136 typedef pthread_spinlock_t lock_quick_type;
137 /**
138  * allocate process private since this is available whether
139  * Thread Process-Shared Synchronization is supported or not.
140  * This means only threads inside this process may access the lock.
141  * (not threads from another process that shares memory).
142  * spinlocks are not supported on all pthread platforms.
143  */
144 #define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE))
145 #define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock))
146 #define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock))
147 #define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock))
148 
149 #endif /* HAVE SPINLOCK */
150 
151 /** Thread creation */
152 typedef pthread_t ub_thread_type;
153 /** On alpine linux default thread stack size is 80 Kb. See
154 http://wiki.musl-libc.org/wiki/Functional_differences_from_glibc#Thread_stack_size
155 This is not enough and cause segfault. Other linux distros have 2 Mb at least.
156 Wrapper for set up thread stack size */
157 #define PTHREADSTACKSIZE 2*1024*1024
158 #define PTHREADCREATE(thr, stackrequired, func, arg) do {\
159 	pthread_attr_t attr; \
160 	size_t stacksize; \
161 	LOCKRET(pthread_attr_init(&attr)); \
162 	LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \
163 	if (stacksize < stackrequired) { \
164 		LOCKRET(pthread_attr_setstacksize(&attr, stackrequired)); \
165 		LOCKRET(pthread_create(thr, &attr, func, arg)); \
166 		LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \
167 		verbose(VERB_ALGO, "Thread stack size set to %u", (unsigned)stacksize); \
168 	} else {LOCKRET(pthread_create(thr, NULL, func, arg));} \
169 	} while(0)
170 /** Use wrapper for set thread stack size on attributes. */
171 #define ub_thread_create(thr, func, arg) PTHREADCREATE(thr, PTHREADSTACKSIZE, func, arg)
172 /** get self id. */
173 #define ub_thread_self() pthread_self()
174 /** wait for another thread to terminate */
175 #define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL))
176 typedef pthread_key_t ub_thread_key_type;
177 #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
178 #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
179 #define ub_thread_key_get(key) pthread_getspecific(key)
180 
181 #ifdef HAVE_PTHREAD_NP_H
182 #include <pthread_np.h>
183 #endif
184 #if defined(HAVE_PTHREAD_SET_NAME_NP)
185 	#define ub_thread_setname(thread, name) do {	\
186 		(void)pthread_set_name_np(thread, name);\
187 		} while(0)
188 #elif defined(HAVE_PTHREAD_SETNAME_NP1)
189 	#define ub_thread_setname(thread, name) do {	\
190 		(void)pthread_setname_np(name);		\
191 		} while(0)
192 #elif defined(HAVE_PTHREAD_SETNAME_NP3)
193 	#define ub_thread_setname(thread, name) do {		\
194 		(void)pthread_setname_np(thread, name, NULL);	\
195 		} while(0)
196 #elif defined(HAVE_PTHREAD_SETNAME_NP)
197 	#define ub_thread_setname(thread, name) do {	\
198 		(void)pthread_setname_np(thread, name);	\
199 		} while(0)
200 #else
201 	#define ub_thread_setname(thread, name) /* nop */
202 #endif /* HAVE_PTHREAD_SET_NAME_NP */
203 
204 
205 #else /* we do not HAVE_PTHREAD */
206 #ifdef HAVE_SOLARIS_THREADS
207 
208 /******************* SOLARIS THREADS ************************/
209 #include <synch.h>
210 #include <thread.h>
211 
212 typedef rwlock_t lock_rw_type;
213 #define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
214 #define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
215 #define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
216 #define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
217 #define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
218 
219 /** use basic mutex */
220 typedef mutex_t lock_basic_type;
221 #define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
222 #define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
223 #define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
224 #define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
225 
226 /** No spinlocks in solaris threads API. Use a mutex. */
227 typedef mutex_t lock_quick_type;
228 #define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
229 #define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
230 #define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
231 #define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
232 
233 /** Thread creation, create a default thread. */
234 typedef thread_t ub_thread_type;
235 #define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
236 #define ub_thread_self() thr_self()
237 #define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
238 typedef thread_key_t ub_thread_key_type;
239 #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
240 #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
241 void* ub_thread_key_get(ub_thread_key_type key);
242 #define ub_thread_setname(thread, name) /* nop */
243 
244 
245 #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
246 /******************* WINDOWS THREADS ************************/
247 #ifdef HAVE_WINDOWS_THREADS
248 #include <windows.h>
249 
250 /* Use a mutex */
251 typedef LONG lock_rw_type;
252 #define lock_rw_init(lock) lock_basic_init(lock)
253 #define lock_rw_destroy(lock) lock_basic_destroy(lock)
254 #define lock_rw_rdlock(lock) lock_basic_lock(lock)
255 #define lock_rw_wrlock(lock) lock_basic_lock(lock)
256 #define lock_rw_unlock(lock) lock_basic_unlock(lock)
257 
258 /** the basic lock is a mutex, implemented opaquely, for error handling. */
259 typedef LONG lock_basic_type;
260 void lock_basic_init(lock_basic_type* lock);
261 void lock_basic_destroy(lock_basic_type* lock);
262 void lock_basic_lock(lock_basic_type* lock);
263 void lock_basic_unlock(lock_basic_type* lock);
264 
265 /** on windows no spinlock, use mutex too. */
266 typedef LONG lock_quick_type;
267 #define lock_quick_init(lock) lock_basic_init(lock)
268 #define lock_quick_destroy(lock) lock_basic_destroy(lock)
269 #define lock_quick_lock(lock) lock_basic_lock(lock)
270 #define lock_quick_unlock(lock) lock_basic_unlock(lock)
271 
272 /** Thread creation, create a default thread. */
273 typedef HANDLE ub_thread_type;
274 void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg);
275 ub_thread_type ub_thread_self(void);
276 void ub_thread_join(ub_thread_type thr);
277 typedef DWORD ub_thread_key_type;
278 void ub_thread_key_create(ub_thread_key_type* key, void* f);
279 void ub_thread_key_set(ub_thread_key_type key, void* v);
280 void* ub_thread_key_get(ub_thread_key_type key);
281 #define ub_thread_setname(thread, name) /* nop */
282 
283 #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
284 
285 /******************* NO THREADS ************************/
286 #define THREADS_DISABLED 1
287 /** In case there is no thread support, define locks to do nothing */
288 typedef int lock_rw_type;
289 #define lock_rw_init(lock) /* nop */
290 #define lock_rw_destroy(lock) /* nop */
291 #define lock_rw_rdlock(lock) /* nop */
292 #define lock_rw_wrlock(lock) /* nop */
293 #define lock_rw_unlock(lock) /* nop */
294 
295 /** define locks to do nothing */
296 typedef int lock_basic_type;
297 #define lock_basic_init(lock) /* nop */
298 #define lock_basic_destroy(lock) /* nop */
299 #define lock_basic_lock(lock) /* nop */
300 #define lock_basic_unlock(lock) /* nop */
301 
302 /** define locks to do nothing */
303 typedef int lock_quick_type;
304 #define lock_quick_init(lock) /* nop */
305 #define lock_quick_destroy(lock) /* nop */
306 #define lock_quick_lock(lock) /* nop */
307 #define lock_quick_unlock(lock) /* nop */
308 
309 /** Thread creation, threads do not exist */
310 typedef pid_t ub_thread_type;
311 /** ub_thread_create is simulated with fork (extremely heavy threads,
312   * with no shared memory). */
313 #define ub_thread_create(thr, func, arg) \
314 	ub_thr_fork_create(thr, func, arg)
315 #define ub_thread_self() getpid()
316 #define ub_thread_join(thread) ub_thr_fork_wait(thread)
317 void ub_thr_fork_wait(ub_thread_type thread);
318 void ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg);
319 typedef void* ub_thread_key_type;
320 #define ub_thread_key_create(key, f) (*(key)) = NULL
321 #define ub_thread_key_set(key, v) (key) = (v)
322 #define ub_thread_key_get(key) (key)
323 #define ub_thread_setname(thread, name) /* nop */
324 
325 #endif /* HAVE_WINDOWS_THREADS */
326 #endif /* HAVE_SOLARIS_THREADS */
327 #endif /* HAVE_PTHREAD */
328 #endif /* USE_THREAD_DEBUG */
329 
330 /**
331  * Block all signals for this thread.
332  * fatal exit on error.
333  */
334 void ub_thread_blocksigs(void);
335 
336 /**
337  * unblock one signal for this thread.
338  */
339 void ub_thread_sig_unblock(int sig);
340 
341 #endif /* UTIL_LOCKS_H */
342