locks.h revision 285206
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
92#ifdef HAVE_PTHREAD
93#include <pthread.h>
94
95/******************* PTHREAD ************************/
96
97/** use pthread mutex for basic lock */
98typedef 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))
104
105#ifndef HAVE_PTHREAD_RWLOCK_T
106/** in case rwlocks are not supported, use a mutex. */
107typedef 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 */
115typedef 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 */
123
124#ifndef HAVE_PTHREAD_SPINLOCK_T
125/** in case spinlocks are not supported, use a mutex. */
126typedef 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))
132
133#else /* HAVE_PTHREAD_SPINLOCK_T */
134/** use pthread spinlock for the quick lock */
135typedef pthread_spinlock_t lock_quick_t;
136/**
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.
142 */
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))
147
148#endif /* HAVE SPINLOCK */
149
150/** Thread creation */
151typedef 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))
154/** get self id. */
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))
158typedef 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)
162
163#else /* we do not HAVE_PTHREAD */
164#ifdef HAVE_SOLARIS_THREADS
165
166/******************* SOLARIS THREADS ************************/
167#include <synch.h>
168#include <thread.h>
169
170typedef 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))
176
177/** use basic mutex */
178typedef 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))
183
184/** No spinlocks in solaris threads API. Use a mutex. */
185typedef 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))
190
191/** Thread creation, create a default thread. */
192typedef 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))
196typedef 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))
199void* ub_thread_key_get(ub_thread_key_t key);
200
201
202#else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
203/******************* WINDOWS THREADS ************************/
204#ifdef HAVE_WINDOWS_THREADS
205#include <windows.h>
206
207/* Use a mutex */
208typedef 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)
214
215/** the basic lock is a mutex, implemented opaquely, for error handling. */
216typedef LONG lock_basic_t;
217void lock_basic_init(lock_basic_t* lock);
218void lock_basic_destroy(lock_basic_t* lock);
219void lock_basic_lock(lock_basic_t* lock);
220void lock_basic_unlock(lock_basic_t* lock);
221
222/** on windows no spinlock, use mutex too. */
223typedef 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)
228
229/** Thread creation, create a default thread. */
230typedef HANDLE ub_thread_t;
231void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
232ub_thread_t ub_thread_self(void);
233void ub_thread_join(ub_thread_t thr);
234typedef DWORD ub_thread_key_t;
235void ub_thread_key_create(ub_thread_key_t* key, void* f);
236void ub_thread_key_set(ub_thread_key_t key, void* v);
237void* ub_thread_key_get(ub_thread_key_t key);
238
239#else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
240
241/******************* NO THREADS ************************/
242#define THREADS_DISABLED 1
243/** In case there is no thread support, define locks to do nothing */
244typedef 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 */
250
251/** define locks to do nothing */
252typedef 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 */
257
258/** define locks to do nothing */
259typedef 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 */
264
265/** Thread creation, threads do not exist */
266typedef 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)
273void ub_thr_fork_wait(ub_thread_t thread);
274void ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
275typedef 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)
279
280#endif /* HAVE_WINDOWS_THREADS */
281#endif /* HAVE_SOLARIS_THREADS */
282#endif /* HAVE_PTHREAD */
283#endif /* USE_THREAD_DEBUG */
284
285/**
286 * Block all signals for this thread.
287 * fatal exit on error.
288 */
289void ub_thread_blocksigs(void);
290
291/**
292 * unblock one signal for this thread.
293 */
294void ub_thread_sig_unblock(int sig);
295
296#endif /* UTIL_LOCKS_H */
297