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