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_t
* thr
, void* (*func
)(void*), void* arg
)
118 *thr
= (ub_thread_t
)pid
;
121 *thr
= (ub_thread_t
)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_t is defined as pid_t.
132 * @param thread: the process id to wait for.
134 void ub_thr_fork_wait(ub_thread_t 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_t 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_t
* 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_t
* lock
)
179 (void)InterlockedExchange(lock
, 0);
182 void lock_basic_lock(lock_basic_t
* 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_t
* 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_t
* 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_t key
, void* v
)
212 if(!TlsSetValue(key
, v
)) {
213 log_win_err("TlsSetValue failed", GetLastError());
217 void* ub_thread_key_get(ub_thread_key_t 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_t
* 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 begintheadex routine setups for the C lib; aligns stack */
236 *thr
=(ub_thread_t
)_beginthreadex(NULL
, 0, (void*)func
, arg
, 0, NULL
);
239 log_win_err("CreateThread failed", GetLastError());
240 fatal_exit("thread create failed");
244 ub_thread_t
ub_thread_self(void)
246 return GetCurrentThread();
249 void ub_thread_join(ub_thread_t 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 */