xref: /openbsd-src/usr.sbin/unbound/util/locks.h (revision 77079be7e74cd516ce5a60021c2a03ba383e594d)
1933707f3Ssthen /**
2933707f3Ssthen  * util/locks.h - unbound locking primitives
3933707f3Ssthen  *
4933707f3Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen  *
6933707f3Ssthen  * This software is open source.
7933707f3Ssthen  *
8933707f3Ssthen  * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen  * modification, are permitted provided that the following conditions
10933707f3Ssthen  * are met:
11933707f3Ssthen  *
12933707f3Ssthen  * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen  * this list of conditions and the following disclaimer.
14933707f3Ssthen  *
15933707f3Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen  * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen  * and/or other materials provided with the distribution.
18933707f3Ssthen  *
19933707f3Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen  * be used to endorse or promote products derived from this software without
21933707f3Ssthen  * specific prior written permission.
22933707f3Ssthen  *
23933707f3Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen 
36933707f3Ssthen #ifndef UTIL_LOCKS_H
37933707f3Ssthen #define UTIL_LOCKS_H
38933707f3Ssthen 
39933707f3Ssthen /**
40933707f3Ssthen  * \file
41933707f3Ssthen  * Locking primitives.
42933707f3Ssthen  * If pthreads is available, these are used.
43933707f3Ssthen  * If no locking exists, they do nothing.
44933707f3Ssthen  *
45933707f3Ssthen  * The idea is to have different sorts of locks for different tasks.
46933707f3Ssthen  * This allows the locking code to be ported more easily.
47933707f3Ssthen  *
48933707f3Ssthen  * Types of locks that are supported.
49933707f3Ssthen  *   o lock_rw: lock that has many readers and one writer (to a data entry).
50933707f3Ssthen  *   o lock_basic: simple mutex. Blocking, one person has access only.
51933707f3Ssthen  *     This lock is meant for non performance sensitive uses.
52933707f3Ssthen  *   o lock_quick: speed lock. For performance sensitive locking of critical
53933707f3Ssthen  *     sections. Could be implemented by a mutex or a spinlock.
54933707f3Ssthen  *
55933707f3Ssthen  * Also thread creation and deletion functions are defined here.
56933707f3Ssthen  */
57933707f3Ssthen 
5898f3ca02Sbrad /* if you define your own LOCKRET before including locks.h, you can get most
5998f3ca02Sbrad  * locking functions without the dependency on log_err. */
6098f3ca02Sbrad #ifndef LOCKRET
61933707f3Ssthen #include "util/log.h"
62933707f3Ssthen /**
63933707f3Ssthen  * The following macro is used to check the return value of the
64933707f3Ssthen  * pthread calls. They return 0 on success and an errno on error.
65933707f3Ssthen  * The errno is logged to the logfile with a descriptive comment.
66933707f3Ssthen  */
67933707f3Ssthen #define LOCKRET(func) do {\
68933707f3Ssthen 	int lockret_err;		\
69933707f3Ssthen 	if( (lockret_err=(func)) != 0)		\
70933707f3Ssthen 		log_err("%s at %d could not " #func ": %s", \
71933707f3Ssthen 		__FILE__, __LINE__, strerror(lockret_err));	\
72933707f3Ssthen  	} while(0)
7398f3ca02Sbrad #endif
74933707f3Ssthen 
75933707f3Ssthen /** DEBUG: use thread debug whenever possible */
76933707f3Ssthen #if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS)
77933707f3Ssthen #  define USE_THREAD_DEBUG
78933707f3Ssthen #endif
79933707f3Ssthen 
80933707f3Ssthen #ifdef USE_THREAD_DEBUG
81933707f3Ssthen /******************* THREAD DEBUG ************************/
82933707f3Ssthen /* (some) checking; to detect races and deadlocks. */
83933707f3Ssthen #include "testcode/checklocks.h"
84933707f3Ssthen 
85933707f3Ssthen #else /* USE_THREAD_DEBUG */
86933707f3Ssthen #define lock_protect(lock, area, size) /* nop */
87933707f3Ssthen #define lock_unprotect(lock, area) /* nop */
88933707f3Ssthen #define lock_get_mem(lock) (0) /* nothing */
89933707f3Ssthen #define checklock_start() /* nop */
90933707f3Ssthen #define checklock_stop() /* nop */
91933707f3Ssthen 
92933707f3Ssthen #ifdef HAVE_PTHREAD
93933707f3Ssthen #include <pthread.h>
94933707f3Ssthen 
95933707f3Ssthen /******************* PTHREAD ************************/
96933707f3Ssthen 
97933707f3Ssthen /** use pthread mutex for basic lock */
98*77079be7Ssthen typedef pthread_mutex_t lock_basic_type;
99933707f3Ssthen /** small front for pthread init func, NULL is default attrs. */
100933707f3Ssthen #define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
101933707f3Ssthen #define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
102933707f3Ssthen #define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock))
103933707f3Ssthen #define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
104933707f3Ssthen 
105933707f3Ssthen #ifndef HAVE_PTHREAD_RWLOCK_T
106933707f3Ssthen /** in case rwlocks are not supported, use a mutex. */
107*77079be7Ssthen typedef pthread_mutex_t lock_rw_type;
108933707f3Ssthen #define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
109933707f3Ssthen #define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
110933707f3Ssthen #define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock))
111933707f3Ssthen #define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock))
112933707f3Ssthen #define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
113933707f3Ssthen #else /* HAVE_PTHREAD_RWLOCK_T */
114933707f3Ssthen /** we use the pthread rwlock */
115*77079be7Ssthen typedef pthread_rwlock_t lock_rw_type;
116933707f3Ssthen /** small front for pthread init func, NULL is default attrs. */
117933707f3Ssthen #define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL))
118933707f3Ssthen #define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock))
119933707f3Ssthen #define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock))
120933707f3Ssthen #define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock))
121933707f3Ssthen #define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock))
122933707f3Ssthen #endif /* HAVE_PTHREAD_RWLOCK_T */
123933707f3Ssthen 
124933707f3Ssthen #ifndef HAVE_PTHREAD_SPINLOCK_T
125933707f3Ssthen /** in case spinlocks are not supported, use a mutex. */
126*77079be7Ssthen typedef pthread_mutex_t lock_quick_type;
127933707f3Ssthen /** small front for pthread init func, NULL is default attrs. */
128933707f3Ssthen #define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
129933707f3Ssthen #define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
130933707f3Ssthen #define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock))
131933707f3Ssthen #define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
132933707f3Ssthen 
133933707f3Ssthen #else /* HAVE_PTHREAD_SPINLOCK_T */
134933707f3Ssthen /** use pthread spinlock for the quick lock */
135*77079be7Ssthen typedef pthread_spinlock_t lock_quick_type;
136933707f3Ssthen /**
137933707f3Ssthen  * allocate process private since this is available whether
138933707f3Ssthen  * Thread Process-Shared Synchronization is supported or not.
139933707f3Ssthen  * This means only threads inside this process may access the lock.
140933707f3Ssthen  * (not threads from another process that shares memory).
141933707f3Ssthen  * spinlocks are not supported on all pthread platforms.
142933707f3Ssthen  */
143933707f3Ssthen #define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE))
144933707f3Ssthen #define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock))
145933707f3Ssthen #define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock))
146933707f3Ssthen #define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock))
147933707f3Ssthen 
148933707f3Ssthen #endif /* HAVE SPINLOCK */
149933707f3Ssthen 
150933707f3Ssthen /** Thread creation */
151*77079be7Ssthen typedef pthread_t ub_thread_type;
152*77079be7Ssthen /** On alpine linux default thread stack size is 80 Kb. See
153*77079be7Ssthen http://wiki.musl-libc.org/wiki/Functional_differences_from_glibc#Thread_stack_size
154*77079be7Ssthen This is not enough and cause segfault. Other linux distros have 2 Mb at least.
155*77079be7Ssthen Wrapper for set up thread stack size */
156*77079be7Ssthen #define PTHREADSTACKSIZE 2*1024*1024
157*77079be7Ssthen #define PTHREADCREATE(thr, stackrequired, func, arg) do {\
158*77079be7Ssthen 	pthread_attr_t attr; \
159*77079be7Ssthen 	size_t stacksize; \
160*77079be7Ssthen 	LOCKRET(pthread_attr_init(&attr)); \
161*77079be7Ssthen 	LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \
162*77079be7Ssthen 	if (stacksize < stackrequired) { \
163*77079be7Ssthen 		LOCKRET(pthread_attr_setstacksize(&attr, stackrequired)); \
164*77079be7Ssthen 		LOCKRET(pthread_create(thr, &attr, func, arg)); \
165*77079be7Ssthen 		LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \
166*77079be7Ssthen 		verbose(VERB_ALGO, "Thread stack size set to %u", (unsigned)stacksize); \
167*77079be7Ssthen 	} else {LOCKRET(pthread_create(thr, NULL, func, arg));} \
168*77079be7Ssthen 	} while(0)
169*77079be7Ssthen /** Use wrapper for set thread stack size on attributes. */
170*77079be7Ssthen #define ub_thread_create(thr, func, arg) PTHREADCREATE(thr, PTHREADSTACKSIZE, func, arg)
171933707f3Ssthen /** get self id. */
172933707f3Ssthen #define ub_thread_self() pthread_self()
173933707f3Ssthen /** wait for another thread to terminate */
174933707f3Ssthen #define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL))
175*77079be7Ssthen typedef pthread_key_t ub_thread_key_type;
176933707f3Ssthen #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
177933707f3Ssthen #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
178933707f3Ssthen #define ub_thread_key_get(key) pthread_getspecific(key)
179933707f3Ssthen 
180933707f3Ssthen #else /* we do not HAVE_PTHREAD */
181933707f3Ssthen #ifdef HAVE_SOLARIS_THREADS
182933707f3Ssthen 
183933707f3Ssthen /******************* SOLARIS THREADS ************************/
184933707f3Ssthen #include <synch.h>
185933707f3Ssthen #include <thread.h>
186933707f3Ssthen 
187*77079be7Ssthen typedef rwlock_t lock_rw_type;
188933707f3Ssthen #define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
189933707f3Ssthen #define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
190933707f3Ssthen #define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
191933707f3Ssthen #define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
192933707f3Ssthen #define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
193933707f3Ssthen 
194933707f3Ssthen /** use basic mutex */
195*77079be7Ssthen typedef mutex_t lock_basic_type;
196933707f3Ssthen #define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
197933707f3Ssthen #define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
198933707f3Ssthen #define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
199933707f3Ssthen #define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
200933707f3Ssthen 
201933707f3Ssthen /** No spinlocks in solaris threads API. Use a mutex. */
202*77079be7Ssthen typedef mutex_t lock_quick_type;
203933707f3Ssthen #define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
204933707f3Ssthen #define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
205933707f3Ssthen #define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
206933707f3Ssthen #define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
207933707f3Ssthen 
208933707f3Ssthen /** Thread creation, create a default thread. */
209*77079be7Ssthen typedef thread_t ub_thread_type;
210933707f3Ssthen #define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
211933707f3Ssthen #define ub_thread_self() thr_self()
212933707f3Ssthen #define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
213*77079be7Ssthen typedef thread_key_t ub_thread_key_type;
214933707f3Ssthen #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
215933707f3Ssthen #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
216*77079be7Ssthen void* ub_thread_key_get(ub_thread_key_type key);
217933707f3Ssthen 
218933707f3Ssthen 
219933707f3Ssthen #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
220933707f3Ssthen /******************* WINDOWS THREADS ************************/
221933707f3Ssthen #ifdef HAVE_WINDOWS_THREADS
222933707f3Ssthen #include <windows.h>
223933707f3Ssthen 
224933707f3Ssthen /* Use a mutex */
225*77079be7Ssthen typedef LONG lock_rw_type;
226933707f3Ssthen #define lock_rw_init(lock) lock_basic_init(lock)
227933707f3Ssthen #define lock_rw_destroy(lock) lock_basic_destroy(lock)
228933707f3Ssthen #define lock_rw_rdlock(lock) lock_basic_lock(lock)
229933707f3Ssthen #define lock_rw_wrlock(lock) lock_basic_lock(lock)
230933707f3Ssthen #define lock_rw_unlock(lock) lock_basic_unlock(lock)
231933707f3Ssthen 
232933707f3Ssthen /** the basic lock is a mutex, implemented opaquely, for error handling. */
233*77079be7Ssthen typedef LONG lock_basic_type;
234*77079be7Ssthen void lock_basic_init(lock_basic_type* lock);
235*77079be7Ssthen void lock_basic_destroy(lock_basic_type* lock);
236*77079be7Ssthen void lock_basic_lock(lock_basic_type* lock);
237*77079be7Ssthen void lock_basic_unlock(lock_basic_type* lock);
238933707f3Ssthen 
239933707f3Ssthen /** on windows no spinlock, use mutex too. */
240*77079be7Ssthen typedef LONG lock_quick_type;
241933707f3Ssthen #define lock_quick_init(lock) lock_basic_init(lock)
242933707f3Ssthen #define lock_quick_destroy(lock) lock_basic_destroy(lock)
243933707f3Ssthen #define lock_quick_lock(lock) lock_basic_lock(lock)
244933707f3Ssthen #define lock_quick_unlock(lock) lock_basic_unlock(lock)
245933707f3Ssthen 
246933707f3Ssthen /** Thread creation, create a default thread. */
247*77079be7Ssthen typedef HANDLE ub_thread_type;
248*77079be7Ssthen void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg);
249*77079be7Ssthen ub_thread_type ub_thread_self(void);
250*77079be7Ssthen void ub_thread_join(ub_thread_type thr);
251*77079be7Ssthen typedef DWORD ub_thread_key_type;
252*77079be7Ssthen void ub_thread_key_create(ub_thread_key_type* key, void* f);
253*77079be7Ssthen void ub_thread_key_set(ub_thread_key_type key, void* v);
254*77079be7Ssthen void* ub_thread_key_get(ub_thread_key_type key);
255933707f3Ssthen 
256933707f3Ssthen #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
257933707f3Ssthen 
258933707f3Ssthen /******************* NO THREADS ************************/
259933707f3Ssthen #define THREADS_DISABLED 1
260933707f3Ssthen /** In case there is no thread support, define locks to do nothing */
261*77079be7Ssthen typedef int lock_rw_type;
262933707f3Ssthen #define lock_rw_init(lock) /* nop */
263933707f3Ssthen #define lock_rw_destroy(lock) /* nop */
264933707f3Ssthen #define lock_rw_rdlock(lock) /* nop */
265933707f3Ssthen #define lock_rw_wrlock(lock) /* nop */
266933707f3Ssthen #define lock_rw_unlock(lock) /* nop */
267933707f3Ssthen 
268933707f3Ssthen /** define locks to do nothing */
269*77079be7Ssthen typedef int lock_basic_type;
270933707f3Ssthen #define lock_basic_init(lock) /* nop */
271933707f3Ssthen #define lock_basic_destroy(lock) /* nop */
272933707f3Ssthen #define lock_basic_lock(lock) /* nop */
273933707f3Ssthen #define lock_basic_unlock(lock) /* nop */
274933707f3Ssthen 
275933707f3Ssthen /** define locks to do nothing */
276*77079be7Ssthen typedef int lock_quick_type;
277933707f3Ssthen #define lock_quick_init(lock) /* nop */
278933707f3Ssthen #define lock_quick_destroy(lock) /* nop */
279933707f3Ssthen #define lock_quick_lock(lock) /* nop */
280933707f3Ssthen #define lock_quick_unlock(lock) /* nop */
281933707f3Ssthen 
282933707f3Ssthen /** Thread creation, threads do not exist */
283*77079be7Ssthen typedef pid_t ub_thread_type;
284933707f3Ssthen /** ub_thread_create is simulated with fork (extremely heavy threads,
285933707f3Ssthen   * with no shared memory). */
286933707f3Ssthen #define ub_thread_create(thr, func, arg) \
287933707f3Ssthen 	ub_thr_fork_create(thr, func, arg)
288933707f3Ssthen #define ub_thread_self() getpid()
289933707f3Ssthen #define ub_thread_join(thread) ub_thr_fork_wait(thread)
290*77079be7Ssthen void ub_thr_fork_wait(ub_thread_type thread);
291*77079be7Ssthen void ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg);
292*77079be7Ssthen typedef void* ub_thread_key_type;
293933707f3Ssthen #define ub_thread_key_create(key, f) (*(key)) = NULL
294933707f3Ssthen #define ub_thread_key_set(key, v) (key) = (v)
295933707f3Ssthen #define ub_thread_key_get(key) (key)
296933707f3Ssthen 
297933707f3Ssthen #endif /* HAVE_WINDOWS_THREADS */
298933707f3Ssthen #endif /* HAVE_SOLARIS_THREADS */
299933707f3Ssthen #endif /* HAVE_PTHREAD */
300933707f3Ssthen #endif /* USE_THREAD_DEBUG */
301933707f3Ssthen 
302933707f3Ssthen /**
303933707f3Ssthen  * Block all signals for this thread.
304933707f3Ssthen  * fatal exit on error.
305933707f3Ssthen  */
306933707f3Ssthen void ub_thread_blocksigs(void);
307933707f3Ssthen 
308933707f3Ssthen /**
309933707f3Ssthen  * unblock one signal for this thread.
310933707f3Ssthen  */
311933707f3Ssthen void ub_thread_sig_unblock(int sig);
312933707f3Ssthen 
313933707f3Ssthen #endif /* UTIL_LOCKS_H */
314