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 /* if you define your own LOCKRET before including locks.h, you can get most 59 * locking functions without the dependency on log_err. */ 60 #ifndef LOCKRET 61 #include "util/log.h" 62 /** 63 * The following macro is used to check the return value of the 64 * pthread calls. They return 0 on success and an errno on error. 65 * The errno is logged to the logfile with a descriptive comment. 66 */ 67 #define LOCKRET(func) do {\ 68 int lockret_err; \ 69 if( (lockret_err=(func)) != 0) \ 70 log_err("%s at %d could not " #func ": %s", \ 71 __FILE__, __LINE__, strerror(lockret_err)); \ 72 } while(0) 73 #endif 74 75 /** DEBUG: use thread debug whenever possible */ 76 #if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS) 77 # define USE_THREAD_DEBUG 78 #endif 79 80 #ifdef USE_THREAD_DEBUG 81 /******************* THREAD DEBUG ************************/ 82 /* (some) checking; to detect races and deadlocks. */ 83 #include "testcode/checklocks.h" 84 85 #else /* USE_THREAD_DEBUG */ 86 #define lock_protect(lock, area, size) /* nop */ 87 #define lock_unprotect(lock, area) /* nop */ 88 #define lock_get_mem(lock) (0) /* nothing */ 89 #define checklock_start() /* nop */ 90 #define checklock_stop() /* nop */ 91 #define checklock_set_output_name(name) /* nop */ 92 93 #ifdef HAVE_PTHREAD 94 #include <pthread.h> 95 96 /******************* PTHREAD ************************/ 97 98 /** use pthread mutex for basic lock */ 99 typedef pthread_mutex_t lock_basic_type; 100 /** small front for pthread init func, NULL is default attrs. */ 101 #define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) 102 #define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) 103 #define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock)) 104 #define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock)) 105 106 #ifndef HAVE_PTHREAD_RWLOCK_T 107 /** in case rwlocks are not supported, use a mutex. */ 108 typedef pthread_mutex_t lock_rw_type; 109 #define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) 110 #define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) 111 #define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock)) 112 #define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock)) 113 #define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock)) 114 #else /* HAVE_PTHREAD_RWLOCK_T */ 115 /** we use the pthread rwlock */ 116 typedef pthread_rwlock_t lock_rw_type; 117 /** small front for pthread init func, NULL is default attrs. */ 118 #define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL)) 119 #define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock)) 120 #define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock)) 121 #define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock)) 122 #define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock)) 123 #endif /* HAVE_PTHREAD_RWLOCK_T */ 124 125 #ifndef HAVE_PTHREAD_SPINLOCK_T 126 /** in case spinlocks are not supported, use a mutex. */ 127 typedef pthread_mutex_t lock_quick_type; 128 /** small front for pthread init func, NULL is default attrs. */ 129 #define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL)) 130 #define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock)) 131 #define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock)) 132 #define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock)) 133 134 #else /* HAVE_PTHREAD_SPINLOCK_T */ 135 /** use pthread spinlock for the quick lock */ 136 typedef pthread_spinlock_t lock_quick_type; 137 /** 138 * allocate process private since this is available whether 139 * Thread Process-Shared Synchronization is supported or not. 140 * This means only threads inside this process may access the lock. 141 * (not threads from another process that shares memory). 142 * spinlocks are not supported on all pthread platforms. 143 */ 144 #define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE)) 145 #define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock)) 146 #define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock)) 147 #define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock)) 148 149 #endif /* HAVE SPINLOCK */ 150 151 /** Thread creation */ 152 typedef pthread_t ub_thread_type; 153 /** On alpine linux default thread stack size is 80 Kb. See 154 http://wiki.musl-libc.org/wiki/Functional_differences_from_glibc#Thread_stack_size 155 This is not enough and cause segfault. Other linux distros have 2 Mb at least. 156 Wrapper for set up thread stack size */ 157 #define PTHREADSTACKSIZE 2*1024*1024 158 #define PTHREADCREATE(thr, stackrequired, func, arg) do {\ 159 pthread_attr_t attr; \ 160 size_t stacksize; \ 161 LOCKRET(pthread_attr_init(&attr)); \ 162 LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \ 163 if (stacksize < stackrequired) { \ 164 LOCKRET(pthread_attr_setstacksize(&attr, stackrequired)); \ 165 LOCKRET(pthread_create(thr, &attr, func, arg)); \ 166 LOCKRET(pthread_attr_getstacksize(&attr, &stacksize)); \ 167 verbose(VERB_ALGO, "Thread stack size set to %u", (unsigned)stacksize); \ 168 } else {LOCKRET(pthread_create(thr, NULL, func, arg));} \ 169 } while(0) 170 /** Use wrapper for set thread stack size on attributes. */ 171 #define ub_thread_create(thr, func, arg) PTHREADCREATE(thr, PTHREADSTACKSIZE, func, arg) 172 /** get self id. */ 173 #define ub_thread_self() pthread_self() 174 /** wait for another thread to terminate */ 175 #define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL)) 176 typedef pthread_key_t ub_thread_key_type; 177 #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f)) 178 #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v)) 179 #define ub_thread_key_get(key) pthread_getspecific(key) 180 181 #ifdef HAVE_PTHREAD_NP_H 182 #include <pthread_np.h> 183 #endif 184 #if defined(HAVE_PTHREAD_SET_NAME_NP) 185 #define ub_thread_setname(thread, name) do { \ 186 (void)pthread_set_name_np(thread, name);\ 187 } while(0) 188 #elif defined(HAVE_PTHREAD_SETNAME_NP1) 189 #define ub_thread_setname(thread, name) do { \ 190 (void)pthread_setname_np(name); \ 191 } while(0) 192 #elif defined(HAVE_PTHREAD_SETNAME_NP3) 193 #define ub_thread_setname(thread, name) do { \ 194 (void)pthread_setname_np(thread, name, NULL); \ 195 } while(0) 196 #elif defined(HAVE_PTHREAD_SETNAME_NP) 197 #define ub_thread_setname(thread, name) do { \ 198 (void)pthread_setname_np(thread, name); \ 199 } while(0) 200 #else 201 #define ub_thread_setname(thread, name) /* nop */ 202 #endif /* HAVE_PTHREAD_SET_NAME_NP */ 203 204 205 #else /* we do not HAVE_PTHREAD */ 206 #ifdef HAVE_SOLARIS_THREADS 207 208 /******************* SOLARIS THREADS ************************/ 209 #include <synch.h> 210 #include <thread.h> 211 212 typedef rwlock_t lock_rw_type; 213 #define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL)) 214 #define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock)) 215 #define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock)) 216 #define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock)) 217 #define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock)) 218 219 /** use basic mutex */ 220 typedef mutex_t lock_basic_type; 221 #define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL)) 222 #define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock)) 223 #define lock_basic_lock(lock) LOCKRET(mutex_lock(lock)) 224 #define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock)) 225 226 /** No spinlocks in solaris threads API. Use a mutex. */ 227 typedef mutex_t lock_quick_type; 228 #define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL)) 229 #define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock)) 230 #define lock_quick_lock(lock) LOCKRET(mutex_lock(lock)) 231 #define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock)) 232 233 /** Thread creation, create a default thread. */ 234 typedef thread_t ub_thread_type; 235 #define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr)) 236 #define ub_thread_self() thr_self() 237 #define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL)) 238 typedef thread_key_t ub_thread_key_type; 239 #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f)) 240 #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v)) 241 void* ub_thread_key_get(ub_thread_key_type key); 242 #define ub_thread_setname(thread, name) /* nop */ 243 244 245 #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */ 246 /******************* WINDOWS THREADS ************************/ 247 #ifdef HAVE_WINDOWS_THREADS 248 #include <windows.h> 249 250 /* Use a mutex */ 251 typedef LONG lock_rw_type; 252 #define lock_rw_init(lock) lock_basic_init(lock) 253 #define lock_rw_destroy(lock) lock_basic_destroy(lock) 254 #define lock_rw_rdlock(lock) lock_basic_lock(lock) 255 #define lock_rw_wrlock(lock) lock_basic_lock(lock) 256 #define lock_rw_unlock(lock) lock_basic_unlock(lock) 257 258 /** the basic lock is a mutex, implemented opaquely, for error handling. */ 259 typedef LONG lock_basic_type; 260 void lock_basic_init(lock_basic_type* lock); 261 void lock_basic_destroy(lock_basic_type* lock); 262 void lock_basic_lock(lock_basic_type* lock); 263 void lock_basic_unlock(lock_basic_type* lock); 264 265 /** on windows no spinlock, use mutex too. */ 266 typedef LONG lock_quick_type; 267 #define lock_quick_init(lock) lock_basic_init(lock) 268 #define lock_quick_destroy(lock) lock_basic_destroy(lock) 269 #define lock_quick_lock(lock) lock_basic_lock(lock) 270 #define lock_quick_unlock(lock) lock_basic_unlock(lock) 271 272 /** Thread creation, create a default thread. */ 273 typedef HANDLE ub_thread_type; 274 void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg); 275 ub_thread_type ub_thread_self(void); 276 void ub_thread_join(ub_thread_type thr); 277 typedef DWORD ub_thread_key_type; 278 void ub_thread_key_create(ub_thread_key_type* key, void* f); 279 void ub_thread_key_set(ub_thread_key_type key, void* v); 280 void* ub_thread_key_get(ub_thread_key_type key); 281 #define ub_thread_setname(thread, name) /* nop */ 282 283 #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */ 284 285 /******************* NO THREADS ************************/ 286 #define THREADS_DISABLED 1 287 /** In case there is no thread support, define locks to do nothing */ 288 typedef int lock_rw_type; 289 #define lock_rw_init(lock) /* nop */ 290 #define lock_rw_destroy(lock) /* nop */ 291 #define lock_rw_rdlock(lock) /* nop */ 292 #define lock_rw_wrlock(lock) /* nop */ 293 #define lock_rw_unlock(lock) /* nop */ 294 295 /** define locks to do nothing */ 296 typedef int lock_basic_type; 297 #define lock_basic_init(lock) /* nop */ 298 #define lock_basic_destroy(lock) /* nop */ 299 #define lock_basic_lock(lock) /* nop */ 300 #define lock_basic_unlock(lock) /* nop */ 301 302 /** define locks to do nothing */ 303 typedef int lock_quick_type; 304 #define lock_quick_init(lock) /* nop */ 305 #define lock_quick_destroy(lock) /* nop */ 306 #define lock_quick_lock(lock) /* nop */ 307 #define lock_quick_unlock(lock) /* nop */ 308 309 /** Thread creation, threads do not exist */ 310 typedef pid_t ub_thread_type; 311 /** ub_thread_create is simulated with fork (extremely heavy threads, 312 * with no shared memory). */ 313 #define ub_thread_create(thr, func, arg) \ 314 ub_thr_fork_create(thr, func, arg) 315 #define ub_thread_self() getpid() 316 #define ub_thread_join(thread) ub_thr_fork_wait(thread) 317 void ub_thr_fork_wait(ub_thread_type thread); 318 void ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg); 319 typedef void* ub_thread_key_type; 320 #define ub_thread_key_create(key, f) (*(key)) = NULL 321 #define ub_thread_key_set(key, v) (key) = (v) 322 #define ub_thread_key_get(key) (key) 323 #define ub_thread_setname(thread, name) /* nop */ 324 325 #endif /* HAVE_WINDOWS_THREADS */ 326 #endif /* HAVE_SOLARIS_THREADS */ 327 #endif /* HAVE_PTHREAD */ 328 #endif /* USE_THREAD_DEBUG */ 329 330 /** 331 * Block all signals for this thread. 332 * fatal exit on error. 333 */ 334 void ub_thread_blocksigs(void); 335 336 /** 337 * unblock one signal for this thread. 338 */ 339 void ub_thread_sig_unblock(int sig); 340 341 #endif /* UTIL_LOCKS_H */ 342