diff options
Diffstat (limited to 'util/locks.c')
| -rw-r--r-- | util/locks.c | 264 | 
1 files changed, 264 insertions, 0 deletions
| diff --git a/util/locks.c b/util/locks.c new file mode 100644 index 000000000000..425f9b9d4568 --- /dev/null +++ b/util/locks.c @@ -0,0 +1,264 @@ +/** + * util/locks.c - 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 REGENTS 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. + */ + +/** + * \file + * Implementation of locking and threading support. + * A place for locking debug code since most locking functions are macros. + */ + +#include "config.h" +#include "util/locks.h" +#include <signal.h> +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +/** block all signals, masks them away. */ +void  +ub_thread_blocksigs(void) +{ +#if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK) +#  if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) +	int err; +#  endif +	sigset_t sigset; +	sigfillset(&sigset); +#ifdef HAVE_PTHREAD +	if((err=pthread_sigmask(SIG_SETMASK, &sigset, NULL))) +		fatal_exit("pthread_sigmask: %s", strerror(err)); +#else +#  ifdef HAVE_SOLARIS_THREADS +	if((err=thr_sigsetmask(SIG_SETMASK, &sigset, NULL))) +		fatal_exit("thr_sigsetmask: %s", strerror(err)); +#  else  +	/* have nothing, do single process signal mask */ +	if(sigprocmask(SIG_SETMASK, &sigset, NULL)) +		fatal_exit("sigprocmask: %s", strerror(errno)); +#  endif /* HAVE_SOLARIS_THREADS */ +#endif /* HAVE_PTHREAD */ +#endif /* have signal stuff */ +} + +/** unblock one signal, so we can catch it */ +void ub_thread_sig_unblock(int sig) +{ +#if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK) +#  if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) +	int err; +#  endif +	sigset_t sigset; +	sigemptyset(&sigset); +	sigaddset(&sigset, sig); +#ifdef HAVE_PTHREAD +	if((err=pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))) +		fatal_exit("pthread_sigmask: %s", strerror(err)); +#else +#  ifdef HAVE_SOLARIS_THREADS +	if((err=thr_sigsetmask(SIG_UNBLOCK, &sigset, NULL))) +		fatal_exit("thr_sigsetmask: %s", strerror(err)); +#  else  +	/* have nothing, do single thread case */ +	if(sigprocmask(SIG_UNBLOCK, &sigset, NULL)) +		fatal_exit("sigprocmask: %s", strerror(errno)); +#  endif /* HAVE_SOLARIS_THREADS */ +#endif /* HAVE_PTHREAD */ +#else +	(void)sig; +#endif /* have signal stuff */ +} + +#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS) +/** + * No threading available: fork a new process. + * This means no shared data structure, and no locking. + * Only the main thread ever returns. Exits on errors. + * @param thr: the location where to store the thread-id. + * @param func: function body of the thread. Return value of func is lost. + * @param arg: user argument to func. + */ +void  +ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg) +{ +	pid_t pid = fork(); +	switch(pid) { +	default:	/* main */ +			*thr = (ub_thread_t)pid; +			return; +	case 0: 	/* child */ +			*thr = (ub_thread_t)getpid(); +			(void)(*func)(arg); +			exit(0); +	case -1:	/* error */ +			fatal_exit("could not fork: %s", strerror(errno)); +	} +} + +/** + * There is no threading. Wait for a process to terminate. + * Note that ub_thread_t is defined as pid_t. + * @param thread: the process id to wait for. + */ +void ub_thr_fork_wait(ub_thread_t thread) +{ +	int status = 0; +	if(waitpid((pid_t)thread, &status, 0) == -1) +		log_err("waitpid(%d): %s", (int)thread, strerror(errno)); +	if(status != 0) +		log_warn("process %d abnormal exit with status %d", +			(int)thread, status); +} +#endif /* !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS) */ + +#ifdef HAVE_SOLARIS_THREADS +void* ub_thread_key_get(ub_thread_key_t key) +{ +	void* ret=NULL; +	LOCKRET(thr_getspecific(key, &ret)); +	return ret; +} +#endif + +#ifdef HAVE_WINDOWS_THREADS +/** log a windows GetLastError message */ +static void log_win_err(const char* str, DWORD err) +{ +	LPTSTR buf; +	if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |  +		FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,  +		NULL, err, 0, (LPTSTR)&buf, 0, NULL) == 0) { +		/* could not format error message */ +		log_err("%s, GetLastError=%d", str, (int)err); +		return; +	} +	log_err("%s, (err=%d): %s", str, (int)err, buf); +	LocalFree(buf); +} + +void lock_basic_init(lock_basic_t* lock) +{ +	/* implement own lock, because windows HANDLE as Mutex usage +	 * uses too many handles and would bog down the whole system. */ +	(void)InterlockedExchange(lock, 0); +} + +void lock_basic_destroy(lock_basic_t* lock) +{ +	(void)InterlockedExchange(lock, 0); +} + +void lock_basic_lock(lock_basic_t* lock) +{ +	LONG wait = 1; /* wait 1 msec at first */ + +	while(InterlockedExchange(lock, 1)) { +		/* if the old value was 1 then if was already locked */ +		Sleep(wait); /* wait with sleep */ +		wait *= 2;   /* exponential backoff for waiting */ +	} +	/* the old value was 0, but we inserted 1, we locked it! */ +} + +void lock_basic_unlock(lock_basic_t* lock) +{ +	/* unlock it by inserting the value of 0. xchg for cache coherency. */ +	(void)InterlockedExchange(lock, 0); +} + +void ub_thread_key_create(ub_thread_key_t* key, void* f) +{ +	*key = TlsAlloc(); +	if(*key == TLS_OUT_OF_INDEXES) { +		*key = 0; +		log_win_err("TlsAlloc Failed(OUT_OF_INDEXES)", GetLastError()); +	} +	else ub_thread_key_set(*key, f); +} + +void ub_thread_key_set(ub_thread_key_t key, void* v) +{ +	if(!TlsSetValue(key, v)) { +		log_win_err("TlsSetValue failed", GetLastError()); +	} +} + +void* ub_thread_key_get(ub_thread_key_t key) +{ +	void* ret = (void*)TlsGetValue(key); +	if(ret == NULL && GetLastError() != ERROR_SUCCESS) { +		log_win_err("TlsGetValue failed", GetLastError()); +	} +	return ret; +} + +void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg) +{ +#ifndef HAVE__BEGINTHREADEX +	*thr = CreateThread(NULL, /* default security (no inherit handle) */ +		0, /* default stack size */ +		(LPTHREAD_START_ROUTINE)func, arg, +		0, /* default flags, run immediately */ +		NULL); /* do not store thread identifier anywhere */ +#else +	/* the begintheadex routine setups for the C lib; aligns stack */ +	*thr=(ub_thread_t)_beginthreadex(NULL, 0, (void*)func, arg, 0, NULL); +#endif +	if(*thr == NULL) { +		log_win_err("CreateThread failed", GetLastError()); +		fatal_exit("thread create failed"); +	} +} + +ub_thread_t ub_thread_self(void) +{ +	return GetCurrentThread(); +} + +void ub_thread_join(ub_thread_t thr) +{ +	DWORD ret = WaitForSingleObject(thr, INFINITE); +	if(ret == WAIT_FAILED) { +		log_win_err("WaitForSingleObject(Thread):WAIT_FAILED",  +			GetLastError()); +	} else if(ret == WAIT_TIMEOUT) { +		log_win_err("WaitForSingleObject(Thread):WAIT_TIMEOUT",  +			GetLastError()); +	} +	/* and close the handle to the thread */ +	if(!CloseHandle(thr)) { +		log_win_err("CloseHandle(Thread) failed", GetLastError()); +	} +} +#endif /* HAVE_WINDOWS_THREADS */ | 
