2 * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "namespace.h"
28 #include <sys/signalvar.h>
29 #include <machine/tls.h>
34 #include "un-namespace.h"
36 #include "thr_private.h"
38 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
44 /* #define DEBUG_SIGNAL */
46 #define DBG_MSG stdout_debug
51 int __sigwait(const sigset_t *set, int *sig);
52 int __sigwaitinfo(const sigset_t *set, siginfo_t *info);
53 int __sigtimedwait(const sigset_t *set, siginfo_t *info,
54 const struct timespec * timeout);
56 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
57 static void _thr_debug_sig(int signo);
61 sigcancel_handler(int sig __unused, siginfo_t *info __unused,
62 ucontext_t *ucp __unused)
64 struct pthread *curthread = tls_get_curthread();
66 if (curthread->cancelflags & THR_CANCEL_AT_POINT)
67 _pthread_testcancel();
72 _thr_ast(struct pthread *curthread)
74 if (!THR_IN_CRITICAL(curthread)) {
75 if (__predict_false((curthread->flags &
76 (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
77 == THR_FLAGS_NEED_SUSPEND))
78 _thr_suspend_check(curthread);
83 _thr_suspend_check(struct pthread *curthread)
88 * Blocks SIGCANCEL which other threads must send.
90 _thr_signal_block(curthread);
93 * Increase critical_count, here we don't use THR_LOCK/UNLOCK
94 * because we are leaf code, we don't want to recursively call
97 curthread->critical_count++;
98 THR_UMTX_LOCK(curthread, &(curthread)->lock);
99 while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
100 THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
102 cycle = curthread->cycle;
104 /* Wake the thread suspending us. */
105 _thr_umtx_wake(&curthread->cycle, INT_MAX);
108 * if we are from pthread_exit, we don't want to
109 * suspend, just go and die.
111 if (curthread->state == PS_DEAD)
113 curthread->flags |= THR_FLAGS_SUSPENDED;
114 THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
115 _thr_umtx_wait(&curthread->cycle, cycle, NULL, 0);
116 THR_UMTX_LOCK(curthread, &(curthread)->lock);
117 curthread->flags &= ~THR_FLAGS_SUSPENDED;
119 THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
120 curthread->critical_count--;
122 _thr_signal_unblock(curthread);
126 _thr_signal_init(void)
128 struct sigaction act;
130 /* Install cancel handler. */
131 SIGEMPTYSET(act.sa_mask);
132 act.sa_flags = SA_SIGINFO | SA_RESTART;
133 act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
134 __sys_sigaction(SIGCANCEL, &act, NULL);
136 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
138 * If enabled, rwlock, mutex, and condition variable operations
139 * are recorded in a text buffer and signal 63 dumps the buffer
140 * to /tmp/cond${pid}.log.
142 act.sa_flags = SA_RESTART;
143 act.sa_handler = _thr_debug_sig;
144 __sys_sigaction(63, &act, NULL);
149 _thr_signal_deinit(void)
154 _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
156 /* Check if the signal number is out of range: */
157 if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) {
158 /* Return an invalid argument: */
163 return __sys_sigaction(sig, act, oact);
166 __strong_reference(_sigaction, sigaction);
169 _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
171 const sigset_t *p = set;
174 if (how != SIG_UNBLOCK) {
177 SIGDELSET(newset, SIGCANCEL);
181 return (__sys_sigprocmask(how, p, oset));
184 __strong_reference(_sigprocmask, sigprocmask);
187 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
189 if (_sigprocmask(how, set, oset))
194 __strong_reference(_pthread_sigmask, pthread_sigmask);
197 _sigsuspend(const sigset_t * set)
199 struct pthread *curthread = tls_get_curthread();
201 const sigset_t *pset;
205 if (SIGISMEMBER(*set, SIGCANCEL)) {
207 SIGDELSET(newset, SIGCANCEL);
212 oldcancel = _thr_cancel_enter(curthread);
213 ret = __sys_sigsuspend(pset);
214 _thr_cancel_leave(curthread, oldcancel);
219 __strong_reference(_sigsuspend, sigsuspend);
222 __sigtimedwait(const sigset_t *set, siginfo_t *info,
223 const struct timespec * timeout)
225 struct pthread *curthread = tls_get_curthread();
227 const sigset_t *pset;
231 if (SIGISMEMBER(*set, SIGCANCEL)) {
233 SIGDELSET(newset, SIGCANCEL);
237 oldcancel = _thr_cancel_enter(curthread);
238 ret = __sys_sigtimedwait(pset, info, timeout);
239 _thr_cancel_leave(curthread, oldcancel);
243 __strong_reference(__sigtimedwait, sigtimedwait);
246 __sigwaitinfo(const sigset_t *set, siginfo_t *info)
248 struct pthread *curthread = tls_get_curthread();
250 const sigset_t *pset;
254 if (SIGISMEMBER(*set, SIGCANCEL)) {
256 SIGDELSET(newset, SIGCANCEL);
261 oldcancel = _thr_cancel_enter(curthread);
262 ret = __sys_sigwaitinfo(pset, info);
263 _thr_cancel_leave(curthread, oldcancel);
267 __strong_reference(__sigwaitinfo, sigwaitinfo);
270 __sigwait(const sigset_t *set, int *sig)
274 s = __sigwaitinfo(set, NULL);
282 __strong_reference(__sigwait, sigwait);
284 #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
286 #define LOGBUF_SIZE (4 * 1024 * 1024)
287 #define LOGBUF_MASK (LOGBUF_SIZE - 1)
289 char LogBuf[LOGBUF_SIZE];
290 unsigned long LogWIndex;
293 _thr_log(const char *buf, size_t bytes)
295 struct pthread *curthread;
300 curthread = tls_get_curthread();
302 plen = snprintf(prefix, sizeof(prefix), "%d.%d: ",
306 plen = snprintf(prefix, sizeof(prefix), "unknown: ");
311 i = atomic_fetchadd_long(&LogWIndex, plen + bytes);
313 if (plen <= (size_t)(LOGBUF_SIZE - i)) {
314 bcopy(prefix, LogBuf + i, plen);
316 bcopy(prefix, LogBuf + i, LOGBUF_SIZE - i);
317 plen -= LOGBUF_SIZE - i;
318 bcopy(prefix, LogBuf, plen);
323 if (bytes <= (size_t)(LOGBUF_SIZE - i)) {
324 bcopy(buf, LogBuf + i, bytes);
326 bcopy(buf, LogBuf + i, LOGBUF_SIZE - i);
327 bytes -= LOGBUF_SIZE - i;
328 bcopy(buf, LogBuf, bytes);
333 _thr_debug_sig(int signo __unused)
339 snprintf(buf, sizeof(buf), "/tmp/cond%d.log", (int)__sys_getpid());
340 fd = open(buf, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0666);
343 if (i < LOGBUF_SIZE) {
344 write(fd, LogBuf, i);
347 write(fd, LogBuf + i, LOGBUF_SIZE - i);
348 write(fd, LogBuf, i);