1933707f3Ssthen /** 2933707f3Ssthen * util/locks.h - unbound locking primitives 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen #ifndef UTIL_LOCKS_H 37933707f3Ssthen #define UTIL_LOCKS_H 38933707f3Ssthen 39933707f3Ssthen /** 40933707f3Ssthen * \file 41933707f3Ssthen * Locking primitives. 42933707f3Ssthen * If pthreads is available, these are used. 43933707f3Ssthen * If no locking exists, they do nothing. 44933707f3Ssthen * 45933707f3Ssthen * The idea is to have different sorts of locks for different tasks. 46933707f3Ssthen * This allows the locking code to be ported more easily. 47933707f3Ssthen * 48933707f3Ssthen * Types of locks that are supported. 49933707f3Ssthen * o lock_rw: lock that has many readers and one writer (to a data entry). 50933707f3Ssthen * o lock_basic: simple mutex. Blocking, one person has access only. 51933707f3Ssthen * This lock is meant for non performance sensitive uses. 52933707f3Ssthen * o lock_quick: speed lock. For performance sensitive locking of critical 53933707f3Ssthen * sections. Could be implemented by a mutex or a spinlock. 54933707f3Ssthen * 55933707f3Ssthen * Also thread creation and deletion functions are defined here. 56933707f3Ssthen */ 57933707f3Ssthen 5898f3ca02Sbrad /* if you define your own LOCKRET before including locks.h, you can get most 5998f3ca02Sbrad * locking functions without the dependency on log_err. */ 6098f3ca02Sbrad #ifndef LOCKRET 61933707f3Ssthen #include "util/log.h" 62933707f3Ssthen /** 63933707f3Ssthen * The following macro is used to check the return value of the 64933707f3Ssthen * pthread calls. They return 0 on success and an errno on error. 65933707f3Ssthen * The errno is logged to the logfile with a descriptive comment. 66933707f3Ssthen */ 67933707f3Ssthen #define LOCKRET(func) do {\ 68933707f3Ssthen int lockret_err; \ 69933707f3Ssthen if( (lockret_err=(func)) != 0) \ 70933707f3Ssthen log_err("%s at %d could not " #func ": %s", \ 71933707f3Ssthen __FILE__, __LINE__, strerror(lockret_err)); \ 72933707f3Ssthen } while(0) 7398f3ca02Sbrad #endif 74933707f3Ssthen 75933707f3Ssthen /** DEBUG: use thread debug whenever possible */ 76933707f3Ssthen #if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS) 77933707f3Ssthen # define USE_THREAD_DEBUG 78933707f3Ssthen #endif 79933707f3Ssthen 80933707f3Ssthen #ifdef USE_THREAD_DEBUG 81933707f3Ssthen /******************* THREAD DEBUG ************************/ 82933707f3Ssthen /* (some) checking; to detect races and deadlocks. */ 83933707f3Ssthen #include "testcode/checklocks.h" 84933707f3Ssthen 85933707f3Ssthen #else /* USE_THREAD_DEBUG */ 86933707f3Ssthen #define lock_protect(lock, area, size) /* nop */ 87933707f3Ssthen #define lock_unprotect(lock, area) /* nop */ 88933707f3Ssthen #define lock_get_mem(lock) (0) /* nothing */ 89933707f3Ssthen #define checklock_start() /* nop */ 90933707f3Ssthen #define checklock_stop() /* nop */ 91933707f3Ssthen 92933707f3Ssthen #ifdef HAVE_PTHREAD 93933707f3Ssthen #include <pthread.h> 94933707f3Ssthen 95933707f3Ssthen /******************* PTHREAD ************************/ 96933707f3Ssthen 97933707f3Ssthen /** use pthread mutex for basic lock */ 98*77079be7Ssthen typedef pthread_mutex_t lock_basic_type; 99933707f3Ssthen /** small front for pthread init func, NULL is default attrs. */ 100933707f3Ssthen #define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) 101933707f3Ssthen #define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) 102933707f3Ssthen #define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock)) 103933707f3Ssthen #define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock)) 104933707f3Ssthen 105933707f3Ssthen #ifndef HAVE_PTHREAD_RWLOCK_T 106933707f3Ssthen /** in case rwlocks are not supported, use a mutex. */ 107*77079be7Ssthen typedef pthread_mutex_t lock_rw_type; 108933707f3Ssthen #define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) 109933707f3Ssthen #define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) 110933707f3Ssthen #define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock)) 111933707f3Ssthen #define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock)) 112933707f3Ssthen #define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock)) 113933707f3Ssthen #else /* HAVE_PTHREAD_RWLOCK_T */ 114933707f3Ssthen /** we use the pthread rwlock */ 115*77079be7Ssthen typedef pthread_rwlock_t lock_rw_type; 116933707f3Ssthen /** small front for pthread init func, NULL is default attrs. */ 117933707f3Ssthen #define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL)) 118933707f3Ssthen #define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock)) 119933707f3Ssthen #define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock)) 120933707f3Ssthen #define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock)) 121933707f3Ssthen #define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock)) 122933707f3Ssthen #endif /* HAVE_PTHREAD_RWLOCK_T */ 123933707f3Ssthen 124933707f3Ssthen #ifndef HAVE_PTHREAD_SPINLOCK_T 125933707f3Ssthen /** in case spinlocks are not supported, use a mutex. */ 126*77079be7Ssthen typedef pthread_mutex_t lock_quick_type; 127933707f3Ssthen /** small front for pthread init func, NULL is default attrs. */ 128933707f3Ssthen #define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) 129933707f3Ssthen #define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) 130933707f3Ssthen #define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock)) 131933707f3Ssthen #define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock)) 132933707f3Ssthen 133933707f3Ssthen #else /* HAVE_PTHREAD_SPINLOCK_T */ 134933707f3Ssthen /** use pthread spinlock for the quick lock */ 135*77079be7Ssthen typedef pthread_spinlock_t lock_quick_type; 136933707f3Ssthen /** 137933707f3Ssthen * allocate process private since this is available whether 138933707f3Ssthen * Thread Process-Shared Synchronization is supported or not. 139933707f3Ssthen * This means only threads inside this process may access the lock. 140933707f3Ssthen * (not threads from another process that shares memory). 141933707f3Ssthen * spinlocks are not supported on all pthread platforms. 142933707f3Ssthen */ 143933707f3Ssthen #define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE)) 144933707f3Ssthen #define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock)) 145933707f3Ssthen #define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock)) 146933707f3Ssthen #define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock)) 147933707f3Ssthen 148933707f3Ssthen #endif /* HAVE SPINLOCK */ 149933707f3Ssthen 150933707f3Ssthen /** Thread creation */ 151*77079be7Ssthen typedef pthread_t ub_thread_type; 152*77079be7Ssthen /** On alpine linux default thread stack size is 80 Kb. See 153*77079be7Ssthen http://wiki.musl-libc.org/wiki/Functional_differences_from_glibc#Thread_stack_size 154*77079be7Ssthen This is not enough and cause segfault. Other linux distros have 2 Mb at least. 155*77079be7Ssthen Wrapper for set up thread stack size */ 156*77079be7Ssthen #define PTHREADSTACKSIZE 2*1024*1024 157*77079be7Ssthen #define PTHREADCREATE(thr, stackrequired, func, arg) do {\ 158*77079be7Ssthen pthread_attr_t attr; \ 159*77079be7Ssthen size_t stacksize; \ 160*77079be7Ssthen LOCKRET(pthread_attr_init(&attr)); \ 161*77079be7Ssthen LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \ 162*77079be7Ssthen if (stacksize < stackrequired) { \ 163*77079be7Ssthen LOCKRET(pthread_attr_setstacksize(&attr, stackrequired)); \ 164*77079be7Ssthen LOCKRET(pthread_create(thr, &attr, func, arg)); \ 165*77079be7Ssthen LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \ 166*77079be7Ssthen verbose(VERB_ALGO, "Thread stack size set to %u", (unsigned)stacksize); \ 167*77079be7Ssthen } else {LOCKRET(pthread_create(thr, NULL, func, arg));} \ 168*77079be7Ssthen } while(0) 169*77079be7Ssthen /** Use wrapper for set thread stack size on attributes. */ 170*77079be7Ssthen #define ub_thread_create(thr, func, arg) PTHREADCREATE(thr, PTHREADSTACKSIZE, func, arg) 171933707f3Ssthen /** get self id. */ 172933707f3Ssthen #define ub_thread_self() pthread_self() 173933707f3Ssthen /** wait for another thread to terminate */ 174933707f3Ssthen #define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL)) 175*77079be7Ssthen typedef pthread_key_t ub_thread_key_type; 176933707f3Ssthen #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f)) 177933707f3Ssthen #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v)) 178933707f3Ssthen #define ub_thread_key_get(key) pthread_getspecific(key) 179933707f3Ssthen 180933707f3Ssthen #else /* we do not HAVE_PTHREAD */ 181933707f3Ssthen #ifdef HAVE_SOLARIS_THREADS 182933707f3Ssthen 183933707f3Ssthen /******************* SOLARIS THREADS ************************/ 184933707f3Ssthen #include <synch.h> 185933707f3Ssthen #include <thread.h> 186933707f3Ssthen 187*77079be7Ssthen typedef rwlock_t lock_rw_type; 188933707f3Ssthen #define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL)) 189933707f3Ssthen #define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock)) 190933707f3Ssthen #define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock)) 191933707f3Ssthen #define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock)) 192933707f3Ssthen #define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock)) 193933707f3Ssthen 194933707f3Ssthen /** use basic mutex */ 195*77079be7Ssthen typedef mutex_t lock_basic_type; 196933707f3Ssthen #define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL)) 197933707f3Ssthen #define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock)) 198933707f3Ssthen #define lock_basic_lock(lock) LOCKRET(mutex_lock(lock)) 199933707f3Ssthen #define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock)) 200933707f3Ssthen 201933707f3Ssthen /** No spinlocks in solaris threads API. Use a mutex. */ 202*77079be7Ssthen typedef mutex_t lock_quick_type; 203933707f3Ssthen #define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL)) 204933707f3Ssthen #define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock)) 205933707f3Ssthen #define lock_quick_lock(lock) LOCKRET(mutex_lock(lock)) 206933707f3Ssthen #define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock)) 207933707f3Ssthen 208933707f3Ssthen /** Thread creation, create a default thread. */ 209*77079be7Ssthen typedef thread_t ub_thread_type; 210933707f3Ssthen #define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr)) 211933707f3Ssthen #define ub_thread_self() thr_self() 212933707f3Ssthen #define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL)) 213*77079be7Ssthen typedef thread_key_t ub_thread_key_type; 214933707f3Ssthen #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f)) 215933707f3Ssthen #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v)) 216*77079be7Ssthen void* ub_thread_key_get(ub_thread_key_type key); 217933707f3Ssthen 218933707f3Ssthen 219933707f3Ssthen #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */ 220933707f3Ssthen /******************* WINDOWS THREADS ************************/ 221933707f3Ssthen #ifdef HAVE_WINDOWS_THREADS 222933707f3Ssthen #include <windows.h> 223933707f3Ssthen 224933707f3Ssthen /* Use a mutex */ 225*77079be7Ssthen typedef LONG lock_rw_type; 226933707f3Ssthen #define lock_rw_init(lock) lock_basic_init(lock) 227933707f3Ssthen #define lock_rw_destroy(lock) lock_basic_destroy(lock) 228933707f3Ssthen #define lock_rw_rdlock(lock) lock_basic_lock(lock) 229933707f3Ssthen #define lock_rw_wrlock(lock) lock_basic_lock(lock) 230933707f3Ssthen #define lock_rw_unlock(lock) lock_basic_unlock(lock) 231933707f3Ssthen 232933707f3Ssthen /** the basic lock is a mutex, implemented opaquely, for error handling. */ 233*77079be7Ssthen typedef LONG lock_basic_type; 234*77079be7Ssthen void lock_basic_init(lock_basic_type* lock); 235*77079be7Ssthen void lock_basic_destroy(lock_basic_type* lock); 236*77079be7Ssthen void lock_basic_lock(lock_basic_type* lock); 237*77079be7Ssthen void lock_basic_unlock(lock_basic_type* lock); 238933707f3Ssthen 239933707f3Ssthen /** on windows no spinlock, use mutex too. */ 240*77079be7Ssthen typedef LONG lock_quick_type; 241933707f3Ssthen #define lock_quick_init(lock) lock_basic_init(lock) 242933707f3Ssthen #define lock_quick_destroy(lock) lock_basic_destroy(lock) 243933707f3Ssthen #define lock_quick_lock(lock) lock_basic_lock(lock) 244933707f3Ssthen #define lock_quick_unlock(lock) lock_basic_unlock(lock) 245933707f3Ssthen 246933707f3Ssthen /** Thread creation, create a default thread. */ 247*77079be7Ssthen typedef HANDLE ub_thread_type; 248*77079be7Ssthen void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg); 249*77079be7Ssthen ub_thread_type ub_thread_self(void); 250*77079be7Ssthen void ub_thread_join(ub_thread_type thr); 251*77079be7Ssthen typedef DWORD ub_thread_key_type; 252*77079be7Ssthen void ub_thread_key_create(ub_thread_key_type* key, void* f); 253*77079be7Ssthen void ub_thread_key_set(ub_thread_key_type key, void* v); 254*77079be7Ssthen void* ub_thread_key_get(ub_thread_key_type key); 255933707f3Ssthen 256933707f3Ssthen #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */ 257933707f3Ssthen 258933707f3Ssthen /******************* NO THREADS ************************/ 259933707f3Ssthen #define THREADS_DISABLED 1 260933707f3Ssthen /** In case there is no thread support, define locks to do nothing */ 261*77079be7Ssthen typedef int lock_rw_type; 262933707f3Ssthen #define lock_rw_init(lock) /* nop */ 263933707f3Ssthen #define lock_rw_destroy(lock) /* nop */ 264933707f3Ssthen #define lock_rw_rdlock(lock) /* nop */ 265933707f3Ssthen #define lock_rw_wrlock(lock) /* nop */ 266933707f3Ssthen #define lock_rw_unlock(lock) /* nop */ 267933707f3Ssthen 268933707f3Ssthen /** define locks to do nothing */ 269*77079be7Ssthen typedef int lock_basic_type; 270933707f3Ssthen #define lock_basic_init(lock) /* nop */ 271933707f3Ssthen #define lock_basic_destroy(lock) /* nop */ 272933707f3Ssthen #define lock_basic_lock(lock) /* nop */ 273933707f3Ssthen #define lock_basic_unlock(lock) /* nop */ 274933707f3Ssthen 275933707f3Ssthen /** define locks to do nothing */ 276*77079be7Ssthen typedef int lock_quick_type; 277933707f3Ssthen #define lock_quick_init(lock) /* nop */ 278933707f3Ssthen #define lock_quick_destroy(lock) /* nop */ 279933707f3Ssthen #define lock_quick_lock(lock) /* nop */ 280933707f3Ssthen #define lock_quick_unlock(lock) /* nop */ 281933707f3Ssthen 282933707f3Ssthen /** Thread creation, threads do not exist */ 283*77079be7Ssthen typedef pid_t ub_thread_type; 284933707f3Ssthen /** ub_thread_create is simulated with fork (extremely heavy threads, 285933707f3Ssthen * with no shared memory). */ 286933707f3Ssthen #define ub_thread_create(thr, func, arg) \ 287933707f3Ssthen ub_thr_fork_create(thr, func, arg) 288933707f3Ssthen #define ub_thread_self() getpid() 289933707f3Ssthen #define ub_thread_join(thread) ub_thr_fork_wait(thread) 290*77079be7Ssthen void ub_thr_fork_wait(ub_thread_type thread); 291*77079be7Ssthen void ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg); 292*77079be7Ssthen typedef void* ub_thread_key_type; 293933707f3Ssthen #define ub_thread_key_create(key, f) (*(key)) = NULL 294933707f3Ssthen #define ub_thread_key_set(key, v) (key) = (v) 295933707f3Ssthen #define ub_thread_key_get(key) (key) 296933707f3Ssthen 297933707f3Ssthen #endif /* HAVE_WINDOWS_THREADS */ 298933707f3Ssthen #endif /* HAVE_SOLARIS_THREADS */ 299933707f3Ssthen #endif /* HAVE_PTHREAD */ 300933707f3Ssthen #endif /* USE_THREAD_DEBUG */ 301933707f3Ssthen 302933707f3Ssthen /** 303933707f3Ssthen * Block all signals for this thread. 304933707f3Ssthen * fatal exit on error. 305933707f3Ssthen */ 306933707f3Ssthen void ub_thread_blocksigs(void); 307933707f3Ssthen 308933707f3Ssthen /** 309933707f3Ssthen * unblock one signal for this thread. 310933707f3Ssthen */ 311933707f3Ssthen void ub_thread_sig_unblock(int sig); 312933707f3Ssthen 313933707f3Ssthen #endif /* UTIL_LOCKS_H */ 314