Home | History | Annotate | Line # | Download | only in util
locks.h revision 1.1.1.2.18.1
      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 #else /* we do not HAVE_PTHREAD */
    182 #ifdef HAVE_SOLARIS_THREADS
    183 
    184 /******************* SOLARIS THREADS ************************/
    185 #include <synch.h>
    186 #include <thread.h>
    187 
    188 typedef rwlock_t lock_rw_type;
    189 #define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
    190 #define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
    191 #define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
    192 #define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
    193 #define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
    194 
    195 /** use basic mutex */
    196 typedef mutex_t lock_basic_type;
    197 #define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
    198 #define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
    199 #define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
    200 #define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
    201 
    202 /** No spinlocks in solaris threads API. Use a mutex. */
    203 typedef mutex_t lock_quick_type;
    204 #define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
    205 #define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
    206 #define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
    207 #define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
    208 
    209 /** Thread creation, create a default thread. */
    210 typedef thread_t ub_thread_type;
    211 #define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
    212 #define ub_thread_self() thr_self()
    213 #define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
    214 typedef thread_key_t ub_thread_key_type;
    215 #define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
    216 #define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
    217 void* ub_thread_key_get(ub_thread_key_type key);
    218 
    219 
    220 #else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
    221 /******************* WINDOWS THREADS ************************/
    222 #ifdef HAVE_WINDOWS_THREADS
    223 #include <windows.h>
    224 
    225 /* Use a mutex */
    226 typedef LONG lock_rw_type;
    227 #define lock_rw_init(lock) lock_basic_init(lock)
    228 #define lock_rw_destroy(lock) lock_basic_destroy(lock)
    229 #define lock_rw_rdlock(lock) lock_basic_lock(lock)
    230 #define lock_rw_wrlock(lock) lock_basic_lock(lock)
    231 #define lock_rw_unlock(lock) lock_basic_unlock(lock)
    232 
    233 /** the basic lock is a mutex, implemented opaquely, for error handling. */
    234 typedef LONG lock_basic_type;
    235 void lock_basic_init(lock_basic_type* lock);
    236 void lock_basic_destroy(lock_basic_type* lock);
    237 void lock_basic_lock(lock_basic_type* lock);
    238 void lock_basic_unlock(lock_basic_type* lock);
    239 
    240 /** on windows no spinlock, use mutex too. */
    241 typedef LONG lock_quick_type;
    242 #define lock_quick_init(lock) lock_basic_init(lock)
    243 #define lock_quick_destroy(lock) lock_basic_destroy(lock)
    244 #define lock_quick_lock(lock) lock_basic_lock(lock)
    245 #define lock_quick_unlock(lock) lock_basic_unlock(lock)
    246 
    247 /** Thread creation, create a default thread. */
    248 typedef HANDLE ub_thread_type;
    249 void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg);
    250 ub_thread_type ub_thread_self(void);
    251 void ub_thread_join(ub_thread_type thr);
    252 typedef DWORD ub_thread_key_type;
    253 void ub_thread_key_create(ub_thread_key_type* key, void* f);
    254 void ub_thread_key_set(ub_thread_key_type key, void* v);
    255 void* ub_thread_key_get(ub_thread_key_type key);
    256 
    257 #else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
    258 
    259 /******************* NO THREADS ************************/
    260 #define THREADS_DISABLED 1
    261 /** In case there is no thread support, define locks to do nothing */
    262 typedef int lock_rw_type;
    263 #define lock_rw_init(lock) /* nop */
    264 #define lock_rw_destroy(lock) /* nop */
    265 #define lock_rw_rdlock(lock) /* nop */
    266 #define lock_rw_wrlock(lock) /* nop */
    267 #define lock_rw_unlock(lock) /* nop */
    268 
    269 /** define locks to do nothing */
    270 typedef int lock_basic_type;
    271 #define lock_basic_init(lock) /* nop */
    272 #define lock_basic_destroy(lock) /* nop */
    273 #define lock_basic_lock(lock) /* nop */
    274 #define lock_basic_unlock(lock) /* nop */
    275 
    276 /** define locks to do nothing */
    277 typedef int lock_quick_type;
    278 #define lock_quick_init(lock) /* nop */
    279 #define lock_quick_destroy(lock) /* nop */
    280 #define lock_quick_lock(lock) /* nop */
    281 #define lock_quick_unlock(lock) /* nop */
    282 
    283 /** Thread creation, threads do not exist */
    284 typedef pid_t ub_thread_type;
    285 /** ub_thread_create is simulated with fork (extremely heavy threads,
    286   * with no shared memory). */
    287 #define ub_thread_create(thr, func, arg) \
    288 	ub_thr_fork_create(thr, func, arg)
    289 #define ub_thread_self() getpid()
    290 #define ub_thread_join(thread) ub_thr_fork_wait(thread)
    291 void ub_thr_fork_wait(ub_thread_type thread);
    292 void ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg);
    293 typedef void* ub_thread_key_type;
    294 #define ub_thread_key_create(key, f) (*(key)) = NULL
    295 #define ub_thread_key_set(key, v) (key) = (v)
    296 #define ub_thread_key_get(key) (key)
    297 
    298 #endif /* HAVE_WINDOWS_THREADS */
    299 #endif /* HAVE_SOLARIS_THREADS */
    300 #endif /* HAVE_PTHREAD */
    301 #endif /* USE_THREAD_DEBUG */
    302 
    303 /**
    304  * Block all signals for this thread.
    305  * fatal exit on error.
    306  */
    307 void ub_thread_blocksigs(void);
    308 
    309 /**
    310  * unblock one signal for this thread.
    311  */
    312 void ub_thread_sig_unblock(int sig);
    313 
    314 #endif /* UTIL_LOCKS_H */
    315