1bb535300SJeff Roberson /* 2df2cf821SDavid Xu * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3bb535300SJeff Roberson * All rights reserved. 4bb535300SJeff Roberson * 5bb535300SJeff Roberson * Redistribution and use in source and binary forms, with or without 6bb535300SJeff Roberson * modification, are permitted provided that the following conditions 7bb535300SJeff Roberson * are met: 8bb535300SJeff Roberson * 1. Redistributions of source code must retain the above copyright 9df2cf821SDavid Xu * notice unmodified, this list of conditions, and the following 10df2cf821SDavid Xu * disclaimer. 11bb535300SJeff Roberson * 2. Redistributions in binary form must reproduce the above copyright 12bb535300SJeff Roberson * notice, this list of conditions and the following disclaimer in the 13bb535300SJeff Roberson * documentation and/or other materials provided with the distribution. 14bb535300SJeff Roberson * 15df2cf821SDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16df2cf821SDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17df2cf821SDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18df2cf821SDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19df2cf821SDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20df2cf821SDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21df2cf821SDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22df2cf821SDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23df2cf821SDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24df2cf821SDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25bb535300SJeff Roberson * 26bb535300SJeff Roberson * $FreeBSD$ 27bb535300SJeff Roberson */ 28bb535300SJeff Roberson 2937a6356bSDavid Xu #include "namespace.h" 30bb535300SJeff Roberson #include <sys/param.h> 31bb535300SJeff Roberson #include <sys/types.h> 32bb535300SJeff Roberson #include <sys/signalvar.h> 33bb535300SJeff Roberson #include <signal.h> 34a091d823SDavid Xu #include <errno.h> 35bb535300SJeff Roberson #include <fcntl.h> 36bb535300SJeff Roberson #include <unistd.h> 37a091d823SDavid Xu #include <string.h> 38bb535300SJeff Roberson #include <pthread.h> 3937a6356bSDavid Xu #include "un-namespace.h" 4089552201SMike Makonnen 41bb535300SJeff Roberson #include "thr_private.h" 42bb535300SJeff Roberson 43bb535300SJeff Roberson /* #define DEBUG_SIGNAL */ 44bb535300SJeff Roberson #ifdef DEBUG_SIGNAL 45bb535300SJeff Roberson #define DBG_MSG stdout_debug 46bb535300SJeff Roberson #else 47bb535300SJeff Roberson #define DBG_MSG(x...) 48bb535300SJeff Roberson #endif 49bb535300SJeff Roberson 5005c3a5eaSDavid Xu extern int __pause(void); 5105c3a5eaSDavid Xu int ___pause(void); 5205c3a5eaSDavid Xu int _raise(int); 5337a6356bSDavid Xu int __sigtimedwait(const sigset_t *set, siginfo_t *info, 5437a6356bSDavid Xu const struct timespec * timeout); 5537a6356bSDavid Xu int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 5637a6356bSDavid Xu int __sigwait(const sigset_t *set, int *sig); 5737a6356bSDavid Xu 58a091d823SDavid Xu static void 5937a6356bSDavid Xu sigcancel_handler(int sig __unused, 6037a6356bSDavid Xu siginfo_t *info __unused, ucontext_t *ucp __unused) 61a091d823SDavid Xu { 62a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 63a091d823SDavid Xu 64bc414752SDavid Xu _thr_ast(curthread); 65bc414752SDavid Xu } 66bc414752SDavid Xu 67bc414752SDavid Xu void 68bc414752SDavid Xu _thr_ast(struct pthread *curthread) 69bc414752SDavid Xu { 70bc414752SDavid Xu if (!THR_IN_CRITICAL(curthread)) { 71f08e1bf6SDavid Xu _thr_testcancel(curthread); 72bc414752SDavid Xu if (__predict_false((curthread->flags & 73bc414752SDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 74bc414752SDavid Xu == THR_FLAGS_NEED_SUSPEND)) 75a091d823SDavid Xu _thr_suspend_check(curthread); 76a091d823SDavid Xu } 77a091d823SDavid Xu } 78a091d823SDavid Xu 79a091d823SDavid Xu void 80a091d823SDavid Xu _thr_suspend_check(struct pthread *curthread) 81a091d823SDavid Xu { 82bc414752SDavid Xu umtx_t cycle; 83d448272dSDavid Xu int err; 84a091d823SDavid Xu 85d448272dSDavid Xu err = errno; 86bc414752SDavid Xu /* 87bc414752SDavid Xu * Blocks SIGCANCEL which other threads must send. 88bc414752SDavid Xu */ 89a091d823SDavid Xu _thr_signal_block(curthread); 90bc414752SDavid Xu 91bc414752SDavid Xu /* 92bc414752SDavid Xu * Increase critical_count, here we don't use THR_LOCK/UNLOCK 93bc414752SDavid Xu * because we are leaf code, we don't want to recursively call 94bc414752SDavid Xu * ourself. 95bc414752SDavid Xu */ 96bc414752SDavid Xu curthread->critical_count++; 97bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 98bc414752SDavid Xu while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 99bc414752SDavid Xu THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 100bc414752SDavid Xu curthread->cycle++; 101a091d823SDavid Xu cycle = curthread->cycle; 102bc414752SDavid Xu 103bc414752SDavid Xu /* Wake the thread suspending us. */ 104bc414752SDavid Xu _thr_umtx_wake(&curthread->cycle, INT_MAX); 105bc414752SDavid Xu 106bc414752SDavid Xu /* 107bc414752SDavid Xu * if we are from pthread_exit, we don't want to 108bc414752SDavid Xu * suspend, just go and die. 109bc414752SDavid Xu */ 110bc414752SDavid Xu if (curthread->state == PS_DEAD) 111bc414752SDavid Xu break; 112bc414752SDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED; 113bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 114a091d823SDavid Xu _thr_umtx_wait(&curthread->cycle, cycle, NULL); 115bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 116a091d823SDavid Xu curthread->flags &= ~THR_FLAGS_SUSPENDED; 117a091d823SDavid Xu } 118bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 119bc414752SDavid Xu curthread->critical_count--; 120bc414752SDavid Xu 121bc414752SDavid Xu /* 122bc414752SDavid Xu * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and 123bc414752SDavid Xu * a new signal frame will nest us, this seems a problem because 124bc414752SDavid Xu * stack will grow and overflow, but because kernel will automatically 125bc414752SDavid Xu * mask the SIGCANCEL when delivering the signal, so we at most only 126bc414752SDavid Xu * have one nesting signal frame, this should be fine. 127bc414752SDavid Xu */ 128a091d823SDavid Xu _thr_signal_unblock(curthread); 129d448272dSDavid Xu errno = err; 130a091d823SDavid Xu } 131a091d823SDavid Xu 132a091d823SDavid Xu void 133a091d823SDavid Xu _thr_signal_init(void) 134a091d823SDavid Xu { 135a091d823SDavid Xu struct sigaction act; 136a091d823SDavid Xu 137a091d823SDavid Xu /* Install cancel handler. */ 138a091d823SDavid Xu SIGEMPTYSET(act.sa_mask); 139a091d823SDavid Xu act.sa_flags = SA_SIGINFO | SA_RESTART; 140a091d823SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 141a091d823SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL); 142a091d823SDavid Xu } 143a091d823SDavid Xu 144a091d823SDavid Xu void 145a091d823SDavid Xu _thr_signal_deinit(void) 146a091d823SDavid Xu { 147a091d823SDavid Xu } 148a091d823SDavid Xu 14905c3a5eaSDavid Xu __weak_reference(___pause, pause); 15005c3a5eaSDavid Xu 15105c3a5eaSDavid Xu int 15205c3a5eaSDavid Xu ___pause(void) 15305c3a5eaSDavid Xu { 15405c3a5eaSDavid Xu struct pthread *curthread = _get_curthread(); 15505c3a5eaSDavid Xu int ret; 15605c3a5eaSDavid Xu 157f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 15805c3a5eaSDavid Xu ret = __pause(); 159f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 16005c3a5eaSDavid Xu 16105c3a5eaSDavid Xu return ret; 16205c3a5eaSDavid Xu } 16305c3a5eaSDavid Xu 16405c3a5eaSDavid Xu __weak_reference(_raise, raise); 16505c3a5eaSDavid Xu 16605c3a5eaSDavid Xu int 16705c3a5eaSDavid Xu _raise(int sig) 16805c3a5eaSDavid Xu { 16905c3a5eaSDavid Xu int ret; 17005c3a5eaSDavid Xu 17105c3a5eaSDavid Xu if (!_thr_isthreaded()) 17205c3a5eaSDavid Xu ret = kill(getpid(), sig); 17305c3a5eaSDavid Xu else 17405c3a5eaSDavid Xu ret = _thr_send_sig(_get_curthread(), sig); 17505c3a5eaSDavid Xu return (ret); 17605c3a5eaSDavid Xu } 17705c3a5eaSDavid Xu 178a091d823SDavid Xu __weak_reference(_sigaction, sigaction); 179a091d823SDavid Xu 180a091d823SDavid Xu int 181a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 182a091d823SDavid Xu { 183a091d823SDavid Xu /* Check if the signal number is out of range: */ 184a091d823SDavid Xu if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 185a091d823SDavid Xu /* Return an invalid argument: */ 186a091d823SDavid Xu errno = EINVAL; 187a091d823SDavid Xu return (-1); 188a091d823SDavid Xu } 189a091d823SDavid Xu 190a091d823SDavid Xu return __sys_sigaction(sig, act, oact); 191a091d823SDavid Xu } 192a091d823SDavid Xu 193a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask); 194a091d823SDavid Xu 195a091d823SDavid Xu int 196a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 197a091d823SDavid Xu { 198a091d823SDavid Xu const sigset_t *p = set; 199a091d823SDavid Xu sigset_t newset; 200a091d823SDavid Xu 201a091d823SDavid Xu if (how != SIG_UNBLOCK) { 202a091d823SDavid Xu if (set != NULL) { 203a091d823SDavid Xu newset = *set; 204a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 205a091d823SDavid Xu p = &newset; 206a091d823SDavid Xu } 207a091d823SDavid Xu } 208a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 209a091d823SDavid Xu } 210a091d823SDavid Xu 211bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask); 212bb535300SJeff Roberson 213bb535300SJeff Roberson int 214bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 215bb535300SJeff Roberson { 216a091d823SDavid Xu if (_sigprocmask(how, set, oset)) 217a091d823SDavid Xu return (errno); 218a091d823SDavid Xu return (0); 219bb535300SJeff Roberson } 220bb535300SJeff Roberson 22105c3a5eaSDavid Xu __weak_reference(__sigsuspend, sigsuspend); 222bb535300SJeff Roberson 223bb535300SJeff Roberson int 224a091d823SDavid Xu _sigsuspend(const sigset_t * set) 225bb535300SJeff Roberson { 22605c3a5eaSDavid Xu sigset_t newset; 22705c3a5eaSDavid Xu const sigset_t *pset; 22805c3a5eaSDavid Xu int ret; 22905c3a5eaSDavid Xu 23005c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 23105c3a5eaSDavid Xu newset = *set; 23205c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 23305c3a5eaSDavid Xu pset = &newset; 23405c3a5eaSDavid Xu } else 23505c3a5eaSDavid Xu pset = set; 23605c3a5eaSDavid Xu 23705c3a5eaSDavid Xu ret = __sys_sigsuspend(pset); 23805c3a5eaSDavid Xu 23905c3a5eaSDavid Xu return (ret); 24005c3a5eaSDavid Xu } 24105c3a5eaSDavid Xu 24205c3a5eaSDavid Xu int 24305c3a5eaSDavid Xu __sigsuspend(const sigset_t * set) 24405c3a5eaSDavid Xu { 245a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 246a091d823SDavid Xu sigset_t newset; 247a091d823SDavid Xu const sigset_t *pset; 248a091d823SDavid Xu int ret; 249bb535300SJeff Roberson 250a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 251a091d823SDavid Xu newset = *set; 252a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 253a091d823SDavid Xu pset = &newset; 254a091d823SDavid Xu } else 255a091d823SDavid Xu pset = set; 2560ad70ba9SMike Makonnen 257f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 258a091d823SDavid Xu ret = __sys_sigsuspend(pset); 259f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 2600ad70ba9SMike Makonnen 261a091d823SDavid Xu return (ret); 262a091d823SDavid Xu } 263a091d823SDavid Xu 264a091d823SDavid Xu __weak_reference(__sigwait, sigwait); 265a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait); 266a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo); 267a091d823SDavid Xu 268a091d823SDavid Xu int 26905c3a5eaSDavid Xu _sigtimedwait(const sigset_t *set, siginfo_t *info, 27005c3a5eaSDavid Xu const struct timespec * timeout) 27105c3a5eaSDavid Xu { 27205c3a5eaSDavid Xu sigset_t newset; 27305c3a5eaSDavid Xu const sigset_t *pset; 27405c3a5eaSDavid Xu int ret; 27505c3a5eaSDavid Xu 27605c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 27705c3a5eaSDavid Xu newset = *set; 27805c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 27905c3a5eaSDavid Xu pset = &newset; 28005c3a5eaSDavid Xu } else 28105c3a5eaSDavid Xu pset = set; 28205c3a5eaSDavid Xu ret = __sys_sigtimedwait(pset, info, timeout); 28305c3a5eaSDavid Xu return (ret); 28405c3a5eaSDavid Xu } 28505c3a5eaSDavid Xu 28605c3a5eaSDavid Xu int 287a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info, 288a091d823SDavid Xu const struct timespec * timeout) 289a091d823SDavid Xu { 290a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 291a091d823SDavid Xu sigset_t newset; 292a091d823SDavid Xu const sigset_t *pset; 293a091d823SDavid Xu int ret; 294a091d823SDavid Xu 295a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 296a091d823SDavid Xu newset = *set; 297a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 298a091d823SDavid Xu pset = &newset; 299a091d823SDavid Xu } else 300a091d823SDavid Xu pset = set; 301f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 302a091d823SDavid Xu ret = __sys_sigtimedwait(pset, info, timeout); 303f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 304a091d823SDavid Xu return (ret); 305a091d823SDavid Xu } 306a091d823SDavid Xu 307a091d823SDavid Xu int 30805c3a5eaSDavid Xu _sigwaitinfo(const sigset_t *set, siginfo_t *info) 30905c3a5eaSDavid Xu { 31005c3a5eaSDavid Xu sigset_t newset; 31105c3a5eaSDavid Xu const sigset_t *pset; 31205c3a5eaSDavid Xu int ret; 31305c3a5eaSDavid Xu 31405c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 31505c3a5eaSDavid Xu newset = *set; 31605c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 31705c3a5eaSDavid Xu pset = &newset; 31805c3a5eaSDavid Xu } else 31905c3a5eaSDavid Xu pset = set; 32005c3a5eaSDavid Xu 32105c3a5eaSDavid Xu ret = __sys_sigwaitinfo(pset, info); 32205c3a5eaSDavid Xu return (ret); 32305c3a5eaSDavid Xu } 32405c3a5eaSDavid Xu 32505c3a5eaSDavid Xu int 326a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info) 327a091d823SDavid Xu { 328a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 329a091d823SDavid Xu sigset_t newset; 330a091d823SDavid Xu const sigset_t *pset; 331a091d823SDavid Xu int ret; 332a091d823SDavid Xu 333a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 334a091d823SDavid Xu newset = *set; 335a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 336a091d823SDavid Xu pset = &newset; 337a091d823SDavid Xu } else 338a091d823SDavid Xu pset = set; 339a091d823SDavid Xu 340f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 341a091d823SDavid Xu ret = __sys_sigwaitinfo(pset, info); 342f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 343a091d823SDavid Xu return (ret); 344a091d823SDavid Xu } 345a091d823SDavid Xu 346a091d823SDavid Xu int 34705c3a5eaSDavid Xu _sigwait(const sigset_t *set, int *sig) 34805c3a5eaSDavid Xu { 34905c3a5eaSDavid Xu sigset_t newset; 35005c3a5eaSDavid Xu const sigset_t *pset; 35105c3a5eaSDavid Xu int ret; 35205c3a5eaSDavid Xu 35305c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 35405c3a5eaSDavid Xu newset = *set; 35505c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 35605c3a5eaSDavid Xu pset = &newset; 35705c3a5eaSDavid Xu } else 35805c3a5eaSDavid Xu pset = set; 35905c3a5eaSDavid Xu 36005c3a5eaSDavid Xu ret = __sys_sigwait(pset, sig); 36105c3a5eaSDavid Xu return (ret); 36205c3a5eaSDavid Xu } 36305c3a5eaSDavid Xu 36405c3a5eaSDavid Xu int 365a091d823SDavid Xu __sigwait(const sigset_t *set, int *sig) 366a091d823SDavid Xu { 367a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 368a091d823SDavid Xu sigset_t newset; 369a091d823SDavid Xu const sigset_t *pset; 370a091d823SDavid Xu int ret; 371a091d823SDavid Xu 372a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 373a091d823SDavid Xu newset = *set; 374a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 375a091d823SDavid Xu pset = &newset; 376a091d823SDavid Xu } else 377a091d823SDavid Xu pset = set; 378a091d823SDavid Xu 379f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 380a091d823SDavid Xu ret = __sys_sigwait(pset, sig); 381f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 382a091d823SDavid Xu return (ret); 383bb535300SJeff Roberson } 384