xref: /freebsd/contrib/unbound/util/locks.h (revision 7661de35d15f582ab33e3bd6b8d909601557e436)
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 LIMITED
25  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * 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 #include "util/log.h"
59 
60 /**
61  * The following macro is used to check the return value of the
62  * pthread calls. They return 0 on success and an errno on error.
63  * The errno is logged to the logfile with a descriptive comment.
64  */
65 #define LOCKRET(func) do {\
66 	int lockret_err;		\
67 	if( (lockret_err=(func)) != 0)		\
68 		log_err("%s at %d could not " #func ": %s", \
69 		__FILE__, __LINE__, strerror(lockret_err));	\
70  	} while(0)
71 
72 /** DEBUG: use thread debug whenever possible */
73 #if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS)
74 #  define USE_THREAD_DEBUG
75 #endif
76 
77 #ifdef USE_THREAD_DEBUG
78 /******************* THREAD DEBUG ************************/
79 /* (some) checking; to detect races and deadlocks. */
80 #include "testcode/checklocks.h"
81 
82 #else /* USE_THREAD_DEBUG */
83 #define lock_protect(lock, area, size) /* nop */
84 #define lock_unprotect(lock, area) /* nop */
85 #define lock_get_mem(lock) (0) /* nothing */
86 #define checklock_start() /* nop */
87 #define checklock_stop() /* nop */
88 
89 #ifdef HAVE_PTHREAD
90 #include <pthread.h>
91 
92 /******************* PTHREAD ************************/
93 
94 /** use pthread mutex for basic lock */
95 typedef pthread_mutex_t lock_basic_t;
96 /** small front for pthread init func, NULL is default attrs. */
97 #define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
98 #define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
99 #define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock))
100 #define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
101 
102 #ifndef HAVE_PTHREAD_RWLOCK_T
103 /** in case rwlocks are not supported, use a mutex. */
104 typedef pthread_mutex_t lock_rw_t;
105 #define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
106 #define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
107 #define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock))
108 #define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock))
109 #define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
110 #else /* HAVE_PTHREAD_RWLOCK_T */
111 /** we use the pthread rwlock */
112 typedef pthread_rwlock_t lock_rw_t;
113 /** small front for pthread init func, NULL is default attrs. */
114 #define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL))
115 #define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock))
116 #define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock))
117 #define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock))
118 #define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock))
119 #endif /* HAVE_PTHREAD_RWLOCK_T */
120 
121 #ifndef HAVE_PTHREAD_SPINLOCK_T
122 /** in case spinlocks are not supported, use a mutex. */
123 typedef pthread_mutex_t lock_quick_t;
124 /** small front for pthread init func, NULL is default attrs. */
125 #define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
126 #define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
127 #define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock))
128 #define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
129 
130 #else /* HAVE_PTHREAD_SPINLOCK_T */
131 /** use pthread spinlock for the quick lock */
132 typedef pthread_spinlock_t lock_quick_t;
133 /**
134  * allocate process private since this is available whether
135  * Thread Process-Shared Synchronization is supported or not.
136  * This means only threads inside this process may access the lock.
137  * (not threads from another process that shares memory).
138  * spinlocks are not supported on all pthread platforms.
139  */
140 #define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE))
141 #define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock))
142 #define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock))
143 #define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock))
144 
145 #endif /* HAVE SPINLOCK */
146 
147 /** Thread creation */
148 typedef pthread_t ub_thread_t;
149 /** Pass where to store tread_t in thr. Use default NULL attributes. */
150 #define ub_thread_create(thr, func, arg) LOCKRET(pthread_create(thr, NULL, func, arg))
151 /** get self id. */
152 #define ub_thread_self() pthread_self()
153 /** wait for another thread to terminate */
154 #define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL))
155 typedef pthread_key_t ub_thread_key_t;
156 #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
157 #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
158 #define ub_thread_key_get(key) pthread_getspecific(key)
159 
160 #else /* we do not HAVE_PTHREAD */
161 #ifdef HAVE_SOLARIS_THREADS
162 
163 /******************* SOLARIS THREADS ************************/
164 #include <synch.h>
165 #include <thread.h>
166 
167 typedef rwlock_t lock_rw_t;
168 #define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
169 #define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
170 #define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
171 #define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
172 #define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
173 
174 /** use basic mutex */
175 typedef mutex_t lock_basic_t;
176 #define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
177 #define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
178 #define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
179 #define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
180 
181 /** No spinlocks in solaris threads API. Use a mutex. */
182 typedef mutex_t lock_quick_t;
183 #define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
184 #define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
185 #define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
186 #define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
187 
188 /** Thread creation, create a default thread. */
189 typedef thread_t ub_thread_t;
190 #define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
191 #define ub_thread_self() thr_self()
192 #define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
193 typedef thread_key_t ub_thread_key_t;
194 #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
195 #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
196 void* ub_thread_key_get(ub_thread_key_t key);
197 
198 
199 #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
200 /******************* WINDOWS THREADS ************************/
201 #ifdef HAVE_WINDOWS_THREADS
202 #include <windows.h>
203 
204 /* Use a mutex */
205 typedef LONG lock_rw_t;
206 #define lock_rw_init(lock) lock_basic_init(lock)
207 #define lock_rw_destroy(lock) lock_basic_destroy(lock)
208 #define lock_rw_rdlock(lock) lock_basic_lock(lock)
209 #define lock_rw_wrlock(lock) lock_basic_lock(lock)
210 #define lock_rw_unlock(lock) lock_basic_unlock(lock)
211 
212 /** the basic lock is a mutex, implemented opaquely, for error handling. */
213 typedef LONG lock_basic_t;
214 void lock_basic_init(lock_basic_t* lock);
215 void lock_basic_destroy(lock_basic_t* lock);
216 void lock_basic_lock(lock_basic_t* lock);
217 void lock_basic_unlock(lock_basic_t* lock);
218 
219 /** on windows no spinlock, use mutex too. */
220 typedef LONG lock_quick_t;
221 #define lock_quick_init(lock) lock_basic_init(lock)
222 #define lock_quick_destroy(lock) lock_basic_destroy(lock)
223 #define lock_quick_lock(lock) lock_basic_lock(lock)
224 #define lock_quick_unlock(lock) lock_basic_unlock(lock)
225 
226 /** Thread creation, create a default thread. */
227 typedef HANDLE ub_thread_t;
228 void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
229 ub_thread_t ub_thread_self(void);
230 void ub_thread_join(ub_thread_t thr);
231 typedef DWORD ub_thread_key_t;
232 void ub_thread_key_create(ub_thread_key_t* key, void* f);
233 void ub_thread_key_set(ub_thread_key_t key, void* v);
234 void* ub_thread_key_get(ub_thread_key_t key);
235 
236 #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
237 
238 /******************* NO THREADS ************************/
239 #define THREADS_DISABLED 1
240 /** In case there is no thread support, define locks to do nothing */
241 typedef int lock_rw_t;
242 #define lock_rw_init(lock) /* nop */
243 #define lock_rw_destroy(lock) /* nop */
244 #define lock_rw_rdlock(lock) /* nop */
245 #define lock_rw_wrlock(lock) /* nop */
246 #define lock_rw_unlock(lock) /* nop */
247 
248 /** define locks to do nothing */
249 typedef int lock_basic_t;
250 #define lock_basic_init(lock) /* nop */
251 #define lock_basic_destroy(lock) /* nop */
252 #define lock_basic_lock(lock) /* nop */
253 #define lock_basic_unlock(lock) /* nop */
254 
255 /** define locks to do nothing */
256 typedef int lock_quick_t;
257 #define lock_quick_init(lock) /* nop */
258 #define lock_quick_destroy(lock) /* nop */
259 #define lock_quick_lock(lock) /* nop */
260 #define lock_quick_unlock(lock) /* nop */
261 
262 /** Thread creation, threads do not exist */
263 typedef pid_t ub_thread_t;
264 /** ub_thread_create is simulated with fork (extremely heavy threads,
265   * with no shared memory). */
266 #define ub_thread_create(thr, func, arg) \
267 	ub_thr_fork_create(thr, func, arg)
268 #define ub_thread_self() getpid()
269 #define ub_thread_join(thread) ub_thr_fork_wait(thread)
270 void ub_thr_fork_wait(ub_thread_t thread);
271 void ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
272 typedef void* ub_thread_key_t;
273 #define ub_thread_key_create(key, f) (*(key)) = NULL
274 #define ub_thread_key_set(key, v) (key) = (v)
275 #define ub_thread_key_get(key) (key)
276 
277 #endif /* HAVE_WINDOWS_THREADS */
278 #endif /* HAVE_SOLARIS_THREADS */
279 #endif /* HAVE_PTHREAD */
280 #endif /* USE_THREAD_DEBUG */
281 
282 /**
283  * Block all signals for this thread.
284  * fatal exit on error.
285  */
286 void ub_thread_blocksigs(void);
287 
288 /**
289  * unblock one signal for this thread.
290  */
291 void ub_thread_sig_unblock(int sig);
292 
293 #endif /* UTIL_LOCKS_H */
294