1 /* 2 * Copyright (c) 2005, David Xu <davidxu@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 */ 26 27 #include "namespace.h" 28 #include <sys/signalvar.h> 29 #include <machine/tls.h> 30 #include <signal.h> 31 #include <errno.h> 32 #include <string.h> 33 #include <pthread.h> 34 #include "un-namespace.h" 35 36 #include "thr_private.h" 37 38 /* #define DEBUG_SIGNAL */ 39 #ifdef DEBUG_SIGNAL 40 #define DBG_MSG stdout_debug 41 #else 42 #define DBG_MSG(x...) 43 #endif 44 45 int __sigwait(const sigset_t *set, int *sig); 46 int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 47 int __sigtimedwait(const sigset_t *set, siginfo_t *info, 48 const struct timespec * timeout); 49 50 static void 51 sigcancel_handler(int sig __unused, siginfo_t *info __unused, 52 ucontext_t *ucp __unused) 53 { 54 struct pthread *curthread = tls_get_curthread(); 55 56 if (curthread->cancelflags & THR_CANCEL_AT_POINT) 57 _pthread_testcancel(); 58 _thr_ast(curthread); 59 } 60 61 void 62 _thr_ast(struct pthread *curthread) 63 { 64 if (!THR_IN_CRITICAL(curthread)) { 65 if (__predict_false((curthread->flags & 66 (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 67 == THR_FLAGS_NEED_SUSPEND)) 68 _thr_suspend_check(curthread); 69 } 70 } 71 72 void 73 _thr_suspend_check(struct pthread *curthread) 74 { 75 umtx_t cycle; 76 77 /* 78 * Blocks SIGCANCEL which other threads must send. 79 */ 80 _thr_signal_block(curthread); 81 82 /* 83 * Increase critical_count, here we don't use THR_LOCK/UNLOCK 84 * because we are leaf code, we don't want to recursively call 85 * ourself. 86 */ 87 curthread->critical_count++; 88 THR_UMTX_LOCK(curthread, &(curthread)->lock); 89 while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 90 THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 91 curthread->cycle++; 92 cycle = curthread->cycle; 93 94 /* Wake the thread suspending us. */ 95 _thr_umtx_wake(&curthread->cycle, INT_MAX); 96 97 /* 98 * if we are from pthread_exit, we don't want to 99 * suspend, just go and die. 100 */ 101 if (curthread->state == PS_DEAD) 102 break; 103 curthread->flags |= THR_FLAGS_SUSPENDED; 104 THR_UMTX_UNLOCK(curthread, &(curthread)->lock); 105 _thr_umtx_wait(&curthread->cycle, cycle, NULL, 0); 106 THR_UMTX_LOCK(curthread, &(curthread)->lock); 107 curthread->flags &= ~THR_FLAGS_SUSPENDED; 108 } 109 THR_UMTX_UNLOCK(curthread, &(curthread)->lock); 110 curthread->critical_count--; 111 112 _thr_signal_unblock(curthread); 113 } 114 115 void 116 _thr_signal_init(void) 117 { 118 struct sigaction act; 119 120 /* Install cancel handler. */ 121 SIGEMPTYSET(act.sa_mask); 122 act.sa_flags = SA_SIGINFO | SA_RESTART; 123 act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 124 __sys_sigaction(SIGCANCEL, &act, NULL); 125 } 126 127 void 128 _thr_signal_deinit(void) 129 { 130 } 131 132 int 133 _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 134 { 135 /* Check if the signal number is out of range: */ 136 if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 137 /* Return an invalid argument: */ 138 errno = EINVAL; 139 return (-1); 140 } 141 142 return __sys_sigaction(sig, act, oact); 143 } 144 145 __strong_reference(_sigaction, sigaction); 146 147 int 148 _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 149 { 150 const sigset_t *p = set; 151 sigset_t newset; 152 153 if (how != SIG_UNBLOCK) { 154 if (set != NULL) { 155 newset = *set; 156 SIGDELSET(newset, SIGCANCEL); 157 p = &newset; 158 } 159 } 160 return (__sys_sigprocmask(how, p, oset)); 161 } 162 163 __strong_reference(_sigprocmask, sigprocmask); 164 165 int 166 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 167 { 168 if (_sigprocmask(how, set, oset)) 169 return (errno); 170 return (0); 171 } 172 173 __strong_reference(_pthread_sigmask, pthread_sigmask); 174 175 int 176 _sigsuspend(const sigset_t * set) 177 { 178 struct pthread *curthread = tls_get_curthread(); 179 sigset_t newset; 180 const sigset_t *pset; 181 int oldcancel; 182 int ret; 183 184 if (SIGISMEMBER(*set, SIGCANCEL)) { 185 newset = *set; 186 SIGDELSET(newset, SIGCANCEL); 187 pset = &newset; 188 } else 189 pset = set; 190 191 oldcancel = _thr_cancel_enter(curthread); 192 ret = __sys_sigsuspend(pset); 193 _thr_cancel_leave(curthread, oldcancel); 194 195 return (ret); 196 } 197 198 __strong_reference(_sigsuspend, sigsuspend); 199 200 int 201 __sigtimedwait(const sigset_t *set, siginfo_t *info, 202 const struct timespec * timeout) 203 { 204 struct pthread *curthread = tls_get_curthread(); 205 sigset_t newset; 206 const sigset_t *pset; 207 int oldcancel; 208 int ret; 209 210 if (SIGISMEMBER(*set, SIGCANCEL)) { 211 newset = *set; 212 SIGDELSET(newset, SIGCANCEL); 213 pset = &newset; 214 } else 215 pset = set; 216 oldcancel = _thr_cancel_enter(curthread); 217 ret = __sys_sigtimedwait(pset, info, timeout); 218 _thr_cancel_leave(curthread, oldcancel); 219 return (ret); 220 } 221 222 __strong_reference(__sigtimedwait, sigtimedwait); 223 224 int 225 __sigwaitinfo(const sigset_t *set, siginfo_t *info) 226 { 227 struct pthread *curthread = tls_get_curthread(); 228 sigset_t newset; 229 const sigset_t *pset; 230 int oldcancel; 231 int ret; 232 233 if (SIGISMEMBER(*set, SIGCANCEL)) { 234 newset = *set; 235 SIGDELSET(newset, SIGCANCEL); 236 pset = &newset; 237 } else 238 pset = set; 239 240 oldcancel = _thr_cancel_enter(curthread); 241 ret = __sys_sigwaitinfo(pset, info); 242 _thr_cancel_leave(curthread, oldcancel); 243 return (ret); 244 } 245 246 __strong_reference(__sigwaitinfo, sigwaitinfo); 247 248 int 249 __sigwait(const sigset_t *set, int *sig) 250 { 251 int s; 252 253 s = __sigwaitinfo(set, NULL); 254 if (s > 0) { 255 *sig = s; 256 return (0); 257 } 258 return (errno); 259 } 260 261 __strong_reference(__sigwait, sigwait); 262