mirror of
https://github.com/monero-project/monero.git
synced 2024-11-17 16:27:39 +00:00
296 lines
12 KiB
C
296 lines
12 KiB
C
/**
|
|
* util/locks.h - unbound locking primitives
|
|
*
|
|
* Copyright (c) 2007, NLnet Labs. All rights reserved.
|
|
*
|
|
* This software is open source.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* Neither the name of the NLNET LABS nor the names of its contributors may
|
|
* be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef UTIL_LOCKS_H
|
|
#define UTIL_LOCKS_H
|
|
|
|
/**
|
|
* \file
|
|
* Locking primitives.
|
|
* If pthreads is available, these are used.
|
|
* If no locking exists, they do nothing.
|
|
*
|
|
* The idea is to have different sorts of locks for different tasks.
|
|
* This allows the locking code to be ported more easily.
|
|
*
|
|
* Types of locks that are supported.
|
|
* o lock_rw: lock that has many readers and one writer (to a data entry).
|
|
* o lock_basic: simple mutex. Blocking, one person has access only.
|
|
* This lock is meant for non performance sensitive uses.
|
|
* o lock_quick: speed lock. For performance sensitive locking of critical
|
|
* sections. Could be implemented by a mutex or a spinlock.
|
|
*
|
|
* Also thread creation and deletion functions are defined here.
|
|
*/
|
|
|
|
/* if you define your own LOCKRET before including locks.h, you can get most
|
|
* locking functions without the dependency on log_err. */
|
|
#ifndef LOCKRET
|
|
#include "util/log.h"
|
|
/**
|
|
* The following macro is used to check the return value of the
|
|
* pthread calls. They return 0 on success and an errno on error.
|
|
* The errno is logged to the logfile with a descriptive comment.
|
|
*/
|
|
#define LOCKRET(func) do {\
|
|
int lockret_err; \
|
|
if( (lockret_err=(func)) != 0) \
|
|
log_err("%s at %d could not " #func ": %s", \
|
|
__FILE__, __LINE__, strerror(lockret_err)); \
|
|
} while(0)
|
|
#endif
|
|
|
|
/** DEBUG: use thread debug whenever possible */
|
|
#if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS)
|
|
# define USE_THREAD_DEBUG
|
|
#endif
|
|
|
|
#ifdef USE_THREAD_DEBUG
|
|
/******************* THREAD DEBUG ************************/
|
|
/* (some) checking; to detect races and deadlocks. */
|
|
#include "testcode/checklocks.h"
|
|
|
|
#else /* USE_THREAD_DEBUG */
|
|
#define lock_protect(lock, area, size) /* nop */
|
|
#define lock_unprotect(lock, area) /* nop */
|
|
#define lock_get_mem(lock) (0) /* nothing */
|
|
#define checklock_start() /* nop */
|
|
#define checklock_stop() /* nop */
|
|
|
|
#ifdef HAVE_PTHREAD
|
|
#include <pthread.h>
|
|
|
|
/******************* PTHREAD ************************/
|
|
|
|
/** use pthread mutex for basic lock */
|
|
typedef pthread_mutex_t lock_basic_t;
|
|
/** small front for pthread init func, NULL is default attrs. */
|
|
#define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
|
|
#define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
|
|
#define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock))
|
|
#define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
|
|
|
|
#ifndef HAVE_PTHREAD_RWLOCK_T
|
|
/** in case rwlocks are not supported, use a mutex. */
|
|
typedef pthread_mutex_t lock_rw_t;
|
|
#define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
|
|
#define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
|
|
#define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock))
|
|
#define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock))
|
|
#define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
|
|
#else /* HAVE_PTHREAD_RWLOCK_T */
|
|
/** we use the pthread rwlock */
|
|
typedef pthread_rwlock_t lock_rw_t;
|
|
/** small front for pthread init func, NULL is default attrs. */
|
|
#define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL))
|
|
#define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock))
|
|
#define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock))
|
|
#define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock))
|
|
#define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock))
|
|
#endif /* HAVE_PTHREAD_RWLOCK_T */
|
|
|
|
#ifndef HAVE_PTHREAD_SPINLOCK_T
|
|
/** in case spinlocks are not supported, use a mutex. */
|
|
typedef pthread_mutex_t lock_quick_t;
|
|
/** small front for pthread init func, NULL is default attrs. */
|
|
#define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
|
|
#define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
|
|
#define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock))
|
|
#define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
|
|
|
|
#else /* HAVE_PTHREAD_SPINLOCK_T */
|
|
/** use pthread spinlock for the quick lock */
|
|
typedef pthread_spinlock_t lock_quick_t;
|
|
/**
|
|
* allocate process private since this is available whether
|
|
* Thread Process-Shared Synchronization is supported or not.
|
|
* This means only threads inside this process may access the lock.
|
|
* (not threads from another process that shares memory).
|
|
* spinlocks are not supported on all pthread platforms.
|
|
*/
|
|
#define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE))
|
|
#define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock))
|
|
#define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock))
|
|
#define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock))
|
|
|
|
#endif /* HAVE SPINLOCK */
|
|
|
|
/** Thread creation */
|
|
typedef pthread_t ub_thread_t;
|
|
/** Pass where to store tread_t in thr. Use default NULL attributes. */
|
|
#define ub_thread_create(thr, func, arg) LOCKRET(pthread_create(thr, NULL, func, arg))
|
|
/** get self id. */
|
|
#define ub_thread_self() pthread_self()
|
|
/** wait for another thread to terminate */
|
|
#define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL))
|
|
typedef pthread_key_t ub_thread_key_t;
|
|
#define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
|
|
#define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
|
|
#define ub_thread_key_get(key) pthread_getspecific(key)
|
|
|
|
#else /* we do not HAVE_PTHREAD */
|
|
#ifdef HAVE_SOLARIS_THREADS
|
|
|
|
/******************* SOLARIS THREADS ************************/
|
|
#include <synch.h>
|
|
#include <thread.h>
|
|
|
|
typedef rwlock_t lock_rw_t;
|
|
#define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
|
|
#define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
|
|
#define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
|
|
#define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
|
|
#define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
|
|
|
|
/** use basic mutex */
|
|
typedef mutex_t lock_basic_t;
|
|
#define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
|
|
#define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
|
|
#define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
|
|
#define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
|
|
|
|
/** No spinlocks in solaris threads API. Use a mutex. */
|
|
typedef mutex_t lock_quick_t;
|
|
#define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
|
|
#define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
|
|
#define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
|
|
#define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
|
|
|
|
/** Thread creation, create a default thread. */
|
|
typedef thread_t ub_thread_t;
|
|
#define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
|
|
#define ub_thread_self() thr_self()
|
|
#define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
|
|
typedef thread_key_t ub_thread_key_t;
|
|
#define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
|
|
#define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
|
|
void* ub_thread_key_get(ub_thread_key_t key);
|
|
|
|
|
|
#else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
|
|
/******************* WINDOWS THREADS ************************/
|
|
#ifdef HAVE_WINDOWS_THREADS
|
|
#include <windows.h>
|
|
|
|
/* Use a mutex */
|
|
typedef LONG lock_rw_t;
|
|
#define lock_rw_init(lock) lock_basic_init(lock)
|
|
#define lock_rw_destroy(lock) lock_basic_destroy(lock)
|
|
#define lock_rw_rdlock(lock) lock_basic_lock(lock)
|
|
#define lock_rw_wrlock(lock) lock_basic_lock(lock)
|
|
#define lock_rw_unlock(lock) lock_basic_unlock(lock)
|
|
|
|
/** the basic lock is a mutex, implemented opaquely, for error handling. */
|
|
typedef LONG lock_basic_t;
|
|
void lock_basic_init(lock_basic_t* lock);
|
|
void lock_basic_destroy(lock_basic_t* lock);
|
|
void lock_basic_lock(lock_basic_t* lock);
|
|
void lock_basic_unlock(lock_basic_t* lock);
|
|
|
|
/** on windows no spinlock, use mutex too. */
|
|
typedef LONG lock_quick_t;
|
|
#define lock_quick_init(lock) lock_basic_init(lock)
|
|
#define lock_quick_destroy(lock) lock_basic_destroy(lock)
|
|
#define lock_quick_lock(lock) lock_basic_lock(lock)
|
|
#define lock_quick_unlock(lock) lock_basic_unlock(lock)
|
|
|
|
/** Thread creation, create a default thread. */
|
|
typedef HANDLE ub_thread_t;
|
|
void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
|
|
ub_thread_t ub_thread_self(void);
|
|
void ub_thread_join(ub_thread_t thr);
|
|
typedef DWORD ub_thread_key_t;
|
|
void ub_thread_key_create(ub_thread_key_t* key, void* f);
|
|
void ub_thread_key_set(ub_thread_key_t key, void* v);
|
|
void* ub_thread_key_get(ub_thread_key_t key);
|
|
|
|
#else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
|
|
|
|
/******************* NO THREADS ************************/
|
|
#define THREADS_DISABLED 1
|
|
/** In case there is no thread support, define locks to do nothing */
|
|
typedef int lock_rw_t;
|
|
#define lock_rw_init(lock) /* nop */
|
|
#define lock_rw_destroy(lock) /* nop */
|
|
#define lock_rw_rdlock(lock) /* nop */
|
|
#define lock_rw_wrlock(lock) /* nop */
|
|
#define lock_rw_unlock(lock) /* nop */
|
|
|
|
/** define locks to do nothing */
|
|
typedef int lock_basic_t;
|
|
#define lock_basic_init(lock) /* nop */
|
|
#define lock_basic_destroy(lock) /* nop */
|
|
#define lock_basic_lock(lock) /* nop */
|
|
#define lock_basic_unlock(lock) /* nop */
|
|
|
|
/** define locks to do nothing */
|
|
typedef int lock_quick_t;
|
|
#define lock_quick_init(lock) /* nop */
|
|
#define lock_quick_destroy(lock) /* nop */
|
|
#define lock_quick_lock(lock) /* nop */
|
|
#define lock_quick_unlock(lock) /* nop */
|
|
|
|
/** Thread creation, threads do not exist */
|
|
typedef pid_t ub_thread_t;
|
|
/** ub_thread_create is simulated with fork (extremely heavy threads,
|
|
* with no shared memory). */
|
|
#define ub_thread_create(thr, func, arg) \
|
|
ub_thr_fork_create(thr, func, arg)
|
|
#define ub_thread_self() getpid()
|
|
#define ub_thread_join(thread) ub_thr_fork_wait(thread)
|
|
void ub_thr_fork_wait(ub_thread_t thread);
|
|
void ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
|
|
typedef void* ub_thread_key_t;
|
|
#define ub_thread_key_create(key, f) (*(key)) = NULL
|
|
#define ub_thread_key_set(key, v) (key) = (v)
|
|
#define ub_thread_key_get(key) (key)
|
|
|
|
#endif /* HAVE_WINDOWS_THREADS */
|
|
#endif /* HAVE_SOLARIS_THREADS */
|
|
#endif /* HAVE_PTHREAD */
|
|
#endif /* USE_THREAD_DEBUG */
|
|
|
|
/**
|
|
* Block all signals for this thread.
|
|
* fatal exit on error.
|
|
*/
|
|
void ub_thread_blocksigs(void);
|
|
|
|
/**
|
|
* unblock one signal for this thread.
|
|
*/
|
|
void ub_thread_sig_unblock(int sig);
|
|
|
|
#endif /* UTIL_LOCKS_H */
|