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