1238106Sdes/**
2238106Sdes * util/locks.h - unbound locking primitives
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33266114Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes#ifndef UTIL_LOCKS_H
37238106Sdes#define UTIL_LOCKS_H
38238106Sdes
39238106Sdes/**
40238106Sdes * \file
41238106Sdes * Locking primitives.
42238106Sdes * If pthreads is available, these are used.
43238106Sdes * If no locking exists, they do nothing.
44238106Sdes *
45238106Sdes * The idea is to have different sorts of locks for different tasks.
46238106Sdes * This allows the locking code to be ported more easily.
47238106Sdes *
48238106Sdes * Types of locks that are supported.
49238106Sdes *   o lock_rw: lock that has many readers and one writer (to a data entry).
50238106Sdes *   o lock_basic: simple mutex. Blocking, one person has access only.
51238106Sdes *     This lock is meant for non performance sensitive uses.
52238106Sdes *   o lock_quick: speed lock. For performance sensitive locking of critical
53238106Sdes *     sections. Could be implemented by a mutex or a spinlock.
54238106Sdes *
55238106Sdes * Also thread creation and deletion functions are defined here.
56238106Sdes */
57238106Sdes
58276605Sdes/* if you define your own LOCKRET before including locks.h, you can get most
59276605Sdes * locking functions without the dependency on log_err. */
60276605Sdes#ifndef LOCKRET
61238106Sdes#include "util/log.h"
62238106Sdes/**
63238106Sdes * The following macro is used to check the return value of the
64238106Sdes * pthread calls. They return 0 on success and an errno on error.
65238106Sdes * The errno is logged to the logfile with a descriptive comment.
66238106Sdes */
67238106Sdes#define LOCKRET(func) do {\
68238106Sdes	int lockret_err;		\
69238106Sdes	if( (lockret_err=(func)) != 0)		\
70238106Sdes		log_err("%s at %d could not " #func ": %s", \
71238106Sdes		__FILE__, __LINE__, strerror(lockret_err));	\
72238106Sdes 	} while(0)
73276605Sdes#endif
74238106Sdes
75238106Sdes/** DEBUG: use thread debug whenever possible */
76238106Sdes#if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS)
77238106Sdes#  define USE_THREAD_DEBUG
78238106Sdes#endif
79238106Sdes
80238106Sdes#ifdef USE_THREAD_DEBUG
81238106Sdes/******************* THREAD DEBUG ************************/
82238106Sdes/* (some) checking; to detect races and deadlocks. */
83238106Sdes#include "testcode/checklocks.h"
84238106Sdes
85238106Sdes#else /* USE_THREAD_DEBUG */
86238106Sdes#define lock_protect(lock, area, size) /* nop */
87238106Sdes#define lock_unprotect(lock, area) /* nop */
88238106Sdes#define lock_get_mem(lock) (0) /* nothing */
89238106Sdes#define checklock_start() /* nop */
90238106Sdes#define checklock_stop() /* nop */
91238106Sdes
92238106Sdes#ifdef HAVE_PTHREAD
93238106Sdes#include <pthread.h>
94238106Sdes
95238106Sdes/******************* PTHREAD ************************/
96238106Sdes
97238106Sdes/** use pthread mutex for basic lock */
98238106Sdestypedef pthread_mutex_t lock_basic_t;
99238106Sdes/** small front for pthread init func, NULL is default attrs. */
100238106Sdes#define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
101238106Sdes#define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
102238106Sdes#define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock))
103238106Sdes#define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
104238106Sdes
105238106Sdes#ifndef HAVE_PTHREAD_RWLOCK_T
106238106Sdes/** in case rwlocks are not supported, use a mutex. */
107238106Sdestypedef pthread_mutex_t lock_rw_t;
108238106Sdes#define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
109238106Sdes#define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
110238106Sdes#define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock))
111238106Sdes#define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock))
112238106Sdes#define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
113238106Sdes#else /* HAVE_PTHREAD_RWLOCK_T */
114238106Sdes/** we use the pthread rwlock */
115238106Sdestypedef pthread_rwlock_t lock_rw_t;
116238106Sdes/** small front for pthread init func, NULL is default attrs. */
117238106Sdes#define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL))
118238106Sdes#define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock))
119238106Sdes#define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock))
120238106Sdes#define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock))
121238106Sdes#define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock))
122238106Sdes#endif /* HAVE_PTHREAD_RWLOCK_T */
123238106Sdes
124238106Sdes#ifndef HAVE_PTHREAD_SPINLOCK_T
125238106Sdes/** in case spinlocks are not supported, use a mutex. */
126238106Sdestypedef pthread_mutex_t lock_quick_t;
127238106Sdes/** small front for pthread init func, NULL is default attrs. */
128238106Sdes#define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
129238106Sdes#define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
130238106Sdes#define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock))
131238106Sdes#define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
132238106Sdes
133238106Sdes#else /* HAVE_PTHREAD_SPINLOCK_T */
134238106Sdes/** use pthread spinlock for the quick lock */
135238106Sdestypedef pthread_spinlock_t lock_quick_t;
136238106Sdes/**
137238106Sdes * allocate process private since this is available whether
138238106Sdes * Thread Process-Shared Synchronization is supported or not.
139238106Sdes * This means only threads inside this process may access the lock.
140238106Sdes * (not threads from another process that shares memory).
141238106Sdes * spinlocks are not supported on all pthread platforms.
142238106Sdes */
143238106Sdes#define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE))
144238106Sdes#define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock))
145238106Sdes#define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock))
146238106Sdes#define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock))
147238106Sdes
148238106Sdes#endif /* HAVE SPINLOCK */
149238106Sdes
150238106Sdes/** Thread creation */
151238106Sdestypedef pthread_t ub_thread_t;
152238106Sdes/** Pass where to store tread_t in thr. Use default NULL attributes. */
153238106Sdes#define ub_thread_create(thr, func, arg) LOCKRET(pthread_create(thr, NULL, func, arg))
154238106Sdes/** get self id. */
155238106Sdes#define ub_thread_self() pthread_self()
156238106Sdes/** wait for another thread to terminate */
157238106Sdes#define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL))
158238106Sdestypedef pthread_key_t ub_thread_key_t;
159238106Sdes#define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
160238106Sdes#define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
161238106Sdes#define ub_thread_key_get(key) pthread_getspecific(key)
162238106Sdes
163238106Sdes#else /* we do not HAVE_PTHREAD */
164238106Sdes#ifdef HAVE_SOLARIS_THREADS
165238106Sdes
166238106Sdes/******************* SOLARIS THREADS ************************/
167238106Sdes#include <synch.h>
168238106Sdes#include <thread.h>
169238106Sdes
170238106Sdestypedef rwlock_t lock_rw_t;
171238106Sdes#define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
172238106Sdes#define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
173238106Sdes#define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
174238106Sdes#define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
175238106Sdes#define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
176238106Sdes
177238106Sdes/** use basic mutex */
178238106Sdestypedef mutex_t lock_basic_t;
179238106Sdes#define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
180238106Sdes#define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
181238106Sdes#define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
182238106Sdes#define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
183238106Sdes
184238106Sdes/** No spinlocks in solaris threads API. Use a mutex. */
185238106Sdestypedef mutex_t lock_quick_t;
186238106Sdes#define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
187238106Sdes#define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
188238106Sdes#define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
189238106Sdes#define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
190238106Sdes
191238106Sdes/** Thread creation, create a default thread. */
192238106Sdestypedef thread_t ub_thread_t;
193238106Sdes#define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
194238106Sdes#define ub_thread_self() thr_self()
195238106Sdes#define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
196238106Sdestypedef thread_key_t ub_thread_key_t;
197238106Sdes#define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
198238106Sdes#define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
199238106Sdesvoid* ub_thread_key_get(ub_thread_key_t key);
200238106Sdes
201238106Sdes
202238106Sdes#else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
203238106Sdes/******************* WINDOWS THREADS ************************/
204238106Sdes#ifdef HAVE_WINDOWS_THREADS
205238106Sdes#include <windows.h>
206238106Sdes
207238106Sdes/* Use a mutex */
208238106Sdestypedef LONG lock_rw_t;
209238106Sdes#define lock_rw_init(lock) lock_basic_init(lock)
210238106Sdes#define lock_rw_destroy(lock) lock_basic_destroy(lock)
211238106Sdes#define lock_rw_rdlock(lock) lock_basic_lock(lock)
212238106Sdes#define lock_rw_wrlock(lock) lock_basic_lock(lock)
213238106Sdes#define lock_rw_unlock(lock) lock_basic_unlock(lock)
214238106Sdes
215238106Sdes/** the basic lock is a mutex, implemented opaquely, for error handling. */
216238106Sdestypedef LONG lock_basic_t;
217238106Sdesvoid lock_basic_init(lock_basic_t* lock);
218238106Sdesvoid lock_basic_destroy(lock_basic_t* lock);
219238106Sdesvoid lock_basic_lock(lock_basic_t* lock);
220238106Sdesvoid lock_basic_unlock(lock_basic_t* lock);
221238106Sdes
222238106Sdes/** on windows no spinlock, use mutex too. */
223238106Sdestypedef LONG lock_quick_t;
224238106Sdes#define lock_quick_init(lock) lock_basic_init(lock)
225238106Sdes#define lock_quick_destroy(lock) lock_basic_destroy(lock)
226238106Sdes#define lock_quick_lock(lock) lock_basic_lock(lock)
227238106Sdes#define lock_quick_unlock(lock) lock_basic_unlock(lock)
228238106Sdes
229238106Sdes/** Thread creation, create a default thread. */
230238106Sdestypedef HANDLE ub_thread_t;
231238106Sdesvoid ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
232238106Sdesub_thread_t ub_thread_self(void);
233238106Sdesvoid ub_thread_join(ub_thread_t thr);
234238106Sdestypedef DWORD ub_thread_key_t;
235238106Sdesvoid ub_thread_key_create(ub_thread_key_t* key, void* f);
236238106Sdesvoid ub_thread_key_set(ub_thread_key_t key, void* v);
237238106Sdesvoid* ub_thread_key_get(ub_thread_key_t key);
238238106Sdes
239238106Sdes#else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
240238106Sdes
241238106Sdes/******************* NO THREADS ************************/
242238106Sdes#define THREADS_DISABLED 1
243238106Sdes/** In case there is no thread support, define locks to do nothing */
244238106Sdestypedef int lock_rw_t;
245238106Sdes#define lock_rw_init(lock) /* nop */
246238106Sdes#define lock_rw_destroy(lock) /* nop */
247238106Sdes#define lock_rw_rdlock(lock) /* nop */
248238106Sdes#define lock_rw_wrlock(lock) /* nop */
249238106Sdes#define lock_rw_unlock(lock) /* nop */
250238106Sdes
251238106Sdes/** define locks to do nothing */
252238106Sdestypedef int lock_basic_t;
253238106Sdes#define lock_basic_init(lock) /* nop */
254238106Sdes#define lock_basic_destroy(lock) /* nop */
255238106Sdes#define lock_basic_lock(lock) /* nop */
256238106Sdes#define lock_basic_unlock(lock) /* nop */
257238106Sdes
258238106Sdes/** define locks to do nothing */
259238106Sdestypedef int lock_quick_t;
260238106Sdes#define lock_quick_init(lock) /* nop */
261238106Sdes#define lock_quick_destroy(lock) /* nop */
262238106Sdes#define lock_quick_lock(lock) /* nop */
263238106Sdes#define lock_quick_unlock(lock) /* nop */
264238106Sdes
265238106Sdes/** Thread creation, threads do not exist */
266238106Sdestypedef pid_t ub_thread_t;
267238106Sdes/** ub_thread_create is simulated with fork (extremely heavy threads,
268238106Sdes  * with no shared memory). */
269238106Sdes#define ub_thread_create(thr, func, arg) \
270238106Sdes	ub_thr_fork_create(thr, func, arg)
271238106Sdes#define ub_thread_self() getpid()
272238106Sdes#define ub_thread_join(thread) ub_thr_fork_wait(thread)
273238106Sdesvoid ub_thr_fork_wait(ub_thread_t thread);
274238106Sdesvoid ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
275238106Sdestypedef void* ub_thread_key_t;
276238106Sdes#define ub_thread_key_create(key, f) (*(key)) = NULL
277238106Sdes#define ub_thread_key_set(key, v) (key) = (v)
278238106Sdes#define ub_thread_key_get(key) (key)
279238106Sdes
280238106Sdes#endif /* HAVE_WINDOWS_THREADS */
281238106Sdes#endif /* HAVE_SOLARIS_THREADS */
282238106Sdes#endif /* HAVE_PTHREAD */
283238106Sdes#endif /* USE_THREAD_DEBUG */
284238106Sdes
285238106Sdes/**
286238106Sdes * Block all signals for this thread.
287238106Sdes * fatal exit on error.
288238106Sdes */
289238106Sdesvoid ub_thread_blocksigs(void);
290238106Sdes
291238106Sdes/**
292238106Sdes * unblock one signal for this thread.
293238106Sdes */
294238106Sdesvoid ub_thread_sig_unblock(int sig);
295238106Sdes
296238106Sdes#endif /* UTIL_LOCKS_H */
297