locks.h revision 269257
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#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 */
95typedef 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. */
104typedef 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 */
112typedef 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. */
123typedef 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 */
132typedef 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 */
148typedef 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))
155typedef 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
167typedef 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 */
175typedef 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. */
182typedef 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. */
189typedef 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))
193typedef 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))
196void* 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 */
205typedef 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. */
213typedef LONG lock_basic_t;
214void lock_basic_init(lock_basic_t* lock);
215void lock_basic_destroy(lock_basic_t* lock);
216void lock_basic_lock(lock_basic_t* lock);
217void lock_basic_unlock(lock_basic_t* lock);
218
219/** on windows no spinlock, use mutex too. */
220typedef 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. */
227typedef HANDLE ub_thread_t;
228void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
229ub_thread_t ub_thread_self(void);
230void ub_thread_join(ub_thread_t thr);
231typedef DWORD ub_thread_key_t;
232void ub_thread_key_create(ub_thread_key_t* key, void* f);
233void ub_thread_key_set(ub_thread_key_t key, void* v);
234void* 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 */
241typedef 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 */
249typedef 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 */
256typedef 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 */
263typedef 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)
270void ub_thr_fork_wait(ub_thread_t thread);
271void ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
272typedef 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 */
286void ub_thread_blocksigs(void);
287
288/**
289 * unblock one signal for this thread.
290 */
291void ub_thread_sig_unblock(int sig);
292
293#endif /* UTIL_LOCKS_H */
294