171b3fa15SDavid Xu /*
2d3b15642Szrj * Copyright (c) 2005, David Xu <davidxu@freebsd.org>
371b3fa15SDavid Xu * All rights reserved.
471b3fa15SDavid Xu *
571b3fa15SDavid Xu * Redistribution and use in source and binary forms, with or without
671b3fa15SDavid Xu * modification, are permitted provided that the following conditions
771b3fa15SDavid Xu * are met:
871b3fa15SDavid Xu * 1. Redistributions of source code must retain the above copyright
971b3fa15SDavid Xu * notice, this list of conditions and the following disclaimer.
1071b3fa15SDavid Xu * 2. Redistributions in binary form must reproduce the above copyright
1171b3fa15SDavid Xu * notice, this list of conditions and the following disclaimer in the
1271b3fa15SDavid Xu * documentation and/or other materials provided with the distribution.
1371b3fa15SDavid Xu *
14d3b15642Szrj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15d3b15642Szrj * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16d3b15642Szrj * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17d3b15642Szrj * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18d3b15642Szrj * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19d3b15642Szrj * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20d3b15642Szrj * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21d3b15642Szrj * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22d3b15642Szrj * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23d3b15642Szrj * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2471b3fa15SDavid Xu *
2571b3fa15SDavid Xu */
2671b3fa15SDavid Xu
27fc71f871SDavid Xu #include "namespace.h"
2871b3fa15SDavid Xu #include <sys/signalvar.h>
299e2ee207SJoerg Sonnenberger #include <machine/tls.h>
3071b3fa15SDavid Xu #include <signal.h>
3171b3fa15SDavid Xu #include <errno.h>
3271b3fa15SDavid Xu #include <string.h>
3371b3fa15SDavid Xu #include <pthread.h>
34fc71f871SDavid Xu #include "un-namespace.h"
3571b3fa15SDavid Xu
3671b3fa15SDavid Xu #include "thr_private.h"
3771b3fa15SDavid Xu
38fcaa7a3aSMatthew Dillon #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
39fcaa7a3aSMatthew Dillon #include <sys/file.h>
40fcaa7a3aSMatthew Dillon #include <stdio.h>
41fcaa7a3aSMatthew Dillon #endif
42fcaa7a3aSMatthew Dillon
4371b3fa15SDavid Xu /* #define DEBUG_SIGNAL */
4471b3fa15SDavid Xu #ifdef DEBUG_SIGNAL
4571b3fa15SDavid Xu #define DBG_MSG stdout_debug
4671b3fa15SDavid Xu #else
4771b3fa15SDavid Xu #define DBG_MSG(x...)
4871b3fa15SDavid Xu #endif
4971b3fa15SDavid Xu
50fc71f871SDavid Xu int __sigwait(const sigset_t *set, int *sig);
51fc71f871SDavid Xu int __sigwaitinfo(const sigset_t *set, siginfo_t *info);
52fc71f871SDavid Xu int __sigtimedwait(const sigset_t *set, siginfo_t *info,
53fc71f871SDavid Xu const struct timespec * timeout);
54fc71f871SDavid Xu
55fcaa7a3aSMatthew Dillon #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
56fcaa7a3aSMatthew Dillon static void _thr_debug_sig(int signo);
57fcaa7a3aSMatthew Dillon #endif
58fcaa7a3aSMatthew Dillon
5971b3fa15SDavid Xu static void
sigcancel_handler(int sig __unused,siginfo_t * info __unused,ucontext_t * ucp __unused)60fc71f871SDavid Xu sigcancel_handler(int sig __unused, siginfo_t *info __unused,
61fc71f871SDavid Xu ucontext_t *ucp __unused)
6271b3fa15SDavid Xu {
63*940be950Szrj pthread_t curthread = tls_get_curthread();
6471b3fa15SDavid Xu
6571b3fa15SDavid Xu if (curthread->cancelflags & THR_CANCEL_AT_POINT)
66fc71f871SDavid Xu _pthread_testcancel();
67fd4288bdSDavid Xu _thr_ast(curthread);
68fd4288bdSDavid Xu }
69fd4288bdSDavid Xu
70fd4288bdSDavid Xu void
_thr_ast(pthread_t curthread)71*940be950Szrj _thr_ast(pthread_t curthread)
72fd4288bdSDavid Xu {
73fd4288bdSDavid Xu if (!THR_IN_CRITICAL(curthread)) {
74fd4288bdSDavid Xu if (__predict_false((curthread->flags &
75fd4288bdSDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED))
76fd4288bdSDavid Xu == THR_FLAGS_NEED_SUSPEND))
7771b3fa15SDavid Xu _thr_suspend_check(curthread);
7871b3fa15SDavid Xu }
7971b3fa15SDavid Xu }
8071b3fa15SDavid Xu
8171b3fa15SDavid Xu void
_thr_suspend_check(pthread_t curthread)82*940be950Szrj _thr_suspend_check(pthread_t curthread)
8371b3fa15SDavid Xu {
84fd4288bdSDavid Xu umtx_t cycle;
8571b3fa15SDavid Xu
86fd4288bdSDavid Xu /*
87fd4288bdSDavid Xu * Blocks SIGCANCEL which other threads must send.
88fd4288bdSDavid Xu */
8971b3fa15SDavid Xu _thr_signal_block(curthread);
90fd4288bdSDavid Xu
91fd4288bdSDavid Xu /*
92fd4288bdSDavid Xu * Increase critical_count, here we don't use THR_LOCK/UNLOCK
93fd4288bdSDavid Xu * because we are leaf code, we don't want to recursively call
94fd4288bdSDavid Xu * ourself.
95fd4288bdSDavid Xu */
96fd4288bdSDavid Xu curthread->critical_count++;
97fd4288bdSDavid Xu THR_UMTX_LOCK(curthread, &(curthread)->lock);
98fd4288bdSDavid Xu while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND |
99fd4288bdSDavid Xu THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) {
100fd4288bdSDavid Xu curthread->cycle++;
10171b3fa15SDavid Xu cycle = curthread->cycle;
102fd4288bdSDavid Xu
103fd4288bdSDavid Xu /* Wake the thread suspending us. */
10498247283SMatthew Dillon _thr_umtx_wake(&curthread->cycle, 0);
105fd4288bdSDavid Xu
106fd4288bdSDavid Xu /*
107fd4288bdSDavid Xu * if we are from pthread_exit, we don't want to
108fd4288bdSDavid Xu * suspend, just go and die.
109fd4288bdSDavid Xu */
110fd4288bdSDavid Xu if (curthread->state == PS_DEAD)
111fd4288bdSDavid Xu break;
112fd4288bdSDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED;
113fd4288bdSDavid Xu THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
1149219c44cSDavid Xu _thr_umtx_wait(&curthread->cycle, cycle, NULL, 0);
115fd4288bdSDavid Xu THR_UMTX_LOCK(curthread, &(curthread)->lock);
11671b3fa15SDavid Xu curthread->flags &= ~THR_FLAGS_SUSPENDED;
11771b3fa15SDavid Xu }
118fd4288bdSDavid Xu THR_UMTX_UNLOCK(curthread, &(curthread)->lock);
119fd4288bdSDavid Xu curthread->critical_count--;
120fd4288bdSDavid Xu
12171b3fa15SDavid Xu _thr_signal_unblock(curthread);
12271b3fa15SDavid Xu }
12371b3fa15SDavid Xu
12471b3fa15SDavid Xu void
_thr_signal_init(void)12571b3fa15SDavid Xu _thr_signal_init(void)
12671b3fa15SDavid Xu {
12771b3fa15SDavid Xu struct sigaction act;
12871b3fa15SDavid Xu
12971b3fa15SDavid Xu /* Install cancel handler. */
13071b3fa15SDavid Xu SIGEMPTYSET(act.sa_mask);
13171b3fa15SDavid Xu act.sa_flags = SA_SIGINFO | SA_RESTART;
13271b3fa15SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler;
13371b3fa15SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL);
134fcaa7a3aSMatthew Dillon
135fcaa7a3aSMatthew Dillon #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
136fcaa7a3aSMatthew Dillon /*
137fcaa7a3aSMatthew Dillon * If enabled, rwlock, mutex, and condition variable operations
138fcaa7a3aSMatthew Dillon * are recorded in a text buffer and signal 63 dumps the buffer
139fcaa7a3aSMatthew Dillon * to /tmp/cond${pid}.log.
140fcaa7a3aSMatthew Dillon */
141fcaa7a3aSMatthew Dillon act.sa_flags = SA_RESTART;
142fcaa7a3aSMatthew Dillon act.sa_handler = _thr_debug_sig;
143fcaa7a3aSMatthew Dillon __sys_sigaction(63, &act, NULL);
144fcaa7a3aSMatthew Dillon #endif
14571b3fa15SDavid Xu }
14671b3fa15SDavid Xu
14771b3fa15SDavid Xu void
_thr_signal_deinit(void)14871b3fa15SDavid Xu _thr_signal_deinit(void)
14971b3fa15SDavid Xu {
15071b3fa15SDavid Xu }
15171b3fa15SDavid Xu
15271b3fa15SDavid Xu int
_sigaction(int sig,const struct sigaction * act,struct sigaction * oact)15371b3fa15SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact)
15471b3fa15SDavid Xu {
15571b3fa15SDavid Xu /* Check if the signal number is out of range: */
15671b3fa15SDavid Xu if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) {
15771b3fa15SDavid Xu /* Return an invalid argument: */
15871b3fa15SDavid Xu errno = EINVAL;
15971b3fa15SDavid Xu return (-1);
16071b3fa15SDavid Xu }
16171b3fa15SDavid Xu
16271b3fa15SDavid Xu return __sys_sigaction(sig, act, oact);
16371b3fa15SDavid Xu }
16471b3fa15SDavid Xu
1655a1048c8SDavid Xu __strong_reference(_sigaction, sigaction);
16671b3fa15SDavid Xu
16771b3fa15SDavid Xu int
_sigprocmask(int how,const sigset_t * set,sigset_t * oset)16871b3fa15SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset)
16971b3fa15SDavid Xu {
17071b3fa15SDavid Xu const sigset_t *p = set;
17171b3fa15SDavid Xu sigset_t newset;
17271b3fa15SDavid Xu
17371b3fa15SDavid Xu if (how != SIG_UNBLOCK) {
17471b3fa15SDavid Xu if (set != NULL) {
17571b3fa15SDavid Xu newset = *set;
17671b3fa15SDavid Xu SIGDELSET(newset, SIGCANCEL);
17771b3fa15SDavid Xu p = &newset;
17871b3fa15SDavid Xu }
17971b3fa15SDavid Xu }
18071b3fa15SDavid Xu return (__sys_sigprocmask(how, p, oset));
18171b3fa15SDavid Xu }
18271b3fa15SDavid Xu
1835a1048c8SDavid Xu __strong_reference(_sigprocmask, sigprocmask);
18471b3fa15SDavid Xu
18571b3fa15SDavid Xu int
_pthread_sigmask(int how,const sigset_t * set,sigset_t * oset)18671b3fa15SDavid Xu _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
18771b3fa15SDavid Xu {
18871b3fa15SDavid Xu if (_sigprocmask(how, set, oset))
18971b3fa15SDavid Xu return (errno);
19071b3fa15SDavid Xu return (0);
19171b3fa15SDavid Xu }
19271b3fa15SDavid Xu
1935a1048c8SDavid Xu __strong_reference(_pthread_sigmask, pthread_sigmask);
19471b3fa15SDavid Xu
19571b3fa15SDavid Xu int
_sigsuspend(const sigset_t * set)19671b3fa15SDavid Xu _sigsuspend(const sigset_t * set)
19771b3fa15SDavid Xu {
198*940be950Szrj pthread_t curthread = tls_get_curthread();
19971b3fa15SDavid Xu sigset_t newset;
20071b3fa15SDavid Xu const sigset_t *pset;
20171b3fa15SDavid Xu int oldcancel;
20271b3fa15SDavid Xu int ret;
20371b3fa15SDavid Xu
20471b3fa15SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) {
20571b3fa15SDavid Xu newset = *set;
20671b3fa15SDavid Xu SIGDELSET(newset, SIGCANCEL);
20771b3fa15SDavid Xu pset = &newset;
20871b3fa15SDavid Xu } else
20971b3fa15SDavid Xu pset = set;
21071b3fa15SDavid Xu
21171b3fa15SDavid Xu oldcancel = _thr_cancel_enter(curthread);
21271b3fa15SDavid Xu ret = __sys_sigsuspend(pset);
21371b3fa15SDavid Xu _thr_cancel_leave(curthread, oldcancel);
21471b3fa15SDavid Xu
21571b3fa15SDavid Xu return (ret);
21671b3fa15SDavid Xu }
21771b3fa15SDavid Xu
2185a1048c8SDavid Xu __strong_reference(_sigsuspend, sigsuspend);
21971b3fa15SDavid Xu
22071b3fa15SDavid Xu int
__sigtimedwait(const sigset_t * set,siginfo_t * info,const struct timespec * timeout)22171b3fa15SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info,
22271b3fa15SDavid Xu const struct timespec * timeout)
22371b3fa15SDavid Xu {
224*940be950Szrj pthread_t curthread = tls_get_curthread();
22571b3fa15SDavid Xu sigset_t newset;
22671b3fa15SDavid Xu const sigset_t *pset;
22771b3fa15SDavid Xu int oldcancel;
22871b3fa15SDavid Xu int ret;
22971b3fa15SDavid Xu
23071b3fa15SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) {
23171b3fa15SDavid Xu newset = *set;
23271b3fa15SDavid Xu SIGDELSET(newset, SIGCANCEL);
23371b3fa15SDavid Xu pset = &newset;
23471b3fa15SDavid Xu } else
23571b3fa15SDavid Xu pset = set;
23671b3fa15SDavid Xu oldcancel = _thr_cancel_enter(curthread);
23771b3fa15SDavid Xu ret = __sys_sigtimedwait(pset, info, timeout);
23871b3fa15SDavid Xu _thr_cancel_leave(curthread, oldcancel);
23971b3fa15SDavid Xu return (ret);
24071b3fa15SDavid Xu }
24171b3fa15SDavid Xu
2425a1048c8SDavid Xu __strong_reference(__sigtimedwait, sigtimedwait);
2435a1048c8SDavid Xu
24471b3fa15SDavid Xu int
__sigwaitinfo(const sigset_t * set,siginfo_t * info)24571b3fa15SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info)
24671b3fa15SDavid Xu {
247*940be950Szrj pthread_t curthread = tls_get_curthread();
24871b3fa15SDavid Xu sigset_t newset;
24971b3fa15SDavid Xu const sigset_t *pset;
25071b3fa15SDavid Xu int oldcancel;
25171b3fa15SDavid Xu int ret;
25271b3fa15SDavid Xu
25371b3fa15SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) {
25471b3fa15SDavid Xu newset = *set;
25571b3fa15SDavid Xu SIGDELSET(newset, SIGCANCEL);
25671b3fa15SDavid Xu pset = &newset;
25771b3fa15SDavid Xu } else
25871b3fa15SDavid Xu pset = set;
25971b3fa15SDavid Xu
26071b3fa15SDavid Xu oldcancel = _thr_cancel_enter(curthread);
26171b3fa15SDavid Xu ret = __sys_sigwaitinfo(pset, info);
26271b3fa15SDavid Xu _thr_cancel_leave(curthread, oldcancel);
26371b3fa15SDavid Xu return (ret);
26471b3fa15SDavid Xu }
26571b3fa15SDavid Xu
2665a1048c8SDavid Xu __strong_reference(__sigwaitinfo, sigwaitinfo);
2675a1048c8SDavid Xu
26871b3fa15SDavid Xu int
__sigwait(const sigset_t * set,int * sig)26971b3fa15SDavid Xu __sigwait(const sigset_t *set, int *sig)
27071b3fa15SDavid Xu {
2717aca7007SDavid Xu int s;
27271b3fa15SDavid Xu
2737aca7007SDavid Xu s = __sigwaitinfo(set, NULL);
2747aca7007SDavid Xu if (s > 0) {
2757aca7007SDavid Xu *sig = s;
2767aca7007SDavid Xu return (0);
27771b3fa15SDavid Xu }
2787aca7007SDavid Xu return (errno);
2797aca7007SDavid Xu }
2805a1048c8SDavid Xu
2815a1048c8SDavid Xu __strong_reference(__sigwait, sigwait);
282fcaa7a3aSMatthew Dillon
283fcaa7a3aSMatthew Dillon #if defined(_PTHREADS_DEBUGGING) || defined(_PTHREADS_DEBUGGING2)
284fcaa7a3aSMatthew Dillon
285fcaa7a3aSMatthew Dillon #define LOGBUF_SIZE (4 * 1024 * 1024)
286fcaa7a3aSMatthew Dillon #define LOGBUF_MASK (LOGBUF_SIZE - 1)
287fcaa7a3aSMatthew Dillon
288fcaa7a3aSMatthew Dillon char LogBuf[LOGBUF_SIZE];
289fcaa7a3aSMatthew Dillon unsigned long LogWIndex;
290fcaa7a3aSMatthew Dillon
291fcaa7a3aSMatthew Dillon void
_thr_log(const char * buf,size_t bytes)292fcaa7a3aSMatthew Dillon _thr_log(const char *buf, size_t bytes)
293fcaa7a3aSMatthew Dillon {
294*940be950Szrj pthread_t curthread;
295fcaa7a3aSMatthew Dillon unsigned long i;
296fcaa7a3aSMatthew Dillon char prefix[32];
297fcaa7a3aSMatthew Dillon size_t plen;
298fcaa7a3aSMatthew Dillon
299fcaa7a3aSMatthew Dillon curthread = tls_get_curthread();
300fcaa7a3aSMatthew Dillon if (curthread) {
301fcaa7a3aSMatthew Dillon plen = snprintf(prefix, sizeof(prefix), "%d.%d: ",
302fcaa7a3aSMatthew Dillon (int)__sys_getpid(),
303fcaa7a3aSMatthew Dillon curthread->tid);
304fcaa7a3aSMatthew Dillon } else {
305fcaa7a3aSMatthew Dillon plen = snprintf(prefix, sizeof(prefix), "unknown: ");
306fcaa7a3aSMatthew Dillon }
307fcaa7a3aSMatthew Dillon
308fcaa7a3aSMatthew Dillon if (bytes == 0)
309fcaa7a3aSMatthew Dillon bytes = strlen(buf);
310fcaa7a3aSMatthew Dillon i = atomic_fetchadd_long(&LogWIndex, plen + bytes);
311fcaa7a3aSMatthew Dillon i = i & LOGBUF_MASK;
312fcaa7a3aSMatthew Dillon if (plen <= (size_t)(LOGBUF_SIZE - i)) {
313fcaa7a3aSMatthew Dillon bcopy(prefix, LogBuf + i, plen);
314fcaa7a3aSMatthew Dillon } else {
315fcaa7a3aSMatthew Dillon bcopy(prefix, LogBuf + i, LOGBUF_SIZE - i);
316fcaa7a3aSMatthew Dillon plen -= LOGBUF_SIZE - i;
317fcaa7a3aSMatthew Dillon bcopy(prefix, LogBuf, plen);
318fcaa7a3aSMatthew Dillon }
319fcaa7a3aSMatthew Dillon
320fcaa7a3aSMatthew Dillon i += plen;
321fcaa7a3aSMatthew Dillon i = i & LOGBUF_MASK;
322fcaa7a3aSMatthew Dillon if (bytes <= (size_t)(LOGBUF_SIZE - i)) {
323fcaa7a3aSMatthew Dillon bcopy(buf, LogBuf + i, bytes);
324fcaa7a3aSMatthew Dillon } else {
325fcaa7a3aSMatthew Dillon bcopy(buf, LogBuf + i, LOGBUF_SIZE - i);
326fcaa7a3aSMatthew Dillon bytes -= LOGBUF_SIZE - i;
327fcaa7a3aSMatthew Dillon bcopy(buf, LogBuf, bytes);
328fcaa7a3aSMatthew Dillon }
329fcaa7a3aSMatthew Dillon }
330fcaa7a3aSMatthew Dillon
331fcaa7a3aSMatthew Dillon static void
_thr_debug_sig(int signo __unused)332fcaa7a3aSMatthew Dillon _thr_debug_sig(int signo __unused)
333fcaa7a3aSMatthew Dillon {
334fcaa7a3aSMatthew Dillon char buf[256];
335fcaa7a3aSMatthew Dillon int fd;
336fcaa7a3aSMatthew Dillon unsigned long i;
337fcaa7a3aSMatthew Dillon
338fcaa7a3aSMatthew Dillon snprintf(buf, sizeof(buf), "/tmp/cond%d.log", (int)__sys_getpid());
339fcaa7a3aSMatthew Dillon fd = open(buf, O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0666);
340fcaa7a3aSMatthew Dillon if (fd >= 0) {
341fcaa7a3aSMatthew Dillon i = LogWIndex;
342fcaa7a3aSMatthew Dillon if (i < LOGBUF_SIZE) {
343fcaa7a3aSMatthew Dillon write(fd, LogBuf, i);
344fcaa7a3aSMatthew Dillon } else {
345fcaa7a3aSMatthew Dillon i &= LOGBUF_MASK;
346fcaa7a3aSMatthew Dillon write(fd, LogBuf + i, LOGBUF_SIZE - i);
347fcaa7a3aSMatthew Dillon write(fd, LogBuf, i);
348fcaa7a3aSMatthew Dillon }
349fcaa7a3aSMatthew Dillon close(fd);
350fcaa7a3aSMatthew Dillon }
351fcaa7a3aSMatthew Dillon }
352fcaa7a3aSMatthew Dillon
353fcaa7a3aSMatthew Dillon #endif
354