Home | History | Annotate | Line # | Download | only in util
      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