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 unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include "namespace.h" 30 #include <sys/param.h> 31 #include <sys/types.h> 32 #include <sys/signalvar.h> 33 #include <signal.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <string.h> 38 #include <pthread.h> 39 #include "un-namespace.h" 40 41 #include "thr_private.h" 42 43 /* #define DEBUG_SIGNAL */ 44 #ifdef DEBUG_SIGNAL 45 #define DBG_MSG stdout_debug 46 #else 47 #define DBG_MSG(x...) 48 #endif 49 50 extern int __pause(void); 51 int ___pause(void); 52 int _raise(int); 53 int __sigtimedwait(const sigset_t *set, siginfo_t *info, 54 const struct timespec * timeout); 55 int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 56 int __sigwait(const sigset_t *set, int *sig); 57 58 static void 59 sigcancel_handler(int sig __unused, 60 siginfo_t *info __unused, ucontext_t *ucp __unused) 61 { 62 struct pthread *curthread = _get_curthread(); 63 64 _thr_ast(curthread); 65 } 66 67 void 68 _thr_ast(struct pthread *curthread) 69 { 70 if (!THR_IN_CRITICAL(curthread)) { 71 _thr_testcancel(curthread); 72 if (__predict_false((curthread->flags & 73 (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 74 == THR_FLAGS_NEED_SUSPEND)) 75 _thr_suspend_check(curthread); 76 } 77 } 78 79 void 80 _thr_suspend_check(struct pthread *curthread) 81 { 82 umtx_t cycle; 83 int err; 84 85 err = errno; 86 /* 87 * Blocks SIGCANCEL which other threads must send. 88 */ 89 _thr_signal_block(curthread); 90 91 /* 92 * Increase critical_count, here we don't use THR_LOCK/UNLOCK 93 * because we are leaf code, we don't want to recursively call 94 * ourself. 95 */ 96 curthread->critical_count++; 97 THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 98 while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 99 THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 100 curthread->cycle++; 101 cycle = curthread->cycle; 102 103 /* Wake the thread suspending us. */ 104 _thr_umtx_wake(&curthread->cycle, INT_MAX); 105 106 /* 107 * if we are from pthread_exit, we don't want to 108 * suspend, just go and die. 109 */ 110 if (curthread->state == PS_DEAD) 111 break; 112 curthread->flags |= THR_FLAGS_SUSPENDED; 113 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 114 _thr_umtx_wait(&curthread->cycle, cycle, NULL); 115 THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 116 curthread->flags &= ~THR_FLAGS_SUSPENDED; 117 } 118 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 119 curthread->critical_count--; 120 121 /* 122 * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and 123 * a new signal frame will nest us, this seems a problem because 124 * stack will grow and overflow, but because kernel will automatically 125 * mask the SIGCANCEL when delivering the signal, so we at most only 126 * have one nesting signal frame, this should be fine. 127 */ 128 _thr_signal_unblock(curthread); 129 errno = err; 130 } 131 132 void 133 _thr_signal_init(void) 134 { 135 struct sigaction act; 136 137 /* Install cancel handler. */ 138 SIGEMPTYSET(act.sa_mask); 139 act.sa_flags = SA_SIGINFO | SA_RESTART; 140 act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 141 __sys_sigaction(SIGCANCEL, &act, NULL); 142 } 143 144 void 145 _thr_signal_deinit(void) 146 { 147 } 148 149 __weak_reference(___pause, pause); 150 151 int 152 ___pause(void) 153 { 154 struct pthread *curthread = _get_curthread(); 155 int ret; 156 157 _thr_cancel_enter(curthread); 158 ret = __pause(); 159 _thr_cancel_leave(curthread); 160 161 return ret; 162 } 163 164 __weak_reference(_raise, raise); 165 166 int 167 _raise(int sig) 168 { 169 int ret; 170 171 if (!_thr_isthreaded()) 172 ret = kill(getpid(), sig); 173 else 174 ret = _thr_send_sig(_get_curthread(), sig); 175 return (ret); 176 } 177 178 __weak_reference(_sigaction, sigaction); 179 180 int 181 _sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 182 { 183 /* Check if the signal number is out of range: */ 184 if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 185 /* Return an invalid argument: */ 186 errno = EINVAL; 187 return (-1); 188 } 189 190 return __sys_sigaction(sig, act, oact); 191 } 192 193 __weak_reference(_sigprocmask, sigprocmask); 194 195 int 196 _sigprocmask(int how, const sigset_t *set, sigset_t *oset) 197 { 198 const sigset_t *p = set; 199 sigset_t newset; 200 201 if (how != SIG_UNBLOCK) { 202 if (set != NULL) { 203 newset = *set; 204 SIGDELSET(newset, SIGCANCEL); 205 p = &newset; 206 } 207 } 208 return (__sys_sigprocmask(how, p, oset)); 209 } 210 211 __weak_reference(_pthread_sigmask, pthread_sigmask); 212 213 int 214 _pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 215 { 216 if (_sigprocmask(how, set, oset)) 217 return (errno); 218 return (0); 219 } 220 221 __weak_reference(__sigsuspend, sigsuspend); 222 223 int 224 _sigsuspend(const sigset_t * set) 225 { 226 sigset_t newset; 227 const sigset_t *pset; 228 int ret; 229 230 if (SIGISMEMBER(*set, SIGCANCEL)) { 231 newset = *set; 232 SIGDELSET(newset, SIGCANCEL); 233 pset = &newset; 234 } else 235 pset = set; 236 237 ret = __sys_sigsuspend(pset); 238 239 return (ret); 240 } 241 242 int 243 __sigsuspend(const sigset_t * set) 244 { 245 struct pthread *curthread = _get_curthread(); 246 sigset_t newset; 247 const sigset_t *pset; 248 int ret; 249 250 if (SIGISMEMBER(*set, SIGCANCEL)) { 251 newset = *set; 252 SIGDELSET(newset, SIGCANCEL); 253 pset = &newset; 254 } else 255 pset = set; 256 257 _thr_cancel_enter(curthread); 258 ret = __sys_sigsuspend(pset); 259 _thr_cancel_leave(curthread); 260 261 return (ret); 262 } 263 264 __weak_reference(__sigwait, sigwait); 265 __weak_reference(__sigtimedwait, sigtimedwait); 266 __weak_reference(__sigwaitinfo, sigwaitinfo); 267 268 int 269 _sigtimedwait(const sigset_t *set, siginfo_t *info, 270 const struct timespec * timeout) 271 { 272 sigset_t newset; 273 const sigset_t *pset; 274 int ret; 275 276 if (SIGISMEMBER(*set, SIGCANCEL)) { 277 newset = *set; 278 SIGDELSET(newset, SIGCANCEL); 279 pset = &newset; 280 } else 281 pset = set; 282 ret = __sys_sigtimedwait(pset, info, timeout); 283 return (ret); 284 } 285 286 int 287 __sigtimedwait(const sigset_t *set, siginfo_t *info, 288 const struct timespec * timeout) 289 { 290 struct pthread *curthread = _get_curthread(); 291 sigset_t newset; 292 const sigset_t *pset; 293 int ret; 294 295 if (SIGISMEMBER(*set, SIGCANCEL)) { 296 newset = *set; 297 SIGDELSET(newset, SIGCANCEL); 298 pset = &newset; 299 } else 300 pset = set; 301 _thr_cancel_enter(curthread); 302 ret = __sys_sigtimedwait(pset, info, timeout); 303 _thr_cancel_leave(curthread); 304 return (ret); 305 } 306 307 int 308 _sigwaitinfo(const sigset_t *set, siginfo_t *info) 309 { 310 sigset_t newset; 311 const sigset_t *pset; 312 int ret; 313 314 if (SIGISMEMBER(*set, SIGCANCEL)) { 315 newset = *set; 316 SIGDELSET(newset, SIGCANCEL); 317 pset = &newset; 318 } else 319 pset = set; 320 321 ret = __sys_sigwaitinfo(pset, info); 322 return (ret); 323 } 324 325 int 326 __sigwaitinfo(const sigset_t *set, siginfo_t *info) 327 { 328 struct pthread *curthread = _get_curthread(); 329 sigset_t newset; 330 const sigset_t *pset; 331 int ret; 332 333 if (SIGISMEMBER(*set, SIGCANCEL)) { 334 newset = *set; 335 SIGDELSET(newset, SIGCANCEL); 336 pset = &newset; 337 } else 338 pset = set; 339 340 _thr_cancel_enter(curthread); 341 ret = __sys_sigwaitinfo(pset, info); 342 _thr_cancel_leave(curthread); 343 return (ret); 344 } 345 346 int 347 _sigwait(const sigset_t *set, int *sig) 348 { 349 sigset_t newset; 350 const sigset_t *pset; 351 int ret; 352 353 if (SIGISMEMBER(*set, SIGCANCEL)) { 354 newset = *set; 355 SIGDELSET(newset, SIGCANCEL); 356 pset = &newset; 357 } else 358 pset = set; 359 360 ret = __sys_sigwait(pset, sig); 361 return (ret); 362 } 363 364 int 365 __sigwait(const sigset_t *set, int *sig) 366 { 367 struct pthread *curthread = _get_curthread(); 368 sigset_t newset; 369 const sigset_t *pset; 370 int ret; 371 372 if (SIGISMEMBER(*set, SIGCANCEL)) { 373 newset = *set; 374 SIGDELSET(newset, SIGCANCEL); 375 pset = &newset; 376 } else 377 pset = set; 378 379 _thr_cancel_enter(curthread); 380 ret = __sys_sigwait(pset, sig); 381 _thr_cancel_leave(curthread); 382 return (ret); 383 } 384