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 LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * 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 */ 95 typedef 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. */ 104 typedef 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 */ 112 typedef 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. */ 123 typedef 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 */ 132 typedef 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 */ 148 typedef 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)) 155 typedef 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 167 typedef 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 */ 175 typedef 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. */ 182 typedef 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. */ 189 typedef 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)) 193 typedef 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)) 196 void* 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 */ 205 typedef 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. */ 213 typedef LONG lock_basic_t; 214 void lock_basic_init(lock_basic_t* lock); 215 void lock_basic_destroy(lock_basic_t* lock); 216 void lock_basic_lock(lock_basic_t* lock); 217 void lock_basic_unlock(lock_basic_t* lock); 218 219 /** on windows no spinlock, use mutex too. */ 220 typedef 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. */ 227 typedef HANDLE ub_thread_t; 228 void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg); 229 ub_thread_t ub_thread_self(void); 230 void ub_thread_join(ub_thread_t thr); 231 typedef DWORD ub_thread_key_t; 232 void ub_thread_key_create(ub_thread_key_t* key, void* f); 233 void ub_thread_key_set(ub_thread_key_t key, void* v); 234 void* 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 */ 241 typedef 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 */ 249 typedef 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 */ 256 typedef 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 */ 263 typedef 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) 270 void ub_thr_fork_wait(ub_thread_t thread); 271 void ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg); 272 typedef 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 */ 286 void ub_thread_blocksigs(void); 287 288 /** 289 * unblock one signal for this thread. 290 */ 291 void ub_thread_sig_unblock(int sig); 292 293 #endif /* UTIL_LOCKS_H */ 294