thr_sig.c revision 117366
1/* 2 * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au> 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 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Birrell. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: head/lib/libkse/thread/thr_sig.c 117366 2003-07-09 22:30:55Z davidxu $ 33 */ 34#include <sys/param.h> 35#include <sys/types.h> 36#include <sys/signalvar.h> 37#include <signal.h> 38#include <errno.h> 39#include <fcntl.h> 40#include <unistd.h> 41#include <string.h> 42#include <pthread.h> 43#include "thr_private.h" 44#include "pthread_md.h" 45 46/* Prototypes: */ 47static void build_siginfo(siginfo_t *info, int signo); 48static void thr_sig_check_state(struct pthread *pthread, int sig); 49static struct pthread *thr_sig_find(struct kse *curkse, int sig, 50 siginfo_t *info); 51static void handle_special_signals(struct kse *curkse, int sig); 52static void thr_sigframe_add(struct pthread *thread); 53static void thr_sigframe_restore(struct pthread *thread, 54 struct pthread_sigframe *psf); 55static void thr_sigframe_save(struct pthread *thread, 56 struct pthread_sigframe *psf); 57 58/* #define DEBUG_SIGNAL */ 59#ifdef DEBUG_SIGNAL 60#define DBG_MSG stdout_debug 61#else 62#define DBG_MSG(x...) 63#endif 64 65/* 66 * Signal setup and delivery. 67 * 68 * 1) Delivering signals to threads in the same KSE. 69 * These signals are sent by upcall events and are set in the 70 * km_sigscaught field of the KSE mailbox. Since these signals 71 * are received while operating on the KSE stack, they can be 72 * delivered either by using signalcontext() to add a stack frame 73 * to the target thread's stack, or by adding them in the thread's 74 * pending set and having the thread run them down after it 75 * 2) Delivering signals to threads in other KSEs/KSEGs. 76 * 3) Delivering signals to threads in critical regions. 77 * 4) Delivering signals to threads after they change their signal masks. 78 * 79 * Methods of delivering signals. 80 * 81 * 1) Add a signal frame to the thread's saved context. 82 * 2) Add the signal to the thread structure, mark the thread as 83 * having signals to handle, and let the thread run them down 84 * after it resumes from the KSE scheduler. 85 * 86 * Problem with 1). You can't do this to a running thread or a 87 * thread in a critical region. 88 * 89 * Problem with 2). You can't do this to a thread that doesn't 90 * yield in some way (explicitly enters the scheduler). A thread 91 * blocked in the kernel or a CPU hungry thread will not see the 92 * signal without entering the scheduler. 93 * 94 * The solution is to use both 1) and 2) to deliver signals: 95 * 96 * o Thread in critical region - use 2). When the thread 97 * leaves the critical region it will check to see if it 98 * has pending signals and run them down. 99 * 100 * o Thread enters scheduler explicitly - use 2). The thread 101 * can check for pending signals after it returns from the 102 * the scheduler. 103 * 104 * o Thread is running and not current thread - use 2). When the 105 * thread hits a condition specified by one of the other bullets, 106 * the signal will be delivered. 107 * 108 * o Thread is running and is current thread (e.g., the thread 109 * has just changed its signal mask and now sees that it has 110 * pending signals) - just run down the pending signals. 111 * 112 * o Thread is swapped out due to quantum expiration - use 1) 113 * 114 * o Thread is blocked in kernel - kse_thr_wakeup() and then 115 * use 1) 116 */ 117 118/* 119 * Rules for selecting threads for signals received: 120 * 121 * 1) If the signal is a sychronous signal, it is delivered to 122 * the generating (current thread). If the thread has the 123 * signal masked, it is added to the threads pending signal 124 * set until the thread unmasks it. 125 * 126 * 2) A thread in sigwait() where the signal is in the thread's 127 * waitset. 128 * 129 * 3) A thread in sigsuspend() where the signal is not in the 130 * thread's suspended signal mask. 131 * 132 * 4) Any thread (first found/easiest to deliver) that has the 133 * signal unmasked. 134 */ 135 136static void * 137sig_daemon(void *arg /* Unused */) 138{ 139 int i; 140 kse_critical_t crit; 141 struct timespec ts; 142 sigset_t set; 143 struct kse *curkse; 144 struct pthread *curthread = _get_curthread(); 145 146 DBG_MSG("signal daemon started\n"); 147 148 curthread->name = strdup("signal thread"); 149 crit = _kse_critical_enter(); 150 curkse = _get_curkse(); 151 SIGFILLSET(set); 152 __sys_sigprocmask(SIG_SETMASK, &set, NULL); 153 __sys_sigpending(&set); 154 ts.tv_sec = 0; 155 ts.tv_nsec = 0; 156 while (1) { 157 KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 158 _thr_proc_sigpending = set; 159 KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 160 for (i = 1; i <= _SIG_MAXSIG; i++) { 161 if (SIGISMEMBER(set, i) != 0) 162 _thr_sig_dispatch(curkse, i, 163 NULL /* no siginfo */); 164 } 165 ts.tv_sec = 30; 166 ts.tv_nsec = 0; 167 curkse->k_mbx.km_flags = 168 KMF_NOUPCALL | KMF_NOCOMPLETED | KMF_WAITSIGEVENT; 169 kse_release(&ts); 170 curkse->k_mbx.km_flags = 0; 171 set = curkse->k_mbx.km_sigscaught; 172 } 173 return (0); 174} 175 176/* Utility function to create signal daemon thread */ 177int 178_thr_start_sig_daemon(void) 179{ 180 pthread_attr_t attr; 181 sigset_t sigset, oldset; 182 183 SIGFILLSET(sigset); 184 pthread_sigmask(SIG_SETMASK, &sigset, &oldset); 185 pthread_attr_init(&attr); 186 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 187 /* sigmask will be inherited */ 188 if (pthread_create(&_thr_sig_daemon, &attr, sig_daemon, NULL)) 189 PANIC("can not create signal daemon thread!\n"); 190 pthread_attr_destroy(&attr); 191 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 192 return (0); 193} 194 195/* 196 * This signal handler only delivers asynchronous signals. 197 * This must be called with upcalls disabled and without 198 * holding any locks. 199 */ 200void 201_thr_sig_dispatch(struct kse *curkse, int sig, siginfo_t *info) 202{ 203 struct pthread *thread; 204 205 DBG_MSG(">>> _thr_sig_dispatch(%d)\n", sig); 206 207 /* Some signals need special handling: */ 208 handle_special_signals(curkse, sig); 209 while ((thread = thr_sig_find(curkse, sig, info)) != NULL) { 210 /* 211 * Setup the target thread to receive the signal: 212 */ 213 DBG_MSG("Got signal %d, selecting thread %p\n", sig, thread); 214 KSE_SCHED_LOCK(curkse, thread->kseg); 215 if ((thread->state == PS_DEAD) || 216 (thread->state == PS_DEADLOCK) || 217 THR_IS_EXITING(thread) || THR_IS_SUSPENDED(thread)) { 218 KSE_SCHED_UNLOCK(curkse, thread->kseg); 219 _thr_ref_delete(NULL, thread); 220 } else if ((thread->state == PS_SIGWAIT && 221 SIGISMEMBER(thread->oldsigmask, sig)) || 222 (thread->state != PS_SIGWAIT && 223 SIGISMEMBER(thread->sigmask, sig))) { 224 KSE_SCHED_UNLOCK(curkse, thread->kseg); 225 _thr_ref_delete(NULL, thread); 226 } else { 227 _thr_sig_add(thread, sig, info); 228 KSE_SCHED_UNLOCK(curkse, thread->kseg); 229 _thr_ref_delete(NULL, thread); 230 break; 231 } 232 } 233 DBG_MSG("<<< _thr_sig_dispatch\n"); 234} 235 236void 237_thr_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) 238{ 239 __siginfohandler_t *sigfunc; 240 struct kse *curkse; 241 242 curkse = _get_curkse(); 243 if ((curkse == NULL) || ((curkse->k_flags & KF_STARTED) == 0)) { 244 /* Upcalls are not yet started; just call the handler. */ 245 sigfunc = _thread_sigact[sig - 1].sa_sigaction; 246 if (((__sighandler_t *)sigfunc != SIG_DFL) && 247 ((__sighandler_t *)sigfunc != SIG_IGN) && 248 (sigfunc != (__siginfohandler_t *)_thr_sig_handler)) { 249 if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) 250 != 0) || (info == NULL)) 251 (*(sigfunc))(sig, info, ucp); 252 else 253 (*(sigfunc))(sig, 254 (siginfo_t*)(intptr_t)info->si_code, ucp); 255 } 256 } 257 else { 258 /* Nothing. */ 259 DBG_MSG("Got signal %d\n", sig); 260 /* XXX Bound thread will fall into this... */ 261 } 262} 263 264/* Must be called with signal lock and schedule lock held in order */ 265static void 266thr_sig_invoke_handler(struct pthread *curthread, int sig, siginfo_t *info, 267 ucontext_t *ucp) 268{ 269 void (*sigfunc)(int, siginfo_t *, void *); 270 sigset_t sigmask; 271 int sa_flags; 272 struct sigaction act; 273 struct kse *curkse; 274 275 /* 276 * Invoke the signal handler without going through the scheduler: 277 */ 278 DBG_MSG("Got signal %d, calling handler for current thread %p\n", 279 sig, curthread); 280 281 if (!_kse_in_critical()) 282 PANIC("thr_sig_invoke_handler without in critical\n"); 283 curkse = _get_curkse(); 284 /* 285 * Check that a custom handler is installed and if 286 * the signal is not blocked: 287 */ 288 sigfunc = _thread_sigact[sig - 1].sa_sigaction; 289 sa_flags = _thread_sigact[sig - 1].sa_flags & SA_SIGINFO; 290 sigmask = curthread->sigmask; 291 SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask); 292 if (!(sa_flags & (SA_NODEFER | SA_RESETHAND))) 293 SIGADDSET(curthread->sigmask, sig); 294 if ((sig != SIGILL) && (sa_flags & SA_RESETHAND)) { 295 if (_thread_dfl_count[sig - 1] == 0) { 296 act.sa_handler = SIG_DFL; 297 act.sa_flags = SA_RESTART; 298 SIGEMPTYSET(act.sa_mask); 299 __sys_sigaction(sig, &act, NULL); 300 __sys_sigaction(sig, NULL, &_thread_sigact[sig - 1]); 301 } 302 } 303 KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 304 KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); 305 _kse_critical_leave(&curthread->tmbx); 306 ucp->uc_sigmask = sigmask; 307 308 if (((__sighandler_t *)sigfunc != SIG_DFL) && 309 ((__sighandler_t *)sigfunc != SIG_IGN)) { 310 if ((sa_flags & SA_SIGINFO) != 0 || info == NULL) 311 (*(sigfunc))(sig, info, ucp); 312 else 313 (*(sigfunc))(sig, (siginfo_t*)(intptr_t)info->si_code, 314 ucp); 315 } else { 316 /* XXX 317 * TODO: exit process if signal would kill it. 318 */ 319#ifdef NOTYET 320 if (sigprop(sig) & SA_KILL) 321 kse_sigexit(sig); 322#endif 323 } 324 _kse_critical_enter(); 325 /* Don't trust after critical leave/enter */ 326 curkse = _get_curkse(); 327 KSE_SCHED_LOCK(curkse, curkse->k_kseg); 328 KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 329 /* 330 * Restore the thread's signal mask. 331 */ 332 curthread->sigmask = ucp->uc_sigmask; 333 334 DBG_MSG("Got signal %d, handler returned %p\n", sig, curthread); 335} 336 337int 338_thr_getprocsig(int sig, siginfo_t *siginfo) 339{ 340 kse_critical_t crit; 341 struct kse *curkse; 342 int ret; 343 344 DBG_MSG(">>> _thr_getprocsig\n"); 345 346 crit = _kse_critical_enter(); 347 curkse = _get_curkse(); 348 KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 349 ret = _thr_getprocsig_unlocked(sig, siginfo); 350 KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 351 _kse_critical_leave(crit); 352 353 DBG_MSG("<<< _thr_getprocsig\n"); 354 return (ret); 355} 356 357int 358_thr_getprocsig_unlocked(int sig, siginfo_t *siginfo) 359{ 360 sigset_t sigset; 361 struct timespec ts; 362 363 /* try to retrieve signal from kernel */ 364 SIGEMPTYSET(sigset); 365 SIGADDSET(sigset, sig); 366 ts.tv_sec = 0; 367 ts.tv_nsec = 0; 368 if (__sys_sigtimedwait(&sigset, siginfo, &ts) > 0) { 369 SIGDELSET(_thr_proc_sigpending, sig); 370 return (sig); 371 } 372 return (0); 373} 374 375/* 376 * Find a thread that can handle the signal. This must be called 377 * with upcalls disabled. 378 */ 379struct pthread * 380thr_sig_find(struct kse *curkse, int sig, siginfo_t *info) 381{ 382 struct pthread *pthread; 383 struct pthread *suspended_thread, *signaled_thread; 384 siginfo_t si; 385 386 DBG_MSG("Looking for thread to handle signal %d\n", sig); 387 388 /* Check if the signal requires a dump of thread information: */ 389 if (sig == SIGINFO) { 390 /* Dump thread information to file: */ 391 _thread_dump_info(); 392 } 393 /* 394 * Enter a loop to look for threads that have the signal 395 * unmasked. POSIX specifies that a thread in a sigwait 396 * will get the signal over any other threads. Second 397 * preference will be threads in in a sigsuspend. Third 398 * preference will be the current thread. If none of the 399 * above, then the signal is delivered to the first thread 400 * that is found. Note that if a custom handler is not 401 * installed, the signal only affects threads in sigwait. 402 */ 403 suspended_thread = NULL; 404 signaled_thread = NULL; 405 406 KSE_LOCK_ACQUIRE(curkse, &_thread_list_lock); 407 TAILQ_FOREACH(pthread, &_thread_list, tle) { 408 if (pthread == _thr_sig_daemon) 409 continue; 410#ifdef NOTYET 411 /* Signal delivering to bound thread is done by kernel */ 412 if (pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) 413 continue; 414#endif 415 416 /* Take the scheduling lock. */ 417 KSE_SCHED_LOCK(curkse, pthread->kseg); 418 if ((pthread->state == PS_DEAD) || 419 (pthread->state == PS_DEADLOCK) || 420 THR_IS_EXITING(pthread) || 421 THR_IS_SUSPENDED(pthread)) { 422 ; /* Skip this thread. */ 423 } else if (pthread->state == PS_SIGWAIT && 424 !SIGISMEMBER(pthread->sigmask, sig)) { 425 /* 426 * retrieve signal from kernel, if it is job control 427 * signal, and sigaction is SIG_DFL, then we will 428 * be stopped in kernel, we hold lock here, but that 429 * does not matter, because that's job control, and 430 * whole process should be stopped. 431 */ 432 if (_thr_getprocsig(sig, &si)) { 433 DBG_MSG("Waking thread %p in sigwait" 434 " with signal %d\n", pthread, sig); 435 /* where to put siginfo ? */ 436 *(pthread->data.sigwaitinfo) = si; 437 pthread->sigmask = pthread->oldsigmask; 438 _thr_setrunnable_unlocked(pthread); 439 } 440 KSE_SCHED_UNLOCK(curkse, pthread->kseg); 441 /* 442 * POSIX doesn't doesn't specify which thread 443 * will get the signal if there are multiple 444 * waiters, so we give it to the first thread 445 * we find. 446 * 447 * Do not attempt to deliver this signal 448 * to other threads and do not add the signal 449 * to the process pending set. 450 */ 451 KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 452 return (NULL); 453 } else if (!SIGISMEMBER(pthread->sigmask, sig) || 454 (!SIGISMEMBER(pthread->oldsigmask, sig) && 455 pthread->state == PS_SIGWAIT)) { 456 if (pthread->state == PS_SIGSUSPEND) { 457 if (suspended_thread == NULL) { 458 suspended_thread = pthread; 459 suspended_thread->refcount++; 460 } 461 } else if (signaled_thread == NULL) { 462 signaled_thread = pthread; 463 signaled_thread->refcount++; 464 } 465 } 466 KSE_SCHED_UNLOCK(curkse, pthread->kseg); 467 } 468 KSE_LOCK_RELEASE(curkse, &_thread_list_lock); 469 470 if (suspended_thread != NULL) { 471 pthread = suspended_thread; 472 if (signaled_thread) 473 _thr_ref_delete(NULL, signaled_thread); 474 } else if (signaled_thread) { 475 pthread = signaled_thread; 476 } else { 477 pthread = NULL; 478 } 479 return (pthread); 480} 481 482static void 483build_siginfo(siginfo_t *info, int signo) 484{ 485 bzero(info, sizeof(*info)); 486 info->si_signo = signo; 487 info->si_pid = _thr_pid; 488} 489 490/* 491 * This is called by a thread when it has pending signals to deliver. 492 * It should only be called from the context of the thread. 493 */ 494void 495_thr_sig_rundown(struct pthread *curthread, ucontext_t *ucp, 496 struct pthread_sigframe *psf) 497{ 498 int interrupted = curthread->interrupted; 499 int timeout = curthread->timeout; 500 siginfo_t siginfo; 501 int i; 502 kse_critical_t crit; 503 struct kse *curkse; 504 505 DBG_MSG(">>> thr_sig_rundown %p\n", curthread); 506 /* Check the threads previous state: */ 507 if ((psf != NULL) && (psf->psf_valid != 0)) { 508 /* 509 * Do a little cleanup handling for those threads in 510 * queues before calling the signal handler. Signals 511 * for these threads are temporarily blocked until 512 * after cleanup handling. 513 */ 514 switch (psf->psf_state) { 515 case PS_COND_WAIT: 516 _cond_wait_backout(curthread); 517 psf->psf_state = PS_RUNNING; 518 break; 519 520 case PS_MUTEX_WAIT: 521 _mutex_lock_backout(curthread); 522 psf->psf_state = PS_RUNNING; 523 break; 524 525 case PS_RUNNING: 526 break; 527 528 default: 529 psf->psf_state = PS_RUNNING; 530 break; 531 } 532 /* XXX see comment in thr_sched_switch_unlocked */ 533 curthread->critical_count--; 534 } 535 536 /* 537 * Lower the priority before calling the handler in case 538 * it never returns (longjmps back): 539 */ 540 crit = _kse_critical_enter(); 541 curkse = _get_curkse(); 542 KSE_SCHED_LOCK(curkse, curkse->k_kseg); 543 KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 544 curthread->active_priority &= ~THR_SIGNAL_PRIORITY; 545 546 while (1) { 547 for (i = 1; i <= _SIG_MAXSIG; i++) { 548 if (SIGISMEMBER(curthread->sigmask, i)) 549 continue; 550 if (SIGISMEMBER(curthread->sigpend, i)) { 551 SIGDELSET(curthread->sigpend, i); 552 siginfo = curthread->siginfo[i-1]; 553 break; 554 } 555 if (SIGISMEMBER(_thr_proc_sigpending, i)) { 556 if (_thr_getprocsig_unlocked(i, &siginfo)) 557 break; 558 } 559 } 560 if (i <= _SIG_MAXSIG) 561 thr_sig_invoke_handler(curthread, i, &siginfo, ucp); 562 else 563 break; 564 } 565 566 if (psf != NULL && psf->psf_valid != 0) 567 thr_sigframe_restore(curthread, psf); 568 curkse = _get_curkse(); 569 KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 570 KSE_SCHED_UNLOCK(curkse, curkse->k_kseg); 571 _kse_critical_leave(&curthread->tmbx); 572 573 curthread->interrupted = interrupted; 574 curthread->timeout = timeout; 575 576 DBG_MSG("<<< thr_sig_rundown %p\n", curthread); 577} 578 579/* 580 * This checks pending signals for the current thread. It should be 581 * called whenever a thread changes its signal mask. Note that this 582 * is called from a thread (using its stack). 583 * 584 * XXX - We might want to just check to see if there are pending 585 * signals for the thread here, but enter the UTS scheduler 586 * to actually install the signal handler(s). 587 */ 588void 589_thr_sig_check_pending(struct pthread *curthread) 590{ 591 ucontext_t uc; 592 volatile int once; 593 594 if (THR_IN_CRITICAL(curthread)) 595 return; 596 597 once = 0; 598 THR_GETCONTEXT(&uc); 599 if (once == 0) { 600 once = 1; 601 curthread->check_pending = 0; 602 _thr_sig_rundown(curthread, &uc, NULL); 603 } 604} 605 606/* 607 * This must be called with upcalls disabled. 608 */ 609static void 610handle_special_signals(struct kse *curkse, int sig) 611{ 612 switch (sig) { 613 /* 614 * POSIX says that pending SIGCONT signals are 615 * discarded when one of these signals occurs. 616 */ 617 case SIGTSTP: 618 case SIGTTIN: 619 case SIGTTOU: 620 KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 621 SIGDELSET(_thr_proc_sigpending, SIGCONT); 622 KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 623 break; 624 case SIGCONT: 625 KSE_LOCK_ACQUIRE(curkse, &_thread_signal_lock); 626 SIGDELSET(_thr_proc_sigpending, SIGTSTP); 627 SIGDELSET(_thr_proc_sigpending, SIGTTIN); 628 SIGDELSET(_thr_proc_sigpending, SIGTTOU); 629 KSE_LOCK_RELEASE(curkse, &_thread_signal_lock); 630 default: 631 break; 632 } 633} 634 635/* 636 * Perform thread specific actions in response to a signal. 637 * This function is only called if there is a handler installed 638 * for the signal, and if the target thread has the signal 639 * unmasked. 640 * 641 * This must be called with the thread's scheduling lock held. 642 */ 643void 644_thr_sig_add(struct pthread *pthread, int sig, siginfo_t *info) 645{ 646 int restart; 647 int suppress_handler = 0; 648 int fromproc = 0; 649 struct pthread *curthread = _get_curthread(); 650 struct kse *curkse; 651 siginfo_t siginfo; 652 653 DBG_MSG(">>> _thr_sig_add\n"); 654 655 curkse = _get_curkse(); 656 restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART; 657 fromproc = (curthread == _thr_sig_daemon); 658 659 if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK || 660 pthread->state == PS_STATE_MAX) 661 return; /* return false */ 662 663#ifdef NOTYET 664 if ((pthread->attrs.flags & PTHREAD_SCOPE_SYSTEM) != 0) { 665 if (!fromproc) 666 kse_thr_interrupt(&pthread->tmbx, 0, sig); 667 return; 668 } 669#endif 670 671 if (pthread->curframe == NULL || 672 (pthread->state != PS_SIGWAIT && 673 SIGISMEMBER(pthread->sigmask, sig)) || 674 THR_IN_CRITICAL(pthread)) { 675 /* thread is running or signal was being masked */ 676 if (!fromproc) { 677 SIGADDSET(pthread->sigpend, sig); 678 if (info == NULL) 679 build_siginfo(&pthread->siginfo[sig-1], sig); 680 else if (info != &pthread->siginfo[sig-1]) 681 memcpy(&pthread->siginfo[sig-1], info, 682 sizeof(*info)); 683 } else { 684 if (!_thr_getprocsig(sig, &pthread->siginfo[sig-1])) 685 return; 686 SIGADDSET(pthread->sigpend, sig); 687 } 688 if (!SIGISMEMBER(pthread->sigmask, sig)) { 689 pthread->check_pending = 1; 690 if (pthread->blocked != 0 && !THR_IN_CRITICAL(pthread)) 691 kse_thr_interrupt(&pthread->tmbx, 692 restart ? -2 : -1); 693 } 694 } 695 else { 696 /* if process signal not exists, just return */ 697 if (fromproc) { 698 if (!_thr_getprocsig(sig, &siginfo)) 699 return; 700 info = &siginfo; 701 } 702 /* 703 * Process according to thread state: 704 */ 705 switch (pthread->state) { 706 case PS_DEAD: 707 case PS_DEADLOCK: 708 case PS_STATE_MAX: 709 return; /* XXX return false */ 710 case PS_LOCKWAIT: 711 case PS_SUSPENDED: 712 /* 713 * You can't call a signal handler for threads in these 714 * states. 715 */ 716 suppress_handler = 1; 717 break; 718 case PS_RUNNING: 719 if ((pthread->flags & THR_FLAGS_IN_RUNQ)) { 720 THR_RUNQ_REMOVE(pthread); 721 pthread->active_priority |= THR_SIGNAL_PRIORITY; 722 THR_RUNQ_INSERT_TAIL(pthread); 723 } else { 724 /* Possible not in RUNQ and has curframe ? */ 725 pthread->active_priority |= THR_SIGNAL_PRIORITY; 726 } 727 suppress_handler = 1; 728 break; 729 /* 730 * States which cannot be interrupted but still require the 731 * signal handler to run: 732 */ 733 case PS_COND_WAIT: 734 case PS_MUTEX_WAIT: 735 break; 736 737 case PS_SLEEP_WAIT: 738 /* 739 * Unmasked signals always cause sleep to terminate 740 * early regardless of SA_RESTART: 741 */ 742 pthread->interrupted = 1; 743 break; 744 745 case PS_JOIN: 746 break; 747 748 case PS_SIGSUSPEND: 749 pthread->interrupted = 1; 750 break; 751 752 case PS_SIGWAIT: 753 if (info == NULL) 754 build_siginfo(&pthread->siginfo[sig-1], sig); 755 else if (info != &pthread->siginfo[sig-1]) 756 memcpy(&pthread->siginfo[sig-1], info, 757 sizeof(*info)); 758 /* 759 * The signal handler is not called for threads in 760 * SIGWAIT. 761 */ 762 suppress_handler = 1; 763 /* Wake up the thread if the signal is not blocked. */ 764 if (!SIGISMEMBER(pthread->sigmask, sig)) { 765 /* Return the signal number: */ 766 *(pthread->data.sigwaitinfo) = pthread->siginfo[sig-1]; 767 pthread->sigmask = pthread->oldsigmask; 768 /* Make the thread runnable: */ 769 _thr_setrunnable_unlocked(pthread); 770 } else { 771 /* Increment the pending signal count. */ 772 SIGADDSET(pthread->sigpend, sig); 773 if (!SIGISMEMBER(pthread->oldsigmask, sig)) { 774 pthread->check_pending = 1; 775 pthread->interrupted = 1; 776 pthread->sigmask = pthread->oldsigmask; 777 _thr_setrunnable_unlocked(pthread); 778 } 779 } 780 781 return; 782 } 783 784 SIGADDSET(pthread->sigpend, sig); 785 if (info == NULL) 786 build_siginfo(&pthread->siginfo[sig-1], sig); 787 else if (info != &pthread->siginfo[sig-1]) 788 memcpy(&pthread->siginfo[sig-1], info, sizeof(*info)); 789 790 if (suppress_handler == 0) { 791 /* 792 * Setup a signal frame and save the current threads 793 * state: 794 */ 795 thr_sigframe_add(pthread); 796 if (pthread->flags & THR_FLAGS_IN_RUNQ) 797 THR_RUNQ_REMOVE(pthread); 798 pthread->active_priority |= THR_SIGNAL_PRIORITY; 799 _thr_setrunnable_unlocked(pthread); 800 } else { 801 pthread->check_pending = 1; 802 } 803 } 804 805 DBG_MSG("<<< _thr_sig_add\n"); 806} 807 808static void 809thr_sig_check_state(struct pthread *pthread, int sig) 810{ 811 /* 812 * Process according to thread state: 813 */ 814 switch (pthread->state) { 815 /* 816 * States which do not change when a signal is trapped: 817 */ 818 case PS_RUNNING: 819 case PS_LOCKWAIT: 820 case PS_MUTEX_WAIT: 821 case PS_COND_WAIT: 822 case PS_JOIN: 823 case PS_SUSPENDED: 824 case PS_DEAD: 825 case PS_DEADLOCK: 826 case PS_STATE_MAX: 827 break; 828 829 case PS_SIGWAIT: 830 build_siginfo(&pthread->siginfo[sig-1], sig); 831 /* Wake up the thread if the signal is blocked. */ 832 if (!SIGISMEMBER(pthread->sigmask, sig)) { 833 /* Return the signal number: */ 834 *(pthread->data.sigwaitinfo) = pthread->siginfo[sig-1]; 835 pthread->sigmask = pthread->oldsigmask; 836 /* Change the state of the thread to run: */ 837 _thr_setrunnable_unlocked(pthread); 838 } else { 839 /* Increment the pending signal count. */ 840 SIGADDSET(pthread->sigpend, sig); 841 if (!SIGISMEMBER(pthread->oldsigmask, sig)) { 842 pthread->check_pending = 1; 843 pthread->interrupted = 1; 844 pthread->sigmask = pthread->oldsigmask; 845 _thr_setrunnable_unlocked(pthread); 846 } 847 } 848 break; 849 850 case PS_SIGSUSPEND: 851 case PS_SLEEP_WAIT: 852 /* 853 * Remove the thread from the wait queue and make it 854 * runnable: 855 */ 856 _thr_setrunnable_unlocked(pthread); 857 858 /* Flag the operation as interrupted: */ 859 pthread->interrupted = 1; 860 break; 861 } 862} 863 864/* 865 * Send a signal to a specific thread (ala pthread_kill): 866 */ 867void 868_thr_sig_send(struct pthread *pthread, int sig) 869{ 870 struct pthread *curthread = _get_curthread(); 871 872#ifdef NOTYET 873 if ((pthread->attr.flags & PTHREAD_SCOPE_SYSTEM) == 0) { 874 kse_thr_interrupt(&pthread->tmbx, sig); 875 return; 876 } 877#endif 878 /* Lock the scheduling queue of the target thread. */ 879 THR_SCHED_LOCK(curthread, pthread); 880 881 /* Check for signals whose actions are SIG_DFL: */ 882 if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) { 883 /* 884 * Check to see if a temporary signal handler is 885 * installed for sigwaiters: 886 */ 887 if (_thread_dfl_count[sig - 1] == 0) { 888 /* 889 * Deliver the signal to the process if a handler 890 * is not installed: 891 */ 892 THR_SCHED_UNLOCK(curthread, pthread); 893 kill(getpid(), sig); 894 THR_SCHED_LOCK(curthread, pthread); 895 } 896 /* 897 * Assuming we're still running after the above kill(), 898 * make any necessary state changes to the thread: 899 */ 900 thr_sig_check_state(pthread, sig); 901 THR_SCHED_UNLOCK(curthread, pthread); 902 } 903 /* 904 * Check that the signal is not being ignored: 905 */ 906 else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { 907 _thr_sig_add(pthread, sig, NULL); 908 THR_SCHED_UNLOCK(curthread, pthread); 909 /* XXX 910 * If thread sent signal to itself, check signals now. 911 * It is not really needed, _kse_critical_leave should 912 * have already checked signals. 913 */ 914 if (pthread == curthread && curthread->check_pending) 915 _thr_sig_check_pending(curthread); 916 } else { 917 THR_SCHED_UNLOCK(curthread, pthread); 918 } 919} 920 921static void 922thr_sigframe_add(struct pthread *thread) 923{ 924 if (thread->curframe == NULL) 925 PANIC("Thread doesn't have signal frame "); 926 927 if (thread->curframe->psf_valid == 0) { 928 thread->curframe->psf_valid = 1; 929 /* 930 * Multiple signals can be added to the same signal 931 * frame. Only save the thread's state the first time. 932 */ 933 thr_sigframe_save(thread, thread->curframe); 934 } 935} 936 937static void 938thr_sigframe_restore(struct pthread *thread, struct pthread_sigframe *psf) 939{ 940 if (psf->psf_valid == 0) 941 PANIC("invalid pthread_sigframe\n"); 942 thread->flags = psf->psf_flags; 943 thread->interrupted = psf->psf_interrupted; 944 thread->signo = psf->psf_signo; 945 thread->state = psf->psf_state; 946 thread->data = psf->psf_wait_data; 947 thread->wakeup_time = psf->psf_wakeup_time; 948} 949 950static void 951thr_sigframe_save(struct pthread *thread, struct pthread_sigframe *psf) 952{ 953 /* This has to initialize all members of the sigframe. */ 954 psf->psf_flags = 955 thread->flags & (THR_FLAGS_PRIVATE | THR_FLAGS_IN_TDLIST); 956 psf->psf_interrupted = thread->interrupted; 957 psf->psf_signo = thread->signo; 958 psf->psf_state = thread->state; 959 psf->psf_wait_data = thread->data; 960 psf->psf_wakeup_time = thread->wakeup_time; 961} 962 963void 964_thr_signal_init(void) 965{ 966 sigset_t sigset; 967 struct sigaction act; 968 int i; 969 970 SIGFILLSET(sigset); 971 __sys_sigprocmask(SIG_SETMASK, &sigset, &_thr_initial->sigmask); 972 /* Enter a loop to get the existing signal status: */ 973 for (i = 1; i <= _SIG_MAXSIG; i++) { 974 /* Check for signals which cannot be trapped: */ 975 if (i == SIGKILL || i == SIGSTOP) { 976 } 977 978 /* Get the signal handler details: */ 979 else if (__sys_sigaction(i, NULL, 980 &_thread_sigact[i - 1]) != 0) { 981 /* 982 * Abort this process if signal 983 * initialisation fails: 984 */ 985 PANIC("Cannot read signal handler info"); 986 } 987 } 988 /* 989 * Install the signal handler for SIGINFO. It isn't 990 * really needed, but it is nice to have for debugging 991 * purposes. 992 */ 993 _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO | SA_RESTART; 994 SIGEMPTYSET(act.sa_mask); 995 act.sa_flags = SA_SIGINFO | SA_RESTART; 996 act.sa_sigaction = (__siginfohandler_t *)&_thr_sig_handler; 997 if (__sys_sigaction(SIGINFO, &act, NULL) != 0) { 998 /* 999 * Abort this process if signal initialisation fails: 1000 */ 1001 PANIC("Cannot initialize signal handler"); 1002 } 1003} 1004 1005void 1006_thr_signal_deinit(void) 1007{ 1008 struct pthread *curthread = _get_curthread(); 1009 sigset_t tmpmask; 1010 int i; 1011 1012 SIGFILLSET(tmpmask); 1013 SIG_CANTMASK(tmpmask); 1014 __sys_sigprocmask(SIG_SETMASK, &tmpmask, NULL); 1015 /* Enter a loop to get the existing signal status: */ 1016 for (i = 1; i <= _SIG_MAXSIG; i++) { 1017 /* Check for signals which cannot be trapped: */ 1018 if (i == SIGKILL || i == SIGSTOP) { 1019 } 1020 1021 /* Set the signal handler details: */ 1022 else if (__sys_sigaction(i, &_thread_sigact[i - 1], NULL) != 0) { 1023 /* 1024 * Abort this process if signal 1025 * initialisation fails: 1026 */ 1027 PANIC("Cannot set signal handler info"); 1028 } 1029 } 1030 __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); 1031} 1032 1033