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 29bb535300SJeff Roberson #include <sys/param.h> 30bb535300SJeff Roberson #include <sys/types.h> 31bb535300SJeff Roberson #include <sys/signalvar.h> 32bb535300SJeff Roberson #include <signal.h> 33a091d823SDavid Xu #include <errno.h> 34bb535300SJeff Roberson #include <fcntl.h> 35bb535300SJeff Roberson #include <unistd.h> 36a091d823SDavid Xu #include <string.h> 37bb535300SJeff Roberson #include <pthread.h> 3889552201SMike Makonnen 39bb535300SJeff Roberson #include "thr_private.h" 40bb535300SJeff Roberson 41bb535300SJeff Roberson /* #define DEBUG_SIGNAL */ 42bb535300SJeff Roberson #ifdef DEBUG_SIGNAL 43bb535300SJeff Roberson #define DBG_MSG stdout_debug 44bb535300SJeff Roberson #else 45bb535300SJeff Roberson #define DBG_MSG(x...) 46bb535300SJeff Roberson #endif 47bb535300SJeff Roberson 48a091d823SDavid Xu static void 49a091d823SDavid Xu sigcancel_handler(int sig, siginfo_t *info, ucontext_t *ucp) 50a091d823SDavid Xu { 51a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 52a091d823SDavid Xu 53a091d823SDavid Xu if (curthread->cancelflags & THR_CANCEL_AT_POINT) 54a091d823SDavid Xu pthread_testcancel(); 55a091d823SDavid Xu if (curthread->flags & THR_FLAGS_NEED_SUSPEND) { 56a091d823SDavid Xu __sys_sigprocmask(SIG_SETMASK, &ucp->uc_sigmask, NULL); 57a091d823SDavid Xu _thr_suspend_check(curthread); 58a091d823SDavid Xu } 59a091d823SDavid Xu } 60a091d823SDavid Xu 61a091d823SDavid Xu void 62a091d823SDavid Xu _thr_suspend_check(struct pthread *curthread) 63a091d823SDavid Xu { 64a091d823SDavid Xu long cycle; 65a091d823SDavid Xu 66a091d823SDavid Xu /* Async suspend. */ 67a091d823SDavid Xu _thr_signal_block(curthread); 68a091d823SDavid Xu THR_LOCK(curthread); 69a091d823SDavid Xu if ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 70a091d823SDavid Xu == THR_FLAGS_NEED_SUSPEND) { 71a091d823SDavid Xu curthread->flags |= THR_FLAGS_SUSPENDED; 72a091d823SDavid Xu while (curthread->flags & THR_FLAGS_NEED_SUSPEND) { 73a091d823SDavid Xu cycle = curthread->cycle; 74a091d823SDavid Xu THR_UNLOCK(curthread); 75a091d823SDavid Xu _thr_signal_unblock(curthread); 76a091d823SDavid Xu _thr_umtx_wait(&curthread->cycle, cycle, NULL); 77a091d823SDavid Xu _thr_signal_block(curthread); 78a091d823SDavid Xu THR_LOCK(curthread); 79a091d823SDavid Xu } 80a091d823SDavid Xu curthread->flags &= ~THR_FLAGS_SUSPENDED; 81a091d823SDavid Xu } 82a091d823SDavid Xu THR_UNLOCK(curthread); 83a091d823SDavid Xu _thr_signal_unblock(curthread); 84a091d823SDavid Xu } 85a091d823SDavid Xu 86a091d823SDavid Xu void 87a091d823SDavid Xu _thr_signal_init(void) 88a091d823SDavid Xu { 89a091d823SDavid Xu struct sigaction act; 90a091d823SDavid Xu 91a091d823SDavid Xu /* Install cancel handler. */ 92a091d823SDavid Xu SIGEMPTYSET(act.sa_mask); 93a091d823SDavid Xu act.sa_flags = SA_SIGINFO | SA_RESTART; 94a091d823SDavid Xu act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 95a091d823SDavid Xu __sys_sigaction(SIGCANCEL, &act, NULL); 96a091d823SDavid Xu } 97a091d823SDavid Xu 98a091d823SDavid Xu void 99a091d823SDavid Xu _thr_signal_deinit(void) 100a091d823SDavid Xu { 101a091d823SDavid Xu } 102a091d823SDavid Xu 103a091d823SDavid Xu __weak_reference(_sigaction, sigaction); 104a091d823SDavid Xu 105a091d823SDavid Xu int 106a091d823SDavid Xu _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 107a091d823SDavid Xu { 108a091d823SDavid Xu /* Check if the signal number is out of range: */ 109a091d823SDavid Xu if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 110a091d823SDavid Xu /* Return an invalid argument: */ 111a091d823SDavid Xu errno = EINVAL; 112a091d823SDavid Xu return (-1); 113a091d823SDavid Xu } 114a091d823SDavid Xu 115a091d823SDavid Xu return __sys_sigaction(sig, act, oact); 116a091d823SDavid Xu } 117a091d823SDavid Xu 118a091d823SDavid Xu __weak_reference(_sigprocmask, sigprocmask); 119a091d823SDavid Xu 120a091d823SDavid Xu int 121a091d823SDavid Xu _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 122a091d823SDavid Xu { 123a091d823SDavid Xu const sigset_t *p = set; 124a091d823SDavid Xu sigset_t newset; 125a091d823SDavid Xu 126a091d823SDavid Xu if (how != SIG_UNBLOCK) { 127a091d823SDavid Xu if (set != NULL) { 128a091d823SDavid Xu newset = *set; 129a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 130a091d823SDavid Xu p = &newset; 131a091d823SDavid Xu } 132a091d823SDavid Xu } 133a091d823SDavid Xu return (__sys_sigprocmask(how, p, oset)); 134a091d823SDavid Xu } 135a091d823SDavid Xu 136bb535300SJeff Roberson __weak_reference(_pthread_sigmask, pthread_sigmask); 137bb535300SJeff Roberson 138bb535300SJeff Roberson int 139bb535300SJeff Roberson _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 140bb535300SJeff Roberson { 141a091d823SDavid Xu if (_sigprocmask(how, set, oset)) 142a091d823SDavid Xu return (errno); 143a091d823SDavid Xu return (0); 144bb535300SJeff Roberson } 145bb535300SJeff Roberson 146a091d823SDavid Xu __weak_reference(_sigsuspend, sigsuspend); 147bb535300SJeff Roberson 148bb535300SJeff Roberson int 149a091d823SDavid Xu _sigsuspend(const sigset_t * set) 150bb535300SJeff Roberson { 151a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 152a091d823SDavid Xu sigset_t newset; 153a091d823SDavid Xu const sigset_t *pset; 154a091d823SDavid Xu int oldcancel; 155a091d823SDavid Xu int ret; 156bb535300SJeff Roberson 157a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 158a091d823SDavid Xu newset = *set; 159a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 160a091d823SDavid Xu pset = &newset; 161a091d823SDavid Xu } else 162a091d823SDavid Xu pset = set; 1630ad70ba9SMike Makonnen 164a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 165a091d823SDavid Xu ret = __sys_sigsuspend(pset); 166a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 1670ad70ba9SMike Makonnen 168a091d823SDavid Xu return (ret); 169a091d823SDavid Xu } 170a091d823SDavid Xu 171a091d823SDavid Xu __weak_reference(__sigwait, sigwait); 172a091d823SDavid Xu __weak_reference(__sigtimedwait, sigtimedwait); 173a091d823SDavid Xu __weak_reference(__sigwaitinfo, sigwaitinfo); 174a091d823SDavid Xu 175a091d823SDavid Xu int 176a091d823SDavid Xu __sigtimedwait(const sigset_t *set, siginfo_t *info, 177a091d823SDavid Xu const struct timespec * timeout) 178a091d823SDavid Xu { 179a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 180a091d823SDavid Xu sigset_t newset; 181a091d823SDavid Xu const sigset_t *pset; 182a091d823SDavid Xu int oldcancel; 183a091d823SDavid Xu int ret; 184a091d823SDavid Xu 185a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 186a091d823SDavid Xu newset = *set; 187a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 188a091d823SDavid Xu pset = &newset; 189a091d823SDavid Xu } else 190a091d823SDavid Xu pset = set; 191a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 192a091d823SDavid Xu ret = __sys_sigtimedwait(pset, info, timeout); 193a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 194a091d823SDavid Xu return (ret); 195a091d823SDavid Xu } 196a091d823SDavid Xu 197a091d823SDavid Xu int 198a091d823SDavid Xu __sigwaitinfo(const sigset_t *set, siginfo_t *info) 199a091d823SDavid Xu { 200a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 201a091d823SDavid Xu sigset_t newset; 202a091d823SDavid Xu const sigset_t *pset; 203a091d823SDavid Xu int oldcancel; 204a091d823SDavid Xu int ret; 205a091d823SDavid Xu 206a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 207a091d823SDavid Xu newset = *set; 208a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 209a091d823SDavid Xu pset = &newset; 210a091d823SDavid Xu } else 211a091d823SDavid Xu pset = set; 212a091d823SDavid Xu 213a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 214a091d823SDavid Xu ret = __sys_sigwaitinfo(pset, info); 215a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 216a091d823SDavid Xu return (ret); 217a091d823SDavid Xu } 218a091d823SDavid Xu 219a091d823SDavid Xu int 220a091d823SDavid Xu __sigwait(const sigset_t *set, int *sig) 221a091d823SDavid Xu { 222a091d823SDavid Xu struct pthread *curthread = _get_curthread(); 223a091d823SDavid Xu sigset_t newset; 224a091d823SDavid Xu const sigset_t *pset; 225a091d823SDavid Xu int oldcancel; 226a091d823SDavid Xu int ret; 227a091d823SDavid Xu 228a091d823SDavid Xu if (SIGISMEMBER(*set, SIGCANCEL)) { 229a091d823SDavid Xu newset = *set; 230a091d823SDavid Xu SIGDELSET(newset, SIGCANCEL); 231a091d823SDavid Xu pset = &newset; 232a091d823SDavid Xu } else 233a091d823SDavid Xu pset = set; 234a091d823SDavid Xu 235a091d823SDavid Xu oldcancel = _thr_cancel_enter(curthread); 236a091d823SDavid Xu ret = __sys_sigwait(pset, sig); 237a091d823SDavid Xu _thr_cancel_leave(curthread, oldcancel); 238a091d823SDavid Xu return (ret); 239bb535300SJeff Roberson } 240