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)) { 71d448272dSDavid Xu if (__predict_false( 72d448272dSDavid Xu SHOULD_ASYNC_CANCEL(curthread->cancelflags))) 73b6b894f6SDavid Xu _pthread_testcancel(); 74bc414752SDavid Xu if (__predict_false((curthread->flags & 75bc414752SDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 76bc414752SDavid Xu == THR_FLAGS_NEED_SUSPEND)) 77a091d823SDavid Xu _thr_suspend_check(curthread); 78a091d823SDavid Xu } 79a091d823SDavid Xu } 80a091d823SDavid Xu 81a091d823SDavid Xu void 82a091d823SDavid Xu _thr_suspend_check(struct pthread *curthread) 83a091d823SDavid Xu { 84bc414752SDavid Xu umtx_t cycle; 85d448272dSDavid Xu int err; 86a091d823SDavid Xu 87d448272dSDavid Xu err = errno; 88bc414752SDavid Xu /* 89bc414752SDavid Xu * Blocks SIGCANCEL which other threads must send. 90bc414752SDavid Xu */ 91a091d823SDavid Xu _thr_signal_block(curthread); 92bc414752SDavid Xu 93bc414752SDavid Xu /* 94bc414752SDavid Xu * Increase critical_count, here we don't use THR_LOCK/UNLOCK 95bc414752SDavid Xu * because we are leaf code, we don't want to recursively call 96bc414752SDavid Xu * ourself. 97bc414752SDavid Xu */ 98bc414752SDavid Xu curthread->critical_count++; 99bc414752SDavid Xu THR_UMTX_LOCK(curthread, &(curthread)->lock); 100bc414752SDavid Xu while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 101bc414752SDavid Xu THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 102bc414752SDavid Xu curthread->cycle++; 103a091d823SDavid Xu cycle = curthread->cycle; 104bc414752SDavid Xu 105bc414752SDavid Xu /* Wake the thread suspending us. */ 106bc414752SDavid Xu _thr_umtx_wake(&curthread->cycle, INT_MAX); 107bc414752SDavid Xu 108bc414752SDavid Xu /* 109bc414752SDavid Xu * if we are from pthread_exit, we don't want to 110bc414752SDavid Xu * suspend, just go and die. 111bc414752SDavid Xu */ 112bc414752SDavid Xu if (curthread->state == PS_DEAD) 113bc414752SDavid Xu break; 114bc414752SDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED; 115bc414752SDavid Xu THR_UMTX_UNLOCK(curthread, &(curthread)->lock); 116a091d823SDavid Xu _thr_umtx_wait(&curthread->cycle, cycle, NULL); 117bc414752SDavid Xu THR_UMTX_LOCK(curthread, &(curthread)->lock); 118a091d823SDavid Xu curthread->flags &= ~THR_FLAGS_SUSPENDED; 119a091d823SDavid Xu } 120bc414752SDavid Xu THR_UMTX_UNLOCK(curthread, &(curthread)->lock); 121bc414752SDavid Xu curthread->critical_count--; 122bc414752SDavid Xu 123bc414752SDavid Xu /* 124bc414752SDavid Xu * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and 125bc414752SDavid Xu * a new signal frame will nest us, this seems a problem because 126bc414752SDavid Xu * stack will grow and overflow, but because kernel will automatically 127bc414752SDavid Xu * mask the SIGCANCEL when delivering the signal, so we at most only 128bc414752SDavid Xu * have one nesting signal frame, this should be fine. 129bc414752SDavid Xu */ 130a091d823SDavid Xu _thr_signal_unblock(curthread); 131d448272dSDavid Xu errno = err; 132a091d823SDavid Xu } 133a091d823SDavid Xu 134a091d823SDavid Xu void 135a091d823SDavid Xu _thr_signal_init(void) 136a091d823SDavid Xu { 137a091d823SDavid Xu struct sigaction act; 138a091d823SDavid Xu 139a091d823SDavid Xu /* Install cancel handler. */ 140a091d823SDavid Xu SIGEMPTYSET(act.sa_mask); 141a091d823SDavid Xu act.sa_flags = SA_SIGINFO | SA_RESTART; 142a091d823SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 143a091d823SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL); 144a091d823SDavid Xu } 145a091d823SDavid Xu 146a091d823SDavid Xu void 147a091d823SDavid Xu _thr_signal_deinit(void) 148a091d823SDavid Xu { 149a091d823SDavid Xu } 150a091d823SDavid Xu 15105c3a5eaSDavid Xu __weak_reference(___pause, pause); 15205c3a5eaSDavid Xu 15305c3a5eaSDavid Xu int 15405c3a5eaSDavid Xu ___pause(void) 15505c3a5eaSDavid Xu { 15605c3a5eaSDavid Xu struct pthread *curthread = _get_curthread(); 15705c3a5eaSDavid Xu int oldcancel; 15805c3a5eaSDavid Xu int ret; 15905c3a5eaSDavid Xu 16005c3a5eaSDavid Xu oldcancel = _thr_cancel_enter(curthread); 16105c3a5eaSDavid Xu ret = __pause(); 16205c3a5eaSDavid Xu _thr_cancel_leave(curthread, oldcancel); 16305c3a5eaSDavid Xu 16405c3a5eaSDavid Xu return ret; 16505c3a5eaSDavid Xu } 16605c3a5eaSDavid Xu 16705c3a5eaSDavid Xu __weak_reference(_raise, raise); 16805c3a5eaSDavid Xu 16905c3a5eaSDavid Xu int 17005c3a5eaSDavid Xu _raise(int sig) 17105c3a5eaSDavid Xu { 17205c3a5eaSDavid Xu int ret; 17305c3a5eaSDavid Xu 17405c3a5eaSDavid Xu if (!_thr_isthreaded()) 17505c3a5eaSDavid Xu ret = kill(getpid(), sig); 17605c3a5eaSDavid Xu else 17705c3a5eaSDavid Xu ret = _thr_send_sig(_get_curthread(), sig); 17805c3a5eaSDavid Xu return (ret); 17905c3a5eaSDavid Xu } 18005c3a5eaSDavid Xu 181a091d823SDavid Xu __weak_reference(_sigaction, sigaction); 182a091d823SDavid Xu 183a091d823SDavid Xu int 184a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 185a091d823SDavid Xu { 186a091d823SDavid Xu /* Check if the signal number is out of range: */ 187a091d823SDavid Xu if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 188a091d823SDavid Xu /* Return an invalid argument: */ 189a091d823SDavid Xu errno = EINVAL; 190a091d823SDavid Xu return (-1); 191a091d823SDavid Xu } 192a091d823SDavid Xu 193a091d823SDavid Xu return __sys_sigaction(sig, act, oact); 194a091d823SDavid Xu } 195a091d823SDavid Xu 196a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask); 197a091d823SDavid Xu 198a091d823SDavid Xu int 199a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 200a091d823SDavid Xu { 201a091d823SDavid Xu const sigset_t *p = set; 202a091d823SDavid Xu sigset_t newset; 203a091d823SDavid Xu 204a091d823SDavid Xu if (how != SIG_UNBLOCK) { 205a091d823SDavid Xu if (set != NULL) { 206a091d823SDavid Xu newset = *set; 207a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 208a091d823SDavid Xu p = &newset; 209a091d823SDavid Xu } 210a091d823SDavid Xu } 211a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 212a091d823SDavid Xu } 213a091d823SDavid Xu 214bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask); 215bb535300SJeff Roberson 216bb535300SJeff Roberson int 217bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 218bb535300SJeff Roberson { 219a091d823SDavid Xu if (_sigprocmask(how, set, oset)) 220a091d823SDavid Xu return (errno); 221a091d823SDavid Xu return (0); 222bb535300SJeff Roberson } 223bb535300SJeff Roberson 22405c3a5eaSDavid Xu __weak_reference(__sigsuspend, sigsuspend); 225bb535300SJeff Roberson 226bb535300SJeff Roberson int 227a091d823SDavid Xu _sigsuspend(const sigset_t * set) 228bb535300SJeff Roberson { 22905c3a5eaSDavid Xu sigset_t newset; 23005c3a5eaSDavid Xu const sigset_t *pset; 23105c3a5eaSDavid Xu int ret; 23205c3a5eaSDavid Xu 23305c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 23405c3a5eaSDavid Xu newset = *set; 23505c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 23605c3a5eaSDavid Xu pset = &newset; 23705c3a5eaSDavid Xu } else 23805c3a5eaSDavid Xu pset = set; 23905c3a5eaSDavid Xu 24005c3a5eaSDavid Xu ret = __sys_sigsuspend(pset); 24105c3a5eaSDavid Xu 24205c3a5eaSDavid Xu return (ret); 24305c3a5eaSDavid Xu } 24405c3a5eaSDavid Xu 24505c3a5eaSDavid Xu int 24605c3a5eaSDavid Xu __sigsuspend(const sigset_t * set) 24705c3a5eaSDavid Xu { 248a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 249a091d823SDavid Xu sigset_t newset; 250a091d823SDavid Xu const sigset_t *pset; 251a091d823SDavid Xu int oldcancel; 252a091d823SDavid Xu int ret; 253bb535300SJeff Roberson 254a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 255a091d823SDavid Xu newset = *set; 256a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 257a091d823SDavid Xu pset = &newset; 258a091d823SDavid Xu } else 259a091d823SDavid Xu pset = set; 2600ad70ba9SMike Makonnen 261a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 262a091d823SDavid Xu ret = __sys_sigsuspend(pset); 263a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 2640ad70ba9SMike Makonnen 265a091d823SDavid Xu return (ret); 266a091d823SDavid Xu } 267a091d823SDavid Xu 268a091d823SDavid Xu __weak_reference(__sigwait, sigwait); 269a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait); 270a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo); 271a091d823SDavid Xu 272a091d823SDavid Xu int 27305c3a5eaSDavid Xu _sigtimedwait(const sigset_t *set, siginfo_t *info, 27405c3a5eaSDavid Xu const struct timespec * timeout) 27505c3a5eaSDavid Xu { 27605c3a5eaSDavid Xu sigset_t newset; 27705c3a5eaSDavid Xu const sigset_t *pset; 27805c3a5eaSDavid Xu int ret; 27905c3a5eaSDavid Xu 28005c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 28105c3a5eaSDavid Xu newset = *set; 28205c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 28305c3a5eaSDavid Xu pset = &newset; 28405c3a5eaSDavid Xu } else 28505c3a5eaSDavid Xu pset = set; 28605c3a5eaSDavid Xu ret = __sys_sigtimedwait(pset, info, timeout); 28705c3a5eaSDavid Xu return (ret); 28805c3a5eaSDavid Xu } 28905c3a5eaSDavid Xu 29005c3a5eaSDavid Xu int 291a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info, 292a091d823SDavid Xu const struct timespec * timeout) 293a091d823SDavid Xu { 294a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 295a091d823SDavid Xu sigset_t newset; 296a091d823SDavid Xu const sigset_t *pset; 297a091d823SDavid Xu int oldcancel; 298a091d823SDavid Xu int ret; 299a091d823SDavid Xu 300a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 301a091d823SDavid Xu newset = *set; 302a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 303a091d823SDavid Xu pset = &newset; 304a091d823SDavid Xu } else 305a091d823SDavid Xu pset = set; 306a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 307a091d823SDavid Xu ret = __sys_sigtimedwait(pset, info, timeout); 308a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 309a091d823SDavid Xu return (ret); 310a091d823SDavid Xu } 311a091d823SDavid Xu 312a091d823SDavid Xu int 31305c3a5eaSDavid Xu _sigwaitinfo(const sigset_t *set, siginfo_t *info) 31405c3a5eaSDavid Xu { 31505c3a5eaSDavid Xu sigset_t newset; 31605c3a5eaSDavid Xu const sigset_t *pset; 31705c3a5eaSDavid Xu int ret; 31805c3a5eaSDavid Xu 31905c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 32005c3a5eaSDavid Xu newset = *set; 32105c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 32205c3a5eaSDavid Xu pset = &newset; 32305c3a5eaSDavid Xu } else 32405c3a5eaSDavid Xu pset = set; 32505c3a5eaSDavid Xu 32605c3a5eaSDavid Xu ret = __sys_sigwaitinfo(pset, info); 32705c3a5eaSDavid Xu return (ret); 32805c3a5eaSDavid Xu } 32905c3a5eaSDavid Xu 33005c3a5eaSDavid Xu int 331a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info) 332a091d823SDavid Xu { 333a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 334a091d823SDavid Xu sigset_t newset; 335a091d823SDavid Xu const sigset_t *pset; 336a091d823SDavid Xu int oldcancel; 337a091d823SDavid Xu int ret; 338a091d823SDavid Xu 339a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 340a091d823SDavid Xu newset = *set; 341a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 342a091d823SDavid Xu pset = &newset; 343a091d823SDavid Xu } else 344a091d823SDavid Xu pset = set; 345a091d823SDavid Xu 346a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 347a091d823SDavid Xu ret = __sys_sigwaitinfo(pset, info); 348a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 349a091d823SDavid Xu return (ret); 350a091d823SDavid Xu } 351a091d823SDavid Xu 352a091d823SDavid Xu int 35305c3a5eaSDavid Xu _sigwait(const sigset_t *set, int *sig) 35405c3a5eaSDavid Xu { 35505c3a5eaSDavid Xu sigset_t newset; 35605c3a5eaSDavid Xu const sigset_t *pset; 35705c3a5eaSDavid Xu int ret; 35805c3a5eaSDavid Xu 35905c3a5eaSDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 36005c3a5eaSDavid Xu newset = *set; 36105c3a5eaSDavid Xu SIGDELSET(newset, SIGCANCEL); 36205c3a5eaSDavid Xu pset = &newset; 36305c3a5eaSDavid Xu } else 36405c3a5eaSDavid Xu pset = set; 36505c3a5eaSDavid Xu 36605c3a5eaSDavid Xu ret = __sys_sigwait(pset, sig); 36705c3a5eaSDavid Xu return (ret); 36805c3a5eaSDavid Xu } 36905c3a5eaSDavid Xu 37005c3a5eaSDavid Xu int 371a091d823SDavid Xu __sigwait(const sigset_t *set, int *sig) 372a091d823SDavid Xu { 373a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 374a091d823SDavid Xu sigset_t newset; 375a091d823SDavid Xu const sigset_t *pset; 376a091d823SDavid Xu int oldcancel; 377a091d823SDavid Xu int ret; 378a091d823SDavid Xu 379a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 380a091d823SDavid Xu newset = *set; 381a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 382a091d823SDavid Xu pset = &newset; 383a091d823SDavid Xu } else 384a091d823SDavid Xu pset = set; 385a091d823SDavid Xu 386a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 387a091d823SDavid Xu ret = __sys_sigwait(pset, sig); 388a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 389a091d823SDavid Xu return (ret); 390bb535300SJeff Roberson } 391