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); 55922d56f9SDavid Xu int _sigtimedwait(const sigset_t *set, siginfo_t *info, 56922d56f9SDavid Xu const struct timespec * timeout); 5737a6356bSDavid Xu int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 58922d56f9SDavid Xu int _sigwaitinfo(const sigset_t *set, siginfo_t *info); 5937a6356bSDavid Xu int __sigwait(const sigset_t *set, int *sig); 60922d56f9SDavid Xu int _sigwait(const sigset_t *set, int *sig); 61922d56f9SDavid Xu int __sigsuspend(const sigset_t *sigmask); 6237a6356bSDavid Xu 636fdfcacbSDavid Xu 64a091d823SDavid Xu static void 6537a6356bSDavid Xu sigcancel_handler(int sig __unused, 6637a6356bSDavid Xu siginfo_t *info __unused, ucontext_t *ucp __unused) 67a091d823SDavid Xu { 68a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 69a091d823SDavid Xu 70b774466bSDavid Xu if (curthread->cancel_defer && curthread->cancel_pending) 712bd2c907SDavid Xu thr_wake(curthread->tid); 72bc414752SDavid Xu _thr_ast(curthread); 73bc414752SDavid Xu } 74bc414752SDavid Xu 75bc414752SDavid Xu void 76bc414752SDavid Xu _thr_ast(struct pthread *curthread) 77bc414752SDavid Xu { 78bc414752SDavid Xu if (!THR_IN_CRITICAL(curthread)) { 79f08e1bf6SDavid Xu _thr_testcancel(curthread); 80bc414752SDavid Xu if (__predict_false((curthread->flags & 81bc414752SDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 82bc414752SDavid Xu == THR_FLAGS_NEED_SUSPEND)) 83a091d823SDavid Xu _thr_suspend_check(curthread); 84a091d823SDavid Xu } 85a091d823SDavid Xu } 86a091d823SDavid Xu 87a091d823SDavid Xu void 88a091d823SDavid Xu _thr_suspend_check(struct pthread *curthread) 89a091d823SDavid Xu { 906fdfcacbSDavid Xu long cycle; 91d448272dSDavid Xu int err; 92a091d823SDavid Xu 93d448272dSDavid Xu err = errno; 94bc414752SDavid Xu /* 95bc414752SDavid Xu * Blocks SIGCANCEL which other threads must send. 96bc414752SDavid Xu */ 97a091d823SDavid Xu _thr_signal_block(curthread); 98bc414752SDavid Xu 99bc414752SDavid Xu /* 100bc414752SDavid Xu * Increase critical_count, here we don't use THR_LOCK/UNLOCK 101bc414752SDavid Xu * because we are leaf code, we don't want to recursively call 102bc414752SDavid Xu * ourself. 103bc414752SDavid Xu */ 104bc414752SDavid Xu curthread->critical_count++; 105bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 106bc414752SDavid Xu while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 107bc414752SDavid Xu THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 108bc414752SDavid Xu curthread->cycle++; 109a091d823SDavid Xu cycle = curthread->cycle; 110bc414752SDavid Xu 111bc414752SDavid Xu /* Wake the thread suspending us. */ 112bc414752SDavid Xu _thr_umtx_wake(&curthread->cycle, INT_MAX); 113bc414752SDavid Xu 114bc414752SDavid Xu /* 115bc414752SDavid Xu * if we are from pthread_exit, we don't want to 116bc414752SDavid Xu * suspend, just go and die. 117bc414752SDavid Xu */ 118bc414752SDavid Xu if (curthread->state == PS_DEAD) 119bc414752SDavid Xu break; 120bc414752SDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED; 121bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 122a091d823SDavid Xu _thr_umtx_wait(&curthread->cycle, cycle, NULL); 123bddd24cdSDavid Xu THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 124a091d823SDavid Xu curthread->flags &= ~THR_FLAGS_SUSPENDED; 125a091d823SDavid Xu } 126bddd24cdSDavid Xu THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 127bc414752SDavid Xu curthread->critical_count--; 128bc414752SDavid Xu 129bc414752SDavid Xu /* 130bc414752SDavid Xu * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and 131bc414752SDavid Xu * a new signal frame will nest us, this seems a problem because 132bc414752SDavid Xu * stack will grow and overflow, but because kernel will automatically 133bc414752SDavid Xu * mask the SIGCANCEL when delivering the signal, so we at most only 134bc414752SDavid Xu * have one nesting signal frame, this should be fine. 135bc414752SDavid Xu */ 136a091d823SDavid Xu _thr_signal_unblock(curthread); 137d448272dSDavid Xu errno = err; 138a091d823SDavid Xu } 139a091d823SDavid Xu 140a091d823SDavid Xu void 141a091d823SDavid Xu _thr_signal_init(void) 142a091d823SDavid Xu { 143a091d823SDavid Xu struct sigaction act; 144a091d823SDavid Xu 145a091d823SDavid Xu /* Install cancel handler. */ 146a091d823SDavid Xu SIGEMPTYSET(act.sa_mask); 147a091d823SDavid Xu act.sa_flags = SA_SIGINFO | SA_RESTART; 148a091d823SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 149a091d823SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL); 150a091d823SDavid Xu } 151a091d823SDavid Xu 152a091d823SDavid Xu void 153a091d823SDavid Xu _thr_signal_deinit(void) 154a091d823SDavid Xu { 155a091d823SDavid Xu } 156a091d823SDavid Xu 15705c3a5eaSDavid Xu __weak_reference(___pause, pause); 15805c3a5eaSDavid Xu 15905c3a5eaSDavid Xu int 16005c3a5eaSDavid Xu ___pause(void) 16105c3a5eaSDavid Xu { 16205c3a5eaSDavid Xu struct pthread *curthread = _get_curthread(); 16305c3a5eaSDavid Xu int ret; 16405c3a5eaSDavid Xu 165f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 16605c3a5eaSDavid Xu ret = __pause(); 167f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 16805c3a5eaSDavid Xu 16905c3a5eaSDavid Xu return ret; 17005c3a5eaSDavid Xu } 17105c3a5eaSDavid Xu 17205c3a5eaSDavid Xu __weak_reference(_raise, raise); 17305c3a5eaSDavid Xu 17405c3a5eaSDavid Xu int 17505c3a5eaSDavid Xu _raise(int sig) 17605c3a5eaSDavid Xu { 17705c3a5eaSDavid Xu int ret; 17805c3a5eaSDavid Xu 17905c3a5eaSDavid Xu if (!_thr_isthreaded()) 18005c3a5eaSDavid Xu ret = kill(getpid(), sig); 18105c3a5eaSDavid Xu else 18205c3a5eaSDavid Xu ret = _thr_send_sig(_get_curthread(), sig); 18305c3a5eaSDavid Xu return (ret); 18405c3a5eaSDavid Xu } 18505c3a5eaSDavid Xu 186a091d823SDavid Xu __weak_reference(_sigaction, sigaction); 187a091d823SDavid Xu 188a091d823SDavid Xu int 189a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 190a091d823SDavid Xu { 191a091d823SDavid Xu /* Check if the signal number is out of range: */ 192a091d823SDavid Xu if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 193a091d823SDavid Xu /* Return an invalid argument: */ 194a091d823SDavid Xu errno = EINVAL; 195a091d823SDavid Xu return (-1); 196a091d823SDavid Xu } 197a091d823SDavid Xu 198a091d823SDavid Xu return __sys_sigaction(sig, act, oact); 199a091d823SDavid Xu } 200a091d823SDavid Xu 201a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask); 202a091d823SDavid Xu 203a091d823SDavid Xu int 204a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 205a091d823SDavid Xu { 206a091d823SDavid Xu const sigset_t *p = set; 207a091d823SDavid Xu sigset_t newset; 208a091d823SDavid Xu 209a091d823SDavid Xu if (how != SIG_UNBLOCK) { 210a091d823SDavid Xu if (set != NULL) { 211a091d823SDavid Xu newset = *set; 212a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 213a091d823SDavid Xu p = &newset; 214a091d823SDavid Xu } 215a091d823SDavid Xu } 216a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 217a091d823SDavid Xu } 218a091d823SDavid Xu 219bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask); 220bb535300SJeff Roberson 221bb535300SJeff Roberson int 222bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 223bb535300SJeff Roberson { 224a091d823SDavid Xu if (_sigprocmask(how, set, oset)) 225a091d823SDavid Xu return (errno); 226a091d823SDavid Xu return (0); 227bb535300SJeff Roberson } 228bb535300SJeff Roberson 22905c3a5eaSDavid Xu __weak_reference(__sigsuspend, sigsuspend); 230bb535300SJeff Roberson 231bb535300SJeff Roberson int 232a091d823SDavid Xu _sigsuspend(const sigset_t * set) 233bb535300SJeff Roberson { 23405c3a5eaSDavid Xu sigset_t newset; 23505c3a5eaSDavid Xu const sigset_t *pset; 23605c3a5eaSDavid Xu int ret; 23705c3a5eaSDavid Xu 23805c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 23905c3a5eaSDavid Xu newset = *set; 24005c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 24105c3a5eaSDavid Xu pset = &newset; 24205c3a5eaSDavid Xu } else 24305c3a5eaSDavid Xu pset = set; 24405c3a5eaSDavid Xu 24505c3a5eaSDavid Xu ret = __sys_sigsuspend(pset); 24605c3a5eaSDavid Xu 24705c3a5eaSDavid Xu return (ret); 24805c3a5eaSDavid Xu } 24905c3a5eaSDavid Xu 25005c3a5eaSDavid Xu int 25105c3a5eaSDavid Xu __sigsuspend(const sigset_t * set) 25205c3a5eaSDavid Xu { 253a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 254a091d823SDavid Xu sigset_t newset; 255a091d823SDavid Xu const sigset_t *pset; 256a091d823SDavid Xu int ret; 257bb535300SJeff Roberson 258a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 259a091d823SDavid Xu newset = *set; 260a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 261a091d823SDavid Xu pset = &newset; 262a091d823SDavid Xu } else 263a091d823SDavid Xu pset = set; 2640ad70ba9SMike Makonnen 265f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 266a091d823SDavid Xu ret = __sys_sigsuspend(pset); 267f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 2680ad70ba9SMike Makonnen 269a091d823SDavid Xu return (ret); 270a091d823SDavid Xu } 271a091d823SDavid Xu 272a091d823SDavid Xu __weak_reference(__sigwait, sigwait); 273a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait); 274a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo); 275a091d823SDavid Xu 276a091d823SDavid Xu int 27705c3a5eaSDavid Xu _sigtimedwait(const sigset_t *set, siginfo_t *info, 27805c3a5eaSDavid Xu const struct timespec * timeout) 27905c3a5eaSDavid Xu { 28005c3a5eaSDavid Xu sigset_t newset; 28105c3a5eaSDavid Xu const sigset_t *pset; 28205c3a5eaSDavid Xu int ret; 28305c3a5eaSDavid Xu 28405c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 28505c3a5eaSDavid Xu newset = *set; 28605c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 28705c3a5eaSDavid Xu pset = &newset; 28805c3a5eaSDavid Xu } else 28905c3a5eaSDavid Xu pset = set; 29005c3a5eaSDavid Xu ret = __sys_sigtimedwait(pset, info, timeout); 29105c3a5eaSDavid Xu return (ret); 29205c3a5eaSDavid Xu } 29305c3a5eaSDavid Xu 29405c3a5eaSDavid Xu int 295a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info, 296a091d823SDavid Xu const struct timespec * timeout) 297a091d823SDavid Xu { 298a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 299a091d823SDavid Xu sigset_t newset; 300a091d823SDavid Xu const sigset_t *pset; 301a091d823SDavid Xu int ret; 302a091d823SDavid Xu 303a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 304a091d823SDavid Xu newset = *set; 305a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 306a091d823SDavid Xu pset = &newset; 307a091d823SDavid Xu } else 308a091d823SDavid Xu pset = set; 309f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 310a091d823SDavid Xu ret = __sys_sigtimedwait(pset, info, timeout); 311f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 312a091d823SDavid Xu return (ret); 313a091d823SDavid Xu } 314a091d823SDavid Xu 315a091d823SDavid Xu int 31605c3a5eaSDavid Xu _sigwaitinfo(const sigset_t *set, siginfo_t *info) 31705c3a5eaSDavid Xu { 31805c3a5eaSDavid Xu sigset_t newset; 31905c3a5eaSDavid Xu const sigset_t *pset; 32005c3a5eaSDavid Xu int ret; 32105c3a5eaSDavid Xu 32205c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 32305c3a5eaSDavid Xu newset = *set; 32405c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 32505c3a5eaSDavid Xu pset = &newset; 32605c3a5eaSDavid Xu } else 32705c3a5eaSDavid Xu pset = set; 32805c3a5eaSDavid Xu 32905c3a5eaSDavid Xu ret = __sys_sigwaitinfo(pset, info); 33005c3a5eaSDavid Xu return (ret); 33105c3a5eaSDavid Xu } 33205c3a5eaSDavid Xu 33305c3a5eaSDavid Xu int 334a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info) 335a091d823SDavid Xu { 336a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 337a091d823SDavid Xu sigset_t newset; 338a091d823SDavid Xu const sigset_t *pset; 339a091d823SDavid Xu int ret; 340a091d823SDavid Xu 341a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 342a091d823SDavid Xu newset = *set; 343a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 344a091d823SDavid Xu pset = &newset; 345a091d823SDavid Xu } else 346a091d823SDavid Xu pset = set; 347a091d823SDavid Xu 348f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 349a091d823SDavid Xu ret = __sys_sigwaitinfo(pset, info); 350f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 351a091d823SDavid Xu return (ret); 352a091d823SDavid Xu } 353a091d823SDavid Xu 354a091d823SDavid Xu int 35505c3a5eaSDavid Xu _sigwait(const sigset_t *set, int *sig) 35605c3a5eaSDavid Xu { 35705c3a5eaSDavid Xu sigset_t newset; 35805c3a5eaSDavid Xu const sigset_t *pset; 35905c3a5eaSDavid Xu int ret; 36005c3a5eaSDavid Xu 36105c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 36205c3a5eaSDavid Xu newset = *set; 36305c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 36405c3a5eaSDavid Xu pset = &newset; 36505c3a5eaSDavid Xu } else 36605c3a5eaSDavid Xu pset = set; 36705c3a5eaSDavid Xu 36805c3a5eaSDavid Xu ret = __sys_sigwait(pset, sig); 36905c3a5eaSDavid Xu return (ret); 37005c3a5eaSDavid Xu } 37105c3a5eaSDavid Xu 37205c3a5eaSDavid Xu int 373a091d823SDavid Xu __sigwait(const sigset_t *set, int *sig) 374a091d823SDavid Xu { 375a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 376a091d823SDavid Xu sigset_t newset; 377a091d823SDavid Xu const sigset_t *pset; 378a091d823SDavid Xu int ret; 379a091d823SDavid Xu 380a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 381a091d823SDavid Xu newset = *set; 382a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 383a091d823SDavid Xu pset = &newset; 384a091d823SDavid Xu } else 385a091d823SDavid Xu pset = set; 386a091d823SDavid Xu 387f08e1bf6SDavid Xu _thr_cancel_enter(curthread); 388a091d823SDavid Xu ret = __sys_sigwait(pset, sig); 389f08e1bf6SDavid Xu _thr_cancel_leave(curthread); 390a091d823SDavid Xu return (ret); 391bb535300SJeff Roberson } 392