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