2 * util/locks.c - unbound locking primitives
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
38 * Implementation of locking and threading support.
39 * A place for locking debug code since most locking functions are macros.
43 #include "util/locks.h"
45 #ifdef HAVE_SYS_WAIT_H
49 /** block all signals, masks them away. */
51 ub_thread_blocksigs(void)
53 #if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK)
54 # if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS)
60 if((err=pthread_sigmask(SIG_SETMASK, &sigset, NULL)))
61 fatal_exit("pthread_sigmask: %s", strerror(err));
63 # ifdef HAVE_SOLARIS_THREADS
64 if((err=thr_sigsetmask(SIG_SETMASK, &sigset, NULL)))
65 fatal_exit("thr_sigsetmask: %s", strerror(err));
67 /* have nothing, do single process signal mask */
68 if(sigprocmask(SIG_SETMASK, &sigset, NULL))
69 fatal_exit("sigprocmask: %s", strerror(errno));
70 # endif /* HAVE_SOLARIS_THREADS */
71 #endif /* HAVE_PTHREAD */
72 #endif /* have signal stuff */
75 /** unblock one signal, so we can catch it */
76 void ub_thread_sig_unblock(int sig)
78 #if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK)
79 # if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS)
84 sigaddset(&sigset, sig);
86 if((err=pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)))
87 fatal_exit("pthread_sigmask: %s", strerror(err));
89 # ifdef HAVE_SOLARIS_THREADS
90 if((err=thr_sigsetmask(SIG_UNBLOCK, &sigset, NULL)))
91 fatal_exit("thr_sigsetmask: %s", strerror(err));
93 /* have nothing, do single thread case */
94 if(sigprocmask(SIG_UNBLOCK, &sigset, NULL))
95 fatal_exit("sigprocmask: %s", strerror(errno));
96 # endif /* HAVE_SOLARIS_THREADS */
97 #endif /* HAVE_PTHREAD */
100 #endif /* have signal stuff */
103 #if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS)
105 * No threading available: fork a new process.
106 * This means no shared data structure, and no locking.
107 * Only the main thread ever returns. Exits on errors.
108 * @param thr: the location where to store the thread-id.
109 * @param func: function body of the thread. Return value of func is lost.
110 * @param arg: user argument to func.
113 ub_thr_fork_create(ub_thread_type* thr, void* (*func)(void*), void* arg)
118 *thr = (ub_thread_type)pid;
121 *thr = (ub_thread_type)getpid();
125 fatal_exit("could not fork: %s", strerror(errno));
130 * There is no threading. Wait for a process to terminate.
131 * Note that ub_thread_type is defined as pid_t.
132 * @param thread: the process id to wait for.
134 void ub_thr_fork_wait(ub_thread_type thread)
137 if(waitpid((pid_t)thread, &status, 0) == -1)
138 log_err("waitpid(%d): %s", (int)thread, strerror(errno));
140 log_warn("process %d abnormal exit with status %d",
141 (int)thread, status);
143 #endif /* !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS) */
145 #ifdef HAVE_SOLARIS_THREADS
146 void* ub_thread_key_get(ub_thread_key_type key)
149 LOCKRET(thr_getspecific(key, &ret));
154 #ifdef HAVE_WINDOWS_THREADS
155 /** log a windows GetLastError message */
156 static void log_win_err(const char* str, DWORD err)
159 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
160 FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
161 NULL, err, 0, (LPTSTR)&buf, 0, NULL) == 0) {
162 /* could not format error message */
163 log_err("%s, GetLastError=%d", str, (int)err);
166 log_err("%s, (err=%d): %s", str, (int)err, buf);
170 void lock_basic_init(lock_basic_type* lock)
172 /* implement own lock, because windows HANDLE as Mutex usage
173 * uses too many handles and would bog down the whole system. */
174 (void)InterlockedExchange(lock, 0);
177 void lock_basic_destroy(lock_basic_type* lock)
179 (void)InterlockedExchange(lock, 0);
182 void lock_basic_lock(lock_basic_type* lock)
184 LONG wait = 1; /* wait 1 msec at first */
186 while(InterlockedExchange(lock, 1)) {
187 /* if the old value was 1 then if was already locked */
188 Sleep(wait); /* wait with sleep */
189 wait *= 2; /* exponential backoff for waiting */
191 /* the old value was 0, but we inserted 1, we locked it! */
194 void lock_basic_unlock(lock_basic_type* lock)
196 /* unlock it by inserting the value of 0. xchg for cache coherency. */
197 (void)InterlockedExchange(lock, 0);
200 void ub_thread_key_create(ub_thread_key_type* key, void* f)
203 if(*key == TLS_OUT_OF_INDEXES) {
205 log_win_err("TlsAlloc Failed(OUT_OF_INDEXES)", GetLastError());
207 else ub_thread_key_set(*key, f);
210 void ub_thread_key_set(ub_thread_key_type key, void* v)
212 if(!TlsSetValue(key, v)) {
213 log_win_err("TlsSetValue failed", GetLastError());
217 void* ub_thread_key_get(ub_thread_key_type key)
219 void* ret = (void*)TlsGetValue(key);
220 if(ret == NULL && GetLastError() != ERROR_SUCCESS) {
221 log_win_err("TlsGetValue failed", GetLastError());
226 void ub_thread_create(ub_thread_type* thr, void* (*func)(void*), void* arg)
228 #ifndef HAVE__BEGINTHREADEX
229 *thr = CreateThread(NULL, /* default security (no inherit handle) */
230 0, /* default stack size */
231 (LPTHREAD_START_ROUTINE)func, arg,
232 0, /* default flags, run immediately */
233 NULL); /* do not store thread identifier anywhere */
235 /* the beginthreadex routine setups for the C lib; aligns stack */
236 *thr=(ub_thread_type)_beginthreadex(NULL, 0, (void*)func, arg, 0, NULL);
239 log_win_err("CreateThread failed", GetLastError());
240 fatal_exit("thread create failed");
244 ub_thread_type ub_thread_self(void)
246 return GetCurrentThread();
249 void ub_thread_join(ub_thread_type thr)
251 DWORD ret = WaitForSingleObject(thr, INFINITE);
252 if(ret == WAIT_FAILED) {
253 log_win_err("WaitForSingleObject(Thread):WAIT_FAILED",
255 } else if(ret == WAIT_TIMEOUT) {
256 log_win_err("WaitForSingleObject(Thread):WAIT_TIMEOUT",
259 /* and close the handle to the thread */
260 if(!CloseHandle(thr)) {
261 log_win_err("CloseHandle(Thread) failed", GetLastError());
264 #endif /* HAVE_WINDOWS_THREADS */