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 5037a6356bSDavid Xu int __sigtimedwait(const sigset_t *set, siginfo_t *info, 5137a6356bSDavid Xu const struct timespec * timeout); 5237a6356bSDavid Xu int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 5337a6356bSDavid Xu int __sigwait(const sigset_t *set, int *sig); 5437a6356bSDavid Xu 55a091d823SDavid Xu static void 5637a6356bSDavid Xu sigcancel_handler(int sig __unused, 5737a6356bSDavid Xu siginfo_t *info __unused, ucontext_t *ucp __unused) 58a091d823SDavid Xu { 59a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 60a091d823SDavid Xu 61bc414752SDavid Xu _thr_ast(curthread); 62bc414752SDavid Xu } 63bc414752SDavid Xu 64bc414752SDavid Xu void 65bc414752SDavid Xu _thr_ast(struct pthread *curthread) 66bc414752SDavid Xu { 67bc414752SDavid Xu if (!THR_IN_CRITICAL(curthread)) { 68d448272dSDavid Xu if (__predict_false( 69d448272dSDavid Xu SHOULD_ASYNC_CANCEL(curthread->cancelflags))) 70b6b894f6SDavid Xu _pthread_testcancel(); 71bc414752SDavid Xu if (__predict_false((curthread->flags & 72bc414752SDavid Xu (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 73bc414752SDavid Xu == THR_FLAGS_NEED_SUSPEND)) 74a091d823SDavid Xu _thr_suspend_check(curthread); 75a091d823SDavid Xu } 76a091d823SDavid Xu } 77a091d823SDavid Xu 78a091d823SDavid Xu void 79a091d823SDavid Xu _thr_suspend_check(struct pthread *curthread) 80a091d823SDavid Xu { 81bc414752SDavid Xu umtx_t cycle; 82d448272dSDavid Xu int err; 83a091d823SDavid Xu 84d448272dSDavid Xu err = errno; 85bc414752SDavid Xu /* 86bc414752SDavid Xu * Blocks SIGCANCEL which other threads must send. 87bc414752SDavid Xu */ 88a091d823SDavid Xu _thr_signal_block(curthread); 89bc414752SDavid Xu 90bc414752SDavid Xu /* 91bc414752SDavid Xu * Increase critical_count, here we don't use THR_LOCK/UNLOCK 92bc414752SDavid Xu * because we are leaf code, we don't want to recursively call 93bc414752SDavid Xu * ourself. 94bc414752SDavid Xu */ 95bc414752SDavid Xu curthread->critical_count++; 96bc414752SDavid Xu THR_UMTX_LOCK(curthread, &(curthread)->lock); 97bc414752SDavid Xu while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 98bc414752SDavid Xu THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 99bc414752SDavid Xu curthread->cycle++; 100a091d823SDavid Xu cycle = curthread->cycle; 101bc414752SDavid Xu 102bc414752SDavid Xu /* Wake the thread suspending us. */ 103bc414752SDavid Xu _thr_umtx_wake(&curthread->cycle, INT_MAX); 104bc414752SDavid Xu 105bc414752SDavid Xu /* 106bc414752SDavid Xu * if we are from pthread_exit, we don't want to 107bc414752SDavid Xu * suspend, just go and die. 108bc414752SDavid Xu */ 109bc414752SDavid Xu if (curthread->state == PS_DEAD) 110bc414752SDavid Xu break; 111bc414752SDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED; 112bc414752SDavid Xu THR_UMTX_UNLOCK(curthread, &(curthread)->lock); 113a091d823SDavid Xu _thr_umtx_wait(&curthread->cycle, cycle, NULL); 114bc414752SDavid Xu THR_UMTX_LOCK(curthread, &(curthread)->lock); 115a091d823SDavid Xu curthread->flags &= ~THR_FLAGS_SUSPENDED; 116a091d823SDavid Xu } 117bc414752SDavid Xu THR_UMTX_UNLOCK(curthread, &(curthread)->lock); 118bc414752SDavid Xu curthread->critical_count--; 119bc414752SDavid Xu 120bc414752SDavid Xu /* 121bc414752SDavid Xu * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and 122bc414752SDavid Xu * a new signal frame will nest us, this seems a problem because 123bc414752SDavid Xu * stack will grow and overflow, but because kernel will automatically 124bc414752SDavid Xu * mask the SIGCANCEL when delivering the signal, so we at most only 125bc414752SDavid Xu * have one nesting signal frame, this should be fine. 126bc414752SDavid Xu */ 127a091d823SDavid Xu _thr_signal_unblock(curthread); 128d448272dSDavid Xu errno = err; 129a091d823SDavid Xu } 130a091d823SDavid Xu 131a091d823SDavid Xu void 132a091d823SDavid Xu _thr_signal_init(void) 133a091d823SDavid Xu { 134a091d823SDavid Xu struct sigaction act; 135a091d823SDavid Xu 136a091d823SDavid Xu /* Install cancel handler. */ 137a091d823SDavid Xu SIGEMPTYSET(act.sa_mask); 138a091d823SDavid Xu act.sa_flags = SA_SIGINFO | SA_RESTART; 139a091d823SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 140a091d823SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL); 141a091d823SDavid Xu } 142a091d823SDavid Xu 143a091d823SDavid Xu void 144a091d823SDavid Xu _thr_signal_deinit(void) 145a091d823SDavid Xu { 146a091d823SDavid Xu } 147a091d823SDavid Xu 148a091d823SDavid Xu __weak_reference(_sigaction, sigaction); 149a091d823SDavid Xu 150a091d823SDavid Xu int 151a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 152a091d823SDavid Xu { 153a091d823SDavid Xu /* Check if the signal number is out of range: */ 154a091d823SDavid Xu if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 155a091d823SDavid Xu /* Return an invalid argument: */ 156a091d823SDavid Xu errno = EINVAL; 157a091d823SDavid Xu return (-1); 158a091d823SDavid Xu } 159a091d823SDavid Xu 160a091d823SDavid Xu return __sys_sigaction(sig, act, oact); 161a091d823SDavid Xu } 162a091d823SDavid Xu 163a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask); 164a091d823SDavid Xu 165a091d823SDavid Xu int 166a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 167a091d823SDavid Xu { 168a091d823SDavid Xu const sigset_t *p = set; 169a091d823SDavid Xu sigset_t newset; 170a091d823SDavid Xu 171a091d823SDavid Xu if (how != SIG_UNBLOCK) { 172a091d823SDavid Xu if (set != NULL) { 173a091d823SDavid Xu newset = *set; 174a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 175a091d823SDavid Xu p = &newset; 176a091d823SDavid Xu } 177a091d823SDavid Xu } 178a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 179a091d823SDavid Xu } 180a091d823SDavid Xu 181bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask); 182bb535300SJeff Roberson 183bb535300SJeff Roberson int 184bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 185bb535300SJeff Roberson { 186a091d823SDavid Xu if (_sigprocmask(how, set, oset)) 187a091d823SDavid Xu return (errno); 188a091d823SDavid Xu return (0); 189bb535300SJeff Roberson } 190bb535300SJeff Roberson 191a091d823SDavid Xu __weak_reference(_sigsuspend, sigsuspend); 192bb535300SJeff Roberson 193bb535300SJeff Roberson int 194a091d823SDavid Xu _sigsuspend(const sigset_t * set) 195bb535300SJeff Roberson { 196a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 197a091d823SDavid Xu sigset_t newset; 198a091d823SDavid Xu const sigset_t *pset; 199a091d823SDavid Xu int oldcancel; 200a091d823SDavid Xu int ret; 201bb535300SJeff Roberson 202a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 203a091d823SDavid Xu newset = *set; 204a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 205a091d823SDavid Xu pset = &newset; 206a091d823SDavid Xu } else 207a091d823SDavid Xu pset = set; 2080ad70ba9SMike Makonnen 209a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 210a091d823SDavid Xu ret = __sys_sigsuspend(pset); 211a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 2120ad70ba9SMike Makonnen 213a091d823SDavid Xu return (ret); 214a091d823SDavid Xu } 215a091d823SDavid Xu 216a091d823SDavid Xu __weak_reference(__sigwait, sigwait); 217a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait); 218a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo); 219a091d823SDavid Xu 220a091d823SDavid Xu int 221a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info, 222a091d823SDavid Xu const struct timespec * timeout) 223a091d823SDavid Xu { 224a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 225a091d823SDavid Xu sigset_t newset; 226a091d823SDavid Xu const sigset_t *pset; 227a091d823SDavid Xu int oldcancel; 228a091d823SDavid Xu int ret; 229a091d823SDavid Xu 230a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 231a091d823SDavid Xu newset = *set; 232a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 233a091d823SDavid Xu pset = &newset; 234a091d823SDavid Xu } else 235a091d823SDavid Xu pset = set; 236a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 237a091d823SDavid Xu ret = __sys_sigtimedwait(pset, info, timeout); 238a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 239a091d823SDavid Xu return (ret); 240a091d823SDavid Xu } 241a091d823SDavid Xu 242a091d823SDavid Xu int 243a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info) 244a091d823SDavid Xu { 245a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 246a091d823SDavid Xu sigset_t newset; 247a091d823SDavid Xu const sigset_t *pset; 248a091d823SDavid Xu int oldcancel; 249a091d823SDavid Xu int ret; 250a091d823SDavid Xu 251a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 252a091d823SDavid Xu newset = *set; 253a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 254a091d823SDavid Xu pset = &newset; 255a091d823SDavid Xu } else 256a091d823SDavid Xu pset = set; 257a091d823SDavid Xu 258a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 259a091d823SDavid Xu ret = __sys_sigwaitinfo(pset, info); 260a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 261a091d823SDavid Xu return (ret); 262a091d823SDavid Xu } 263a091d823SDavid Xu 264a091d823SDavid Xu int 265a091d823SDavid Xu __sigwait(const sigset_t *set, int *sig) 266a091d823SDavid Xu { 267a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 268a091d823SDavid Xu sigset_t newset; 269a091d823SDavid Xu const sigset_t *pset; 270a091d823SDavid Xu int oldcancel; 271a091d823SDavid Xu int ret; 272a091d823SDavid Xu 273a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 274a091d823SDavid Xu newset = *set; 275a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 276a091d823SDavid Xu pset = &newset; 277a091d823SDavid Xu } else 278a091d823SDavid Xu pset = set; 279a091d823SDavid Xu 280a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 281a091d823SDavid Xu ret = __sys_sigwait(pset, sig); 282a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 283a091d823SDavid Xu return (ret); 284bb535300SJeff Roberson } 285