2 * util/locks.h - unbound locking primitives
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
42 * If pthreads is available, these are used.
43 * If no locking exists, they do nothing.
45 * The idea is to have different sorts of locks for different tasks.
46 * This allows the locking code to be ported more easily.
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.
55 * Also thread creation and deletion functions are defined here.
58 /* if you define your own LOCKRET before including locks.h, you can get most
59 * locking functions without the dependency on log_err. */
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.
67 #define LOCKRET(func) do {\
69 if( (lockret_err=(func)) != 0) \
70 log_err("%s at %d could not " #func ": %s", \
71 __FILE__, __LINE__, strerror(lockret_err)); \
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
80 #ifdef USE_THREAD_DEBUG
81 /******************* THREAD DEBUG ************************/
82 /* (some) checking; to detect races and deadlocks. */
83 #include "testcode/checklocks.h"
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 */
95 /******************* PTHREAD ************************/
97 /** use pthread mutex for basic lock */
98 typedef pthread_mutex_t lock_basic_t
;
99 /** small front for pthread init func, NULL is default attrs. */
100 #define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
101 #define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
102 #define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock))
103 #define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
105 #ifndef HAVE_PTHREAD_RWLOCK_T
106 /** in case rwlocks are not supported, use a mutex. */
107 typedef pthread_mutex_t lock_rw_t
;
108 #define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
109 #define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
110 #define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock))
111 #define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock))
112 #define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
113 #else /* HAVE_PTHREAD_RWLOCK_T */
114 /** we use the pthread rwlock */
115 typedef pthread_rwlock_t lock_rw_t
;
116 /** small front for pthread init func, NULL is default attrs. */
117 #define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL))
118 #define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock))
119 #define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock))
120 #define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock))
121 #define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock))
122 #endif /* HAVE_PTHREAD_RWLOCK_T */
124 #ifndef HAVE_PTHREAD_SPINLOCK_T
125 /** in case spinlocks are not supported, use a mutex. */
126 typedef pthread_mutex_t lock_quick_t
;
127 /** small front for pthread init func, NULL is default attrs. */
128 #define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
129 #define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
130 #define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock))
131 #define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
133 #else /* HAVE_PTHREAD_SPINLOCK_T */
134 /** use pthread spinlock for the quick lock */
135 typedef pthread_spinlock_t lock_quick_t
;
137 * allocate process private since this is available whether
138 * Thread Process-Shared Synchronization is supported or not.
139 * This means only threads inside this process may access the lock.
140 * (not threads from another process that shares memory).
141 * spinlocks are not supported on all pthread platforms.
143 #define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE))
144 #define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock))
145 #define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock))
146 #define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock))
148 #endif /* HAVE SPINLOCK */
150 /** Thread creation */
151 typedef pthread_t ub_thread_t
;
152 /** Pass where to store tread_t in thr. Use default NULL attributes. */
153 #define ub_thread_create(thr, func, arg) LOCKRET(pthread_create(thr, NULL, func, arg))
155 #define ub_thread_self() pthread_self()
156 /** wait for another thread to terminate */
157 #define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL))
158 typedef pthread_key_t ub_thread_key_t
;
159 #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
160 #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
161 #define ub_thread_key_get(key) pthread_getspecific(key)
163 #else /* we do not HAVE_PTHREAD */
164 #ifdef HAVE_SOLARIS_THREADS
166 /******************* SOLARIS THREADS ************************/
170 typedef rwlock_t lock_rw_t
;
171 #define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
172 #define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
173 #define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
174 #define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
175 #define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
177 /** use basic mutex */
178 typedef mutex_t lock_basic_t
;
179 #define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
180 #define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
181 #define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
182 #define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
184 /** No spinlocks in solaris threads API. Use a mutex. */
185 typedef mutex_t lock_quick_t
;
186 #define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
187 #define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
188 #define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
189 #define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
191 /** Thread creation, create a default thread. */
192 typedef thread_t ub_thread_t
;
193 #define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
194 #define ub_thread_self() thr_self()
195 #define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
196 typedef thread_key_t ub_thread_key_t
;
197 #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
198 #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
199 void* ub_thread_key_get(ub_thread_key_t key
);
202 #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
203 /******************* WINDOWS THREADS ************************/
204 #ifdef HAVE_WINDOWS_THREADS
208 typedef LONG lock_rw_t
;
209 #define lock_rw_init(lock) lock_basic_init(lock)
210 #define lock_rw_destroy(lock) lock_basic_destroy(lock)
211 #define lock_rw_rdlock(lock) lock_basic_lock(lock)
212 #define lock_rw_wrlock(lock) lock_basic_lock(lock)
213 #define lock_rw_unlock(lock) lock_basic_unlock(lock)
215 /** the basic lock is a mutex, implemented opaquely, for error handling. */
216 typedef LONG lock_basic_t
;
217 void lock_basic_init(lock_basic_t
* lock
);
218 void lock_basic_destroy(lock_basic_t
* lock
);
219 void lock_basic_lock(lock_basic_t
* lock
);
220 void lock_basic_unlock(lock_basic_t
* lock
);
222 /** on windows no spinlock, use mutex too. */
223 typedef LONG lock_quick_t
;
224 #define lock_quick_init(lock) lock_basic_init(lock)
225 #define lock_quick_destroy(lock) lock_basic_destroy(lock)
226 #define lock_quick_lock(lock) lock_basic_lock(lock)
227 #define lock_quick_unlock(lock) lock_basic_unlock(lock)
229 /** Thread creation, create a default thread. */
230 typedef HANDLE ub_thread_t
;
231 void ub_thread_create(ub_thread_t
* thr
, void* (*func
)(void*), void* arg
);
232 ub_thread_t
ub_thread_self(void);
233 void ub_thread_join(ub_thread_t thr
);
234 typedef DWORD ub_thread_key_t
;
235 void ub_thread_key_create(ub_thread_key_t
* key
, void* f
);
236 void ub_thread_key_set(ub_thread_key_t key
, void* v
);
237 void* ub_thread_key_get(ub_thread_key_t key
);
239 #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
241 /******************* NO THREADS ************************/
242 #define THREADS_DISABLED 1
243 /** In case there is no thread support, define locks to do nothing */
244 typedef int lock_rw_t
;
245 #define lock_rw_init(lock) /* nop */
246 #define lock_rw_destroy(lock) /* nop */
247 #define lock_rw_rdlock(lock) /* nop */
248 #define lock_rw_wrlock(lock) /* nop */
249 #define lock_rw_unlock(lock) /* nop */
251 /** define locks to do nothing */
252 typedef int lock_basic_t
;
253 #define lock_basic_init(lock) /* nop */
254 #define lock_basic_destroy(lock) /* nop */
255 #define lock_basic_lock(lock) /* nop */
256 #define lock_basic_unlock(lock) /* nop */
258 /** define locks to do nothing */
259 typedef int lock_quick_t
;
260 #define lock_quick_init(lock) /* nop */
261 #define lock_quick_destroy(lock) /* nop */
262 #define lock_quick_lock(lock) /* nop */
263 #define lock_quick_unlock(lock) /* nop */
265 /** Thread creation, threads do not exist */
266 typedef pid_t ub_thread_t
;
267 /** ub_thread_create is simulated with fork (extremely heavy threads,
268 * with no shared memory). */
269 #define ub_thread_create(thr, func, arg) \
270 ub_thr_fork_create(thr, func, arg)
271 #define ub_thread_self() getpid()
272 #define ub_thread_join(thread) ub_thr_fork_wait(thread)
273 void ub_thr_fork_wait(ub_thread_t thread
);
274 void ub_thr_fork_create(ub_thread_t
* thr
, void* (*func
)(void*), void* arg
);
275 typedef void* ub_thread_key_t
;
276 #define ub_thread_key_create(key, f) (*(key)) = NULL
277 #define ub_thread_key_set(key, v) (key) = (v)
278 #define ub_thread_key_get(key) (key)
280 #endif /* HAVE_WINDOWS_THREADS */
281 #endif /* HAVE_SOLARIS_THREADS */
282 #endif /* HAVE_PTHREAD */
283 #endif /* USE_THREAD_DEBUG */
286 * Block all signals for this thread.
287 * fatal exit on error.
289 void ub_thread_blocksigs(void);
292 * unblock one signal for this thread.
294 void ub_thread_sig_unblock(int sig
);
296 #endif /* UTIL_LOCKS_H */