thr_sig.c revision 176818
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: head/lib/libthr/thread/thr_sig.c 176818 2008-03-05 07:04:55Z davidxu $ 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 50extern int __pause(void); 51int ___pause(void); 52int _raise(int); 53int __sigtimedwait(const sigset_t *set, siginfo_t *info, 54 const struct timespec * timeout); 55int _sigtimedwait(const sigset_t *set, siginfo_t *info, 56 const struct timespec * timeout); 57int __sigwaitinfo(const sigset_t *set, siginfo_t *info); 58int _sigwaitinfo(const sigset_t *set, siginfo_t *info); 59int __sigwait(const sigset_t *set, int *sig); 60int _sigwait(const sigset_t *set, int *sig); 61int __sigsuspend(const sigset_t *sigmask); 62 63 64static void 65sigcancel_handler(int sig __unused, 66 siginfo_t *info __unused, ucontext_t *ucp __unused) 67{ 68 struct pthread *curthread = _get_curthread(); 69 70 if (curthread->cancel_defer && curthread->cancel_pending) 71 thr_wake(curthread->tid); 72 curthread->in_sigcancel_handler++; 73 _thr_ast(curthread); 74 curthread->in_sigcancel_handler--; 75} 76 77void 78_thr_ast(struct pthread *curthread) 79{ 80 if (!THR_IN_CRITICAL(curthread)) { 81 _thr_testcancel(curthread); 82 if (__predict_false((curthread->flags & 83 (THR_FLAGS_NEED_SUSPEND | THR_FLAGS_SUSPENDED)) 84 == THR_FLAGS_NEED_SUSPEND)) 85 _thr_suspend_check(curthread); 86 } 87} 88 89void 90_thr_suspend_check(struct pthread *curthread) 91{ 92 long cycle; 93 int err; 94 95 err = errno; 96 /* 97 * Blocks SIGCANCEL which other threads must send. 98 */ 99 _thr_signal_block(curthread); 100 101 /* 102 * Increase critical_count, here we don't use THR_LOCK/UNLOCK 103 * because we are leaf code, we don't want to recursively call 104 * ourself. 105 */ 106 curthread->critical_count++; 107 THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 108 while ((curthread->flags & (THR_FLAGS_NEED_SUSPEND | 109 THR_FLAGS_SUSPENDED)) == THR_FLAGS_NEED_SUSPEND) { 110 curthread->cycle++; 111 cycle = curthread->cycle; 112 113 /* Wake the thread suspending us. */ 114 _thr_umtx_wake(&curthread->cycle, INT_MAX); 115 116 /* 117 * if we are from pthread_exit, we don't want to 118 * suspend, just go and die. 119 */ 120 if (curthread->state == PS_DEAD) 121 break; 122 curthread->flags |= THR_FLAGS_SUSPENDED; 123 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 124 _thr_umtx_wait(&curthread->cycle, cycle, NULL); 125 THR_UMUTEX_LOCK(curthread, &(curthread)->lock); 126 curthread->flags &= ~THR_FLAGS_SUSPENDED; 127 } 128 THR_UMUTEX_UNLOCK(curthread, &(curthread)->lock); 129 curthread->critical_count--; 130 131 /* 132 * Unblocks SIGCANCEL, it is possible a new SIGCANCEL is ready and 133 * a new signal frame will nest us, this seems a problem because 134 * stack will grow and overflow, but because kernel will automatically 135 * mask the SIGCANCEL when delivering the signal, so we at most only 136 * have one nesting signal frame, this should be fine. 137 */ 138 _thr_signal_unblock(curthread); 139 errno = err; 140} 141 142void 143_thr_signal_init(void) 144{ 145 struct sigaction act; 146 147 /* Install cancel handler. */ 148 SIGEMPTYSET(act.sa_mask); 149 act.sa_flags = SA_SIGINFO | SA_RESTART; 150 act.sa_sigaction = (__siginfohandler_t *)&sigcancel_handler; 151 __sys_sigaction(SIGCANCEL, &act, NULL); 152} 153 154void 155_thr_signal_deinit(void) 156{ 157} 158 159__weak_reference(___pause, pause); 160 161int 162___pause(void) 163{ 164 struct pthread *curthread = _get_curthread(); 165 int ret; 166 167 _thr_cancel_enter(curthread); 168 ret = __pause(); 169 _thr_cancel_leave(curthread); 170 171 return ret; 172} 173 174__weak_reference(_raise, raise); 175 176int 177_raise(int sig) 178{ 179 int ret; 180 181 if (!_thr_isthreaded()) 182 ret = kill(getpid(), sig); 183 else 184 ret = _thr_send_sig(_get_curthread(), sig); 185 return (ret); 186} 187 188__weak_reference(_sigaction, sigaction); 189 190int 191_sigaction(int sig, const struct sigaction * act, struct sigaction * oact) 192{ 193 /* Check if the signal number is out of range: */ 194 if (sig < 1 || sig > _SIG_MAXSIG || sig == SIGCANCEL) { 195 /* Return an invalid argument: */ 196 errno = EINVAL; 197 return (-1); 198 } 199 200 return __sys_sigaction(sig, act, oact); 201} 202 203__weak_reference(_sigprocmask, sigprocmask); 204 205int 206_sigprocmask(int how, const sigset_t *set, sigset_t *oset) 207{ 208 const sigset_t *p = set; 209 sigset_t newset; 210 211 if (how != SIG_UNBLOCK) { 212 if (set != NULL) { 213 newset = *set; 214 SIGDELSET(newset, SIGCANCEL); 215 p = &newset; 216 } 217 } 218 return (__sys_sigprocmask(how, p, oset)); 219} 220 221__weak_reference(_pthread_sigmask, pthread_sigmask); 222 223int 224_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) 225{ 226 if (_sigprocmask(how, set, oset)) 227 return (errno); 228 return (0); 229} 230 231__weak_reference(__sigsuspend, sigsuspend); 232 233int 234_sigsuspend(const sigset_t * set) 235{ 236 sigset_t newset; 237 const sigset_t *pset; 238 int ret; 239 240 if (SIGISMEMBER(*set, SIGCANCEL)) { 241 newset = *set; 242 SIGDELSET(newset, SIGCANCEL); 243 pset = &newset; 244 } else 245 pset = set; 246 247 ret = __sys_sigsuspend(pset); 248 249 return (ret); 250} 251 252int 253__sigsuspend(const sigset_t * set) 254{ 255 struct pthread *curthread = _get_curthread(); 256 sigset_t newset; 257 const sigset_t *pset; 258 int ret; 259 260 if (SIGISMEMBER(*set, SIGCANCEL)) { 261 newset = *set; 262 SIGDELSET(newset, SIGCANCEL); 263 pset = &newset; 264 } else 265 pset = set; 266 267 _thr_cancel_enter(curthread); 268 ret = __sys_sigsuspend(pset); 269 _thr_cancel_leave(curthread); 270 271 return (ret); 272} 273 274__weak_reference(__sigwait, sigwait); 275__weak_reference(__sigtimedwait, sigtimedwait); 276__weak_reference(__sigwaitinfo, sigwaitinfo); 277 278int 279_sigtimedwait(const sigset_t *set, siginfo_t *info, 280 const struct timespec * timeout) 281{ 282 sigset_t newset; 283 const sigset_t *pset; 284 int ret; 285 286 if (SIGISMEMBER(*set, SIGCANCEL)) { 287 newset = *set; 288 SIGDELSET(newset, SIGCANCEL); 289 pset = &newset; 290 } else 291 pset = set; 292 ret = __sys_sigtimedwait(pset, info, timeout); 293 return (ret); 294} 295 296int 297__sigtimedwait(const sigset_t *set, siginfo_t *info, 298 const struct timespec * timeout) 299{ 300 struct pthread *curthread = _get_curthread(); 301 sigset_t newset; 302 const sigset_t *pset; 303 int ret; 304 305 if (SIGISMEMBER(*set, SIGCANCEL)) { 306 newset = *set; 307 SIGDELSET(newset, SIGCANCEL); 308 pset = &newset; 309 } else 310 pset = set; 311 _thr_cancel_enter(curthread); 312 ret = __sys_sigtimedwait(pset, info, timeout); 313 _thr_cancel_leave(curthread); 314 return (ret); 315} 316 317int 318_sigwaitinfo(const sigset_t *set, siginfo_t *info) 319{ 320 sigset_t newset; 321 const sigset_t *pset; 322 int ret; 323 324 if (SIGISMEMBER(*set, SIGCANCEL)) { 325 newset = *set; 326 SIGDELSET(newset, SIGCANCEL); 327 pset = &newset; 328 } else 329 pset = set; 330 331 ret = __sys_sigwaitinfo(pset, info); 332 return (ret); 333} 334 335int 336__sigwaitinfo(const sigset_t *set, siginfo_t *info) 337{ 338 struct pthread *curthread = _get_curthread(); 339 sigset_t newset; 340 const sigset_t *pset; 341 int ret; 342 343 if (SIGISMEMBER(*set, SIGCANCEL)) { 344 newset = *set; 345 SIGDELSET(newset, SIGCANCEL); 346 pset = &newset; 347 } else 348 pset = set; 349 350 _thr_cancel_enter(curthread); 351 ret = __sys_sigwaitinfo(pset, info); 352 _thr_cancel_leave(curthread); 353 return (ret); 354} 355 356int 357_sigwait(const sigset_t *set, int *sig) 358{ 359 sigset_t newset; 360 const sigset_t *pset; 361 int ret; 362 363 if (SIGISMEMBER(*set, SIGCANCEL)) { 364 newset = *set; 365 SIGDELSET(newset, SIGCANCEL); 366 pset = &newset; 367 } else 368 pset = set; 369 370 ret = __sys_sigwait(pset, sig); 371 return (ret); 372} 373 374int 375__sigwait(const sigset_t *set, int *sig) 376{ 377 struct pthread *curthread = _get_curthread(); 378 sigset_t newset; 379 const sigset_t *pset; 380 int ret; 381 382 if (SIGISMEMBER(*set, SIGCANCEL)) { 383 newset = *set; 384 SIGDELSET(newset, SIGCANCEL); 385 pset = &newset; 386 } else 387 pset = set; 388 389 _thr_cancel_enter(curthread); 390 ret = __sys_sigwait(pset, sig); 391 _thr_cancel_leave(curthread); 392 return (ret); 393} 394