1238106Sdes/** 2238106Sdes * util/locks.c - unbound locking primitives 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24238106Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25238106Sdes * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26238106Sdes * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27238106Sdes * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28238106Sdes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29238106Sdes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30238106Sdes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31238106Sdes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32238106Sdes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33238106Sdes * POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * Implementation of locking and threading support. 39238106Sdes * A place for locking debug code since most locking functions are macros. 40238106Sdes */ 41238106Sdes 42238106Sdes#include "config.h" 43238106Sdes#include "util/locks.h" 44238106Sdes#include <signal.h> 45238106Sdes#ifdef HAVE_SYS_WAIT_H 46238106Sdes#include <sys/wait.h> 47238106Sdes#endif 48238106Sdes 49238106Sdes/** block all signals, masks them away. */ 50238106Sdesvoid 51238106Sdesub_thread_blocksigs(void) 52238106Sdes{ 53238106Sdes#if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK) 54238106Sdes# if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) 55238106Sdes int err; 56238106Sdes# endif 57238106Sdes sigset_t sigset; 58238106Sdes sigfillset(&sigset); 59238106Sdes#ifdef HAVE_PTHREAD 60238106Sdes if((err=pthread_sigmask(SIG_SETMASK, &sigset, NULL))) 61238106Sdes fatal_exit("pthread_sigmask: %s", strerror(err)); 62238106Sdes#else 63238106Sdes# ifdef HAVE_SOLARIS_THREADS 64238106Sdes if((err=thr_sigsetmask(SIG_SETMASK, &sigset, NULL))) 65238106Sdes fatal_exit("thr_sigsetmask: %s", strerror(err)); 66238106Sdes# else 67238106Sdes /* have nothing, do single process signal mask */ 68238106Sdes if(sigprocmask(SIG_SETMASK, &sigset, NULL)) 69238106Sdes fatal_exit("sigprocmask: %s", strerror(errno)); 70238106Sdes# endif /* HAVE_SOLARIS_THREADS */ 71238106Sdes#endif /* HAVE_PTHREAD */ 72238106Sdes#endif /* have signal stuff */ 73238106Sdes} 74238106Sdes 75238106Sdes/** unblock one signal, so we can catch it */ 76238106Sdesvoid ub_thread_sig_unblock(int sig) 77238106Sdes{ 78238106Sdes#if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK) 79238106Sdes# if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) 80238106Sdes int err; 81238106Sdes# endif 82238106Sdes sigset_t sigset; 83238106Sdes sigemptyset(&sigset); 84238106Sdes sigaddset(&sigset, sig); 85238106Sdes#ifdef HAVE_PTHREAD 86238106Sdes if((err=pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))) 87238106Sdes fatal_exit("pthread_sigmask: %s", strerror(err)); 88238106Sdes#else 89238106Sdes# ifdef HAVE_SOLARIS_THREADS 90238106Sdes if((err=thr_sigsetmask(SIG_UNBLOCK, &sigset, NULL))) 91238106Sdes fatal_exit("thr_sigsetmask: %s", strerror(err)); 92238106Sdes# else 93238106Sdes /* have nothing, do single thread case */ 94238106Sdes if(sigprocmask(SIG_UNBLOCK, &sigset, NULL)) 95238106Sdes fatal_exit("sigprocmask: %s", strerror(errno)); 96238106Sdes# endif /* HAVE_SOLARIS_THREADS */ 97238106Sdes#endif /* HAVE_PTHREAD */ 98238106Sdes#else 99238106Sdes (void)sig; 100238106Sdes#endif /* have signal stuff */ 101238106Sdes} 102238106Sdes 103238106Sdes#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS) 104238106Sdes/** 105238106Sdes * No threading available: fork a new process. 106238106Sdes * This means no shared data structure, and no locking. 107238106Sdes * Only the main thread ever returns. Exits on errors. 108238106Sdes * @param thr: the location where to store the thread-id. 109238106Sdes * @param func: function body of the thread. Return value of func is lost. 110238106Sdes * @param arg: user argument to func. 111238106Sdes */ 112238106Sdesvoid 113238106Sdesub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg) 114238106Sdes{ 115238106Sdes pid_t pid = fork(); 116238106Sdes switch(pid) { 117238106Sdes default: /* main */ 118238106Sdes *thr = (ub_thread_t)pid; 119238106Sdes return; 120238106Sdes case 0: /* child */ 121238106Sdes *thr = (ub_thread_t)getpid(); 122238106Sdes (void)(*func)(arg); 123238106Sdes exit(0); 124238106Sdes case -1: /* error */ 125238106Sdes fatal_exit("could not fork: %s", strerror(errno)); 126238106Sdes } 127238106Sdes} 128238106Sdes 129238106Sdes/** 130238106Sdes * There is no threading. Wait for a process to terminate. 131238106Sdes * Note that ub_thread_t is defined as pid_t. 132238106Sdes * @param thread: the process id to wait for. 133238106Sdes */ 134238106Sdesvoid ub_thr_fork_wait(ub_thread_t thread) 135238106Sdes{ 136238106Sdes int status = 0; 137238106Sdes if(waitpid((pid_t)thread, &status, 0) == -1) 138238106Sdes log_err("waitpid(%d): %s", (int)thread, strerror(errno)); 139238106Sdes if(status != 0) 140238106Sdes log_warn("process %d abnormal exit with status %d", 141238106Sdes (int)thread, status); 142238106Sdes} 143238106Sdes#endif /* !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS) */ 144238106Sdes 145238106Sdes#ifdef HAVE_SOLARIS_THREADS 146238106Sdesvoid* ub_thread_key_get(ub_thread_key_t key) 147238106Sdes{ 148238106Sdes void* ret=NULL; 149238106Sdes LOCKRET(thr_getspecific(key, &ret)); 150238106Sdes return ret; 151238106Sdes} 152238106Sdes#endif 153238106Sdes 154238106Sdes#ifdef HAVE_WINDOWS_THREADS 155238106Sdes/** log a windows GetLastError message */ 156238106Sdesstatic void log_win_err(const char* str, DWORD err) 157238106Sdes{ 158238106Sdes LPTSTR buf; 159238106Sdes if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 160238106Sdes FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, 161238106Sdes NULL, err, 0, (LPTSTR)&buf, 0, NULL) == 0) { 162238106Sdes /* could not format error message */ 163238106Sdes log_err("%s, GetLastError=%d", str, (int)err); 164238106Sdes return; 165238106Sdes } 166238106Sdes log_err("%s, (err=%d): %s", str, (int)err, buf); 167238106Sdes LocalFree(buf); 168238106Sdes} 169238106Sdes 170238106Sdesvoid lock_basic_init(lock_basic_t* lock) 171238106Sdes{ 172238106Sdes /* implement own lock, because windows HANDLE as Mutex usage 173238106Sdes * uses too many handles and would bog down the whole system. */ 174238106Sdes (void)InterlockedExchange(lock, 0); 175238106Sdes} 176238106Sdes 177238106Sdesvoid lock_basic_destroy(lock_basic_t* lock) 178238106Sdes{ 179238106Sdes (void)InterlockedExchange(lock, 0); 180238106Sdes} 181238106Sdes 182238106Sdesvoid lock_basic_lock(lock_basic_t* lock) 183238106Sdes{ 184238106Sdes LONG wait = 1; /* wait 1 msec at first */ 185238106Sdes 186238106Sdes while(InterlockedExchange(lock, 1)) { 187238106Sdes /* if the old value was 1 then if was already locked */ 188238106Sdes Sleep(wait); /* wait with sleep */ 189238106Sdes wait *= 2; /* exponential backoff for waiting */ 190238106Sdes } 191238106Sdes /* the old value was 0, but we inserted 1, we locked it! */ 192238106Sdes} 193238106Sdes 194238106Sdesvoid lock_basic_unlock(lock_basic_t* lock) 195238106Sdes{ 196238106Sdes /* unlock it by inserting the value of 0. xchg for cache coherency. */ 197238106Sdes (void)InterlockedExchange(lock, 0); 198238106Sdes} 199238106Sdes 200238106Sdesvoid ub_thread_key_create(ub_thread_key_t* key, void* f) 201238106Sdes{ 202238106Sdes *key = TlsAlloc(); 203238106Sdes if(*key == TLS_OUT_OF_INDEXES) { 204238106Sdes *key = 0; 205238106Sdes log_win_err("TlsAlloc Failed(OUT_OF_INDEXES)", GetLastError()); 206238106Sdes } 207238106Sdes else ub_thread_key_set(*key, f); 208238106Sdes} 209238106Sdes 210238106Sdesvoid ub_thread_key_set(ub_thread_key_t key, void* v) 211238106Sdes{ 212238106Sdes if(!TlsSetValue(key, v)) { 213238106Sdes log_win_err("TlsSetValue failed", GetLastError()); 214238106Sdes } 215238106Sdes} 216238106Sdes 217238106Sdesvoid* ub_thread_key_get(ub_thread_key_t key) 218238106Sdes{ 219238106Sdes void* ret = (void*)TlsGetValue(key); 220238106Sdes if(ret == NULL && GetLastError() != ERROR_SUCCESS) { 221238106Sdes log_win_err("TlsGetValue failed", GetLastError()); 222238106Sdes } 223238106Sdes return ret; 224238106Sdes} 225238106Sdes 226238106Sdesvoid ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg) 227238106Sdes{ 228238106Sdes#ifndef HAVE__BEGINTHREADEX 229238106Sdes *thr = CreateThread(NULL, /* default security (no inherit handle) */ 230238106Sdes 0, /* default stack size */ 231238106Sdes (LPTHREAD_START_ROUTINE)func, arg, 232238106Sdes 0, /* default flags, run immediately */ 233238106Sdes NULL); /* do not store thread identifier anywhere */ 234238106Sdes#else 235238106Sdes /* the begintheadex routine setups for the C lib; aligns stack */ 236238106Sdes *thr=(ub_thread_t)_beginthreadex(NULL, 0, (void*)func, arg, 0, NULL); 237238106Sdes#endif 238238106Sdes if(*thr == NULL) { 239238106Sdes log_win_err("CreateThread failed", GetLastError()); 240238106Sdes fatal_exit("thread create failed"); 241238106Sdes } 242238106Sdes} 243238106Sdes 244238106Sdesub_thread_t ub_thread_self(void) 245238106Sdes{ 246238106Sdes return GetCurrentThread(); 247238106Sdes} 248238106Sdes 249238106Sdesvoid ub_thread_join(ub_thread_t thr) 250238106Sdes{ 251238106Sdes DWORD ret = WaitForSingleObject(thr, INFINITE); 252238106Sdes if(ret == WAIT_FAILED) { 253238106Sdes log_win_err("WaitForSingleObject(Thread):WAIT_FAILED", 254238106Sdes GetLastError()); 255238106Sdes } else if(ret == WAIT_TIMEOUT) { 256238106Sdes log_win_err("WaitForSingleObject(Thread):WAIT_TIMEOUT", 257238106Sdes GetLastError()); 258238106Sdes } 259238106Sdes /* and close the handle to the thread */ 260238106Sdes if(!CloseHandle(thr)) { 261238106Sdes log_win_err("CloseHandle(Thread) failed", GetLastError()); 262238106Sdes } 263238106Sdes} 264238106Sdes#endif /* HAVE_WINDOWS_THREADS */ 265