thr_sig.c revision 76280
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 76280 2001-05-04 20:37:07Z deischen $ 33 */ 34#include <sys/param.h> 35#include <sys/types.h> 36#include <sys/signalvar.h> 37#include <signal.h> 38#include <fcntl.h> 39#include <unistd.h> 40#include <setjmp.h> 41#include <errno.h> 42#include <pthread.h> 43#include "pthread_private.h" 44 45/* Prototypes: */ 46static void thread_sig_add(pthread_t pthread, int sig, int has_args); 47static void thread_sig_check_state(pthread_t pthread, int sig); 48static pthread_t thread_sig_find(int sig); 49static void thread_sig_handle_special(int sig); 50static void thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp); 51static void thread_sigframe_add(pthread_t thread, int sig, int has_args); 52static void thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf); 53 54/* #define DEBUG_SIGNAL */ 55#ifdef DEBUG_SIGNAL 56#define DBG_MSG stdout_debug 57#else 58#define DBG_MSG(x...) 59#endif 60 61#if defined(_PTHREADS_INVARIANTS) 62#define SIG_SET_ACTIVE() _sig_in_handler = 1 63#define SIG_SET_INACTIVE() _sig_in_handler = 0 64#else 65#define SIG_SET_ACTIVE() 66#define SIG_SET_INACTIVE() 67#endif 68 69void 70_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) 71{ 72 struct pthread *curthread = _get_curthread(); 73 pthread_t pthread, pthread_h; 74 void *stackp; 75 int in_sched = 0; 76 char c; 77 78 if (ucp == NULL) 79 PANIC("Thread signal handler received null context"); 80 DBG_MSG("Got signal %d, current thread %p\n", sig, curthread); 81 82 if (_thread_kern_in_sched != 0) 83 in_sched = 1; 84 else { 85 stackp = (void *)GET_STACK_UC(ucp); 86 if ((stackp >= _thread_kern_sched_stack) && 87 (stackp <= _thread_kern_sched_stack + SCHED_STACK_SIZE)) 88 in_sched = 1; 89 } 90 /* Check if an interval timer signal: */ 91 if (sig == _SCHED_SIGNAL) { 92 /* Update the scheduling clock: */ 93 gettimeofday((struct timeval *)&_sched_tod, NULL); 94 _sched_ticks++; 95 96 if (in_sched != 0) { 97 /* 98 * The scheduler is already running; ignore this 99 * signal. 100 */ 101 } 102 /* 103 * Check if the scheduler interrupt has come when 104 * the currently running thread has deferred thread 105 * signals. 106 */ 107 else if (curthread->sig_defer_count > 0) 108 curthread->yield_on_sig_undefer = 1; 109 else { 110 /* 111 * Save the context of the currently running thread: 112 */ 113 thread_sig_savecontext(curthread, ucp); 114 115 /* 116 * Schedule the next thread. This function is not 117 * expected to return because it will do a longjmp 118 * instead. 119 */ 120 _thread_kern_sched(ucp); 121 122 /* 123 * This point should not be reached, so abort the 124 * process: 125 */ 126 PANIC("Returned to signal function from scheduler"); 127 } 128 } 129 /* 130 * Check if the kernel has been interrupted while the scheduler 131 * is accessing the scheduling queues or if there is a currently 132 * running thread that has deferred signals. 133 */ 134 else if ((in_sched != 0) || (curthread->sig_defer_count > 0)) { 135 /* Cast the signal number to a character variable: */ 136 c = sig; 137 138 /* 139 * Write the signal number to the kernel pipe so that it will 140 * be ready to read when this signal handler returns. 141 */ 142 if (_queue_signals != 0) { 143 __sys_write(_thread_kern_pipe[1], &c, 1); 144 DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig); 145 } 146 if (_thread_sigq[sig - 1].blocked == 0) { 147 DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig); 148 /* 149 * Do not block this signal; it will be blocked 150 * when the pending signals are run down. 151 */ 152 /* _thread_sigq[sig - 1].blocked = 1; */ 153 154 /* 155 * Queue the signal, saving siginfo and sigcontext 156 * (ucontext). 157 * 158 * XXX - Do we need to copy siginfo and ucp? 159 */ 160 _thread_sigq[sig - 1].signo = sig; 161 if (info != NULL) 162 memcpy(&_thread_sigq[sig - 1].siginfo, info, 163 sizeof(*info)); 164 memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp)); 165 166 /* Indicate that there are queued signals: */ 167 _thread_sigq[sig - 1].pending = 1; 168 _sigq_check_reqd = 1; 169 } 170 /* These signals need special handling: */ 171 else if (sig == SIGCHLD || sig == SIGTSTP || 172 sig == SIGTTIN || sig == SIGTTOU) { 173 _thread_sigq[sig - 1].pending = 1; 174 _thread_sigq[sig - 1].signo = sig; 175 _sigq_check_reqd = 1; 176 } 177 else 178 DBG_MSG("Got signal %d, ignored.\n", sig); 179 } 180 /* 181 * The signal handlers should have been installed so that they 182 * cannot be interrupted by other signals. 183 */ 184 else if (_thread_sigq[sig - 1].blocked == 0) { 185 /* 186 * The signal is not blocked; handle the signal. 187 * 188 * Ignore subsequent occurrences of this signal 189 * until the current signal is handled: 190 */ 191 _thread_sigq[sig - 1].blocked = 1; 192 193 /* This signal will be handled; clear the pending flag: */ 194 _thread_sigq[sig - 1].pending = 0; 195 196 /* 197 * Save siginfo and sigcontext (ucontext). 198 * 199 * XXX - Do we need to copy siginfo and ucp? 200 */ 201 _thread_sigq[sig - 1].signo = sig; 202 203 if (info != NULL) 204 memcpy(&_thread_sigq[sig - 1].siginfo, info, 205 sizeof(*info)); 206 memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp)); 207 SIG_SET_ACTIVE(); 208 209 /* Handle special signals: */ 210 thread_sig_handle_special(sig); 211 212 pthread_h = NULL; 213 if ((pthread = thread_sig_find(sig)) != NULL) { 214 DBG_MSG("Got signal %d, adding frame to thread %p\n", 215 sig, pthread); 216 /* 217 * A thread was found that can handle the signal. 218 * Save the context of the currently running thread 219 * so that we can switch to another thread without 220 * losing track of where the current thread left off. 221 * This also applies if the current thread is the 222 * thread to be signaled. 223 */ 224 thread_sig_savecontext(curthread, ucp); 225 226 /* Setup the target thread to receive the signal: */ 227 thread_sig_add(pthread, sig, /*has_args*/ 1); 228 229 /* Take a peek at the next ready to run thread: */ 230 pthread_h = PTHREAD_PRIOQ_FIRST(); 231 DBG_MSG("Finished adding frame, head of prio list %p\n", 232 pthread_h); 233 } 234 else 235 DBG_MSG("No thread to handle signal %d\n", sig); 236 SIG_SET_INACTIVE(); 237 238 /* 239 * Switch to a different context if the currently running 240 * thread takes a signal, or if another thread takes a 241 * signal and the currently running thread is not in a 242 * signal handler. 243 */ 244 if ((pthread == curthread) || ((pthread_h != NULL) && 245 (pthread_h->active_priority > curthread->active_priority))) { 246 /* Enter the kernel scheduler: */ 247 _thread_kern_sched(ucp); 248 } 249 } 250 else { 251 SIG_SET_ACTIVE(); 252 thread_sig_handle_special(sig); 253 SIG_SET_INACTIVE(); 254 } 255} 256 257static void 258thread_sig_savecontext(pthread_t pthread, ucontext_t *ucp) 259{ 260 memcpy(&pthread->ctx.uc, ucp, sizeof(*ucp)); 261 262 /* XXX - Save FP registers too? */ 263 FP_SAVE_UC(&pthread->ctx.uc); 264 265 /* Mark the context saved as a ucontext: */ 266 pthread->ctxtype = CTX_UC; 267} 268 269/* 270 * Find a thread that can handle the signal. 271 */ 272pthread_t 273thread_sig_find(int sig) 274{ 275 struct pthread *curthread = _get_curthread(); 276 int handler_installed; 277 pthread_t pthread, pthread_next; 278 pthread_t suspended_thread, signaled_thread; 279 280 DBG_MSG("Looking for thread to handle signal %d\n", sig); 281 /* Check if the signal requires a dump of thread information: */ 282 if (sig == SIGINFO) { 283 /* Dump thread information to file: */ 284 _thread_dump_info(); 285 286 /* Unblock this signal to allow further dumps: */ 287 _thread_sigq[sig - 1].blocked = 0; 288 } 289 /* Check if an interval timer signal: */ 290 else if (sig == _SCHED_SIGNAL) { 291 /* 292 * This shouldn't ever occur (should this panic?). 293 */ 294 } else { 295 /* 296 * Enter a loop to look for threads that have the signal 297 * unmasked. POSIX specifies that a thread in a sigwait 298 * will get the signal over any other threads. Second 299 * preference will be threads in in a sigsuspend. Third 300 * preference will be the current thread. If none of the 301 * above, then the signal is delivered to the first thread 302 * that is found. Note that if a custom handler is not 303 * installed, the signal only affects threads in sigwait. 304 */ 305 suspended_thread = NULL; 306 if ((curthread != &_thread_kern_thread) && 307 !sigismember(&curthread->sigmask, sig)) 308 signaled_thread = curthread; 309 else 310 signaled_thread = NULL; 311 if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) || 312 (_thread_sigact[sig - 1].sa_handler == SIG_DFL)) 313 handler_installed = 0; 314 else 315 handler_installed = 1; 316 317 for (pthread = TAILQ_FIRST(&_waitingq); 318 pthread != NULL; pthread = pthread_next) { 319 /* 320 * Grab the next thread before possibly destroying 321 * the link entry. 322 */ 323 pthread_next = TAILQ_NEXT(pthread, pqe); 324 325 if ((pthread->state == PS_SIGWAIT) && 326 sigismember(pthread->data.sigwait, sig)) { 327 /* Change the state of the thread to run: */ 328 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 329 /* 330 * A signal handler is not invoked for threads 331 * in sigwait. Clear the blocked and pending 332 * flags. 333 */ 334 _thread_sigq[sig - 1].blocked = 0; 335 _thread_sigq[sig - 1].pending = 0; 336 337 /* Return the signal number: */ 338 pthread->signo = sig; 339 340 /* 341 * POSIX doesn't doesn't specify which thread 342 * will get the signal if there are multiple 343 * waiters, so we give it to the first thread 344 * we find. 345 * 346 * Do not attempt to deliver this signal 347 * to other threads and do not add the signal 348 * to the process pending set. 349 */ 350 return (NULL); 351 } 352 else if ((handler_installed != 0) && 353 !sigismember(&pthread->sigmask, sig)) { 354 if (pthread->state == PS_SIGSUSPEND) { 355 if (suspended_thread == NULL) 356 suspended_thread = pthread; 357 } else if (signaled_thread == NULL) 358 signaled_thread = pthread; 359 } 360 } 361 362 /* 363 * Only perform wakeups and signal delivery if there is a 364 * custom handler installed: 365 */ 366 if (handler_installed == 0) { 367 /* 368 * There is no handler installed. Unblock the 369 * signal so that if a handler _is_ installed, any 370 * subsequent signals can be handled. 371 */ 372 _thread_sigq[sig - 1].blocked = 0; 373 } else { 374 /* 375 * If we didn't find a thread in the waiting queue, 376 * check the all threads queue: 377 */ 378 if (suspended_thread == NULL && 379 signaled_thread == NULL) { 380 /* 381 * Enter a loop to look for other threads 382 * capable of receiving the signal: 383 */ 384 TAILQ_FOREACH(pthread, &_thread_list, tle) { 385 if (!sigismember(&pthread->sigmask, 386 sig)) { 387 signaled_thread = pthread; 388 break; 389 } 390 } 391 } 392 393 if (suspended_thread == NULL && 394 signaled_thread == NULL) 395 /* 396 * Add it to the set of signals pending 397 * on the process: 398 */ 399 sigaddset(&_process_sigpending, sig); 400 else { 401 /* 402 * We only deliver the signal to one thread; 403 * give preference to the suspended thread: 404 */ 405 if (suspended_thread != NULL) 406 pthread = suspended_thread; 407 else 408 pthread = signaled_thread; 409 return (pthread); 410 } 411 } 412 } 413 414 /* Returns nothing. */ 415 return (NULL); 416} 417 418void 419_thread_sig_check_pending(pthread_t pthread) 420{ 421 sigset_t sigset; 422 int i; 423 424 /* 425 * Check if there are pending signals for the running 426 * thread or process that aren't blocked: 427 */ 428 sigset = pthread->sigpend; 429 SIGSETOR(sigset, _process_sigpending); 430 SIGSETNAND(sigset, pthread->sigmask); 431 if (SIGNOTEMPTY(sigset)) { 432 for (i = 1; i < NSIG; i++) { 433 if (sigismember(&sigset, i) != 0) { 434 if (sigismember(&pthread->sigpend, i) != 0) 435 thread_sig_add(pthread, i, 436 /*has_args*/ 0); 437 else { 438 thread_sig_add(pthread, i, 439 /*has_args*/ 1); 440 sigdelset(&_process_sigpending, i); 441 } 442 } 443 } 444 } 445} 446 447/* 448 * This can only be called from the kernel scheduler. It assumes that 449 * all thread contexts are saved and that a signal frame can safely be 450 * added to any user thread. 451 */ 452void 453_thread_sig_handle_pending(void) 454{ 455 pthread_t pthread; 456 int i, sig; 457 458 PTHREAD_ASSERT(_thread_kern_in_sched != 0, 459 "_thread_sig_handle_pending called from outside kernel schedule"); 460 /* 461 * Check the array of pending signals: 462 */ 463 for (i = 0; i < NSIG; i++) { 464 if (_thread_sigq[i].pending != 0) { 465 /* This signal is no longer pending. */ 466 _thread_sigq[i].pending = 0; 467 468 sig = _thread_sigq[i].signo; 469 470 /* Some signals need special handling: */ 471 thread_sig_handle_special(sig); 472 473 if (_thread_sigq[i].blocked == 0) { 474 /* 475 * Block future signals until this one 476 * is handled: 477 */ 478 _thread_sigq[i].blocked = 1; 479 480 if ((pthread = thread_sig_find(sig)) != NULL) { 481 /* 482 * Setup the target thread to receive 483 * the signal: 484 */ 485 thread_sig_add(pthread, sig, 486 /*has_args*/ 1); 487 } 488 } 489 } 490 } 491} 492 493static void 494thread_sig_handle_special(int sig) 495{ 496 pthread_t pthread, pthread_next; 497 int i; 498 499 switch (sig) { 500 case SIGCHLD: 501 /* 502 * Go through the file list and set all files 503 * to non-blocking again in case the child 504 * set some of them to block. Sigh. 505 */ 506 for (i = 0; i < _thread_dtablesize; i++) { 507 /* Check if this file is used: */ 508 if (_thread_fd_table[i] != NULL) { 509 /* 510 * Set the file descriptor to non-blocking: 511 */ 512 __sys_fcntl(i, F_SETFL, 513 _thread_fd_table[i]->flags | O_NONBLOCK); 514 } 515 } 516 /* 517 * Enter a loop to wake up all threads waiting 518 * for a process to complete: 519 */ 520 for (pthread = TAILQ_FIRST(&_waitingq); 521 pthread != NULL; pthread = pthread_next) { 522 /* 523 * Grab the next thread before possibly 524 * destroying the link entry: 525 */ 526 pthread_next = TAILQ_NEXT(pthread, pqe); 527 528 /* 529 * If this thread is waiting for a child 530 * process to complete, wake it up: 531 */ 532 if (pthread->state == PS_WAIT_WAIT) { 533 /* Make the thread runnable: */ 534 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 535 536 /* Return the signal number: */ 537 pthread->signo = sig; 538 } 539 } 540 break; 541 542 /* 543 * POSIX says that pending SIGCONT signals are 544 * discarded when one of these signals occurs. 545 */ 546 case SIGTSTP: 547 case SIGTTIN: 548 case SIGTTOU: 549 /* 550 * Enter a loop to discard pending SIGCONT 551 * signals: 552 */ 553 TAILQ_FOREACH(pthread, &_thread_list, tle) { 554 sigdelset(&pthread->sigpend, SIGCONT); 555 } 556 break; 557 558 default: 559 break; 560 } 561} 562 563/* 564 * Perform thread specific actions in response to a signal. 565 * This function is only called if there is a handler installed 566 * for the signal, and if the target thread has the signal 567 * unmasked. 568 */ 569static void 570thread_sig_add(pthread_t pthread, int sig, int has_args) 571{ 572 int restart; 573 int suppress_handler = 0; 574 int thread_is_active = 0; 575 576 restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART; 577 578 /* Make sure this signal isn't still in the pending set: */ 579 sigdelset(&pthread->sigpend, sig); 580 581 /* 582 * Process according to thread state: 583 */ 584 switch (pthread->state) { 585 /* 586 * States which do not change when a signal is trapped: 587 */ 588 case PS_DEAD: 589 case PS_DEADLOCK: 590 case PS_STATE_MAX: 591 case PS_SIGTHREAD: 592 /* 593 * You can't call a signal handler for threads in these 594 * states. 595 */ 596 suppress_handler = 1; 597 break; 598 599 /* 600 * States which do not need any cleanup handling when signals 601 * occur: 602 */ 603 case PS_RUNNING: 604 /* 605 * Remove the thread from the queue before changing its 606 * priority: 607 */ 608 if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) 609 PTHREAD_PRIOQ_REMOVE(pthread); 610 else 611 /* 612 * This thread is running; avoid placing it in 613 * the run queue: 614 */ 615 thread_is_active = 1; 616 break; 617 618 case PS_SUSPENDED: 619 break; 620 621 case PS_SPINBLOCK: 622 /* Remove the thread from the workq and waitq: */ 623 PTHREAD_WORKQ_REMOVE(pthread); 624 PTHREAD_WAITQ_REMOVE(pthread); 625 /* Make the thread runnable: */ 626 PTHREAD_SET_STATE(pthread, PS_RUNNING); 627 break; 628 629 case PS_SIGWAIT: 630 /* The signal handler is not called for threads in SIGWAIT. */ 631 suppress_handler = 1; 632 /* Wake up the thread if the signal is blocked. */ 633 if (sigismember(pthread->data.sigwait, sig)) { 634 /* Change the state of the thread to run: */ 635 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 636 637 /* Return the signal number: */ 638 pthread->signo = sig; 639 } else 640 /* Increment the pending signal count. */ 641 sigaddset(&pthread->sigpend, sig); 642 break; 643 644 /* 645 * The wait state is a special case due to the handling of 646 * SIGCHLD signals. 647 */ 648 case PS_WAIT_WAIT: 649 if (sig == SIGCHLD) { 650 /* Change the state of the thread to run: */ 651 PTHREAD_WAITQ_REMOVE(pthread); 652 PTHREAD_SET_STATE(pthread, PS_RUNNING); 653 654 /* Return the signal number: */ 655 pthread->signo = sig; 656 } 657 else { 658 /* 659 * Mark the thread as interrupted only if the 660 * restart flag is not set on the signal action: 661 */ 662 if (restart == 0) 663 pthread->interrupted = 1; 664 PTHREAD_WAITQ_REMOVE(pthread); 665 PTHREAD_SET_STATE(pthread, PS_RUNNING); 666 } 667 break; 668 669 /* 670 * States which cannot be interrupted but still require the 671 * signal handler to run: 672 */ 673 case PS_JOIN: 674 /* Only set the interrupted flag for PS_JOIN: */ 675 pthread->interrupted = 1; 676 /* FALLTHROUGH */ 677 case PS_COND_WAIT: 678 case PS_MUTEX_WAIT: 679 /* 680 * Remove the thread from the wait queue. It will 681 * be added back to the wait queue once all signal 682 * handlers have been invoked. 683 */ 684 PTHREAD_WAITQ_REMOVE(pthread); 685 break; 686 687 /* 688 * States which are interruptible but may need to be removed 689 * from queues before any signal handler is called. 690 * 691 * XXX - We may not need to handle this condition, but will 692 * mark it as a potential problem. 693 */ 694 case PS_FDLR_WAIT: 695 case PS_FDLW_WAIT: 696 case PS_FILE_WAIT: 697 if (restart == 0) 698 pthread->interrupted = 1; 699 /* 700 * Remove the thread from the wait queue. Our 701 * signal handler hook will remove this thread 702 * from the fd or file queue before invoking 703 * the actual handler. 704 */ 705 PTHREAD_WAITQ_REMOVE(pthread); 706 break; 707 708 /* 709 * States which are interruptible: 710 */ 711 case PS_FDR_WAIT: 712 case PS_FDW_WAIT: 713 if (restart == 0) { 714 /* 715 * Flag the operation as interrupted and 716 * set the state to running: 717 */ 718 pthread->interrupted = 1; 719 PTHREAD_SET_STATE(pthread, PS_RUNNING); 720 } 721 PTHREAD_WORKQ_REMOVE(pthread); 722 PTHREAD_WAITQ_REMOVE(pthread); 723 break; 724 725 case PS_POLL_WAIT: 726 case PS_SELECT_WAIT: 727 case PS_SLEEP_WAIT: 728 /* 729 * Unmasked signals always cause poll, select, and sleep 730 * to terminate early, regardless of SA_RESTART: 731 */ 732 pthread->interrupted = 1; 733 /* Remove threads in poll and select from the workq: */ 734 if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0) 735 PTHREAD_WORKQ_REMOVE(pthread); 736 PTHREAD_WAITQ_REMOVE(pthread); 737 PTHREAD_SET_STATE(pthread, PS_RUNNING); 738 break; 739 740 case PS_SIGSUSPEND: 741 PTHREAD_WAITQ_REMOVE(pthread); 742 PTHREAD_SET_STATE(pthread, PS_RUNNING); 743 break; 744 } 745 746 if (suppress_handler == 0) { 747 /* Setup a signal frame and save the current threads state: */ 748 thread_sigframe_add(pthread, sig, has_args); 749 750 /* 751 * Signals are deferred until just before the threads 752 * signal handler is invoked: 753 */ 754 pthread->sig_defer_count = 1; 755 756 /* Make sure the thread is runnable: */ 757 if (pthread->state != PS_RUNNING) 758 PTHREAD_SET_STATE(pthread, PS_RUNNING); 759 /* 760 * The thread should be removed from all scheduling 761 * queues at this point. Raise the priority and place 762 * the thread in the run queue. 763 */ 764 pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY; 765 if (thread_is_active == 0) 766 PTHREAD_PRIOQ_INSERT_TAIL(pthread); 767 } 768} 769 770static void 771thread_sig_check_state(pthread_t pthread, int sig) 772{ 773 /* 774 * Process according to thread state: 775 */ 776 switch (pthread->state) { 777 /* 778 * States which do not change when a signal is trapped: 779 */ 780 case PS_DEAD: 781 case PS_DEADLOCK: 782 case PS_STATE_MAX: 783 case PS_SIGTHREAD: 784 case PS_RUNNING: 785 case PS_SUSPENDED: 786 case PS_SPINBLOCK: 787 case PS_COND_WAIT: 788 case PS_JOIN: 789 case PS_MUTEX_WAIT: 790 break; 791 792 case PS_SIGWAIT: 793 /* Wake up the thread if the signal is blocked. */ 794 if (sigismember(pthread->data.sigwait, sig)) { 795 /* Change the state of the thread to run: */ 796 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 797 798 /* Return the signal number: */ 799 pthread->signo = sig; 800 } else 801 /* Increment the pending signal count. */ 802 sigaddset(&pthread->sigpend, sig); 803 break; 804 805 /* 806 * The wait state is a special case due to the handling of 807 * SIGCHLD signals. 808 */ 809 case PS_WAIT_WAIT: 810 if (sig == SIGCHLD) { 811 /* 812 * Remove the thread from the wait queue and 813 * make it runnable: 814 */ 815 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 816 817 /* Return the signal number: */ 818 pthread->signo = sig; 819 } 820 break; 821 822 case PS_FDLR_WAIT: 823 case PS_FDLW_WAIT: 824 case PS_SIGSUSPEND: 825 case PS_SLEEP_WAIT: 826 /* 827 * Remove the thread from the wait queue and make it 828 * runnable: 829 */ 830 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 831 832 /* Flag the operation as interrupted: */ 833 pthread->interrupted = 1; 834 break; 835 836 /* 837 * These states are additionally in the work queue: 838 */ 839 case PS_FDR_WAIT: 840 case PS_FDW_WAIT: 841 case PS_FILE_WAIT: 842 case PS_POLL_WAIT: 843 case PS_SELECT_WAIT: 844 /* 845 * Remove the thread from the wait and work queues, and 846 * make it runnable: 847 */ 848 PTHREAD_WORKQ_REMOVE(pthread); 849 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 850 851 /* Flag the operation as interrupted: */ 852 pthread->interrupted = 1; 853 break; 854 } 855} 856 857/* 858 * Send a signal to a specific thread (ala pthread_kill): 859 */ 860void 861_thread_sig_send(pthread_t pthread, int sig) 862{ 863 struct pthread *curthread = _get_curthread(); 864 865 /* Check for signals whose actions are SIG_DFL: */ 866 if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) { 867 /* 868 * Check to see if a temporary signal handler is 869 * installed for sigwaiters: 870 */ 871 if (_thread_dfl_count[sig] == 0) 872 /* 873 * Deliver the signal to the process if a handler 874 * is not installed: 875 */ 876 kill(getpid(), sig); 877 /* 878 * Assuming we're still running after the above kill(), 879 * make any necessary state changes to the thread: 880 */ 881 thread_sig_check_state(pthread, sig); 882 } 883 /* 884 * Check that the signal is not being ignored: 885 */ 886 else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { 887 if (pthread->state == PS_SIGWAIT && 888 sigismember(pthread->data.sigwait, sig)) { 889 /* Change the state of the thread to run: */ 890 PTHREAD_NEW_STATE(pthread, PS_RUNNING); 891 892 /* Return the signal number: */ 893 pthread->signo = sig; 894 } else if (pthread == curthread) { 895 /* Add the signal to the pending set: */ 896 sigaddset(&pthread->sigpend, sig); 897 if (!sigismember(&pthread->sigmask, sig)) { 898 /* 899 * Call the kernel scheduler which will safely 900 * install a signal frame for this thread: 901 */ 902 _thread_kern_sched_sig(); 903 } 904 } else if (!sigismember(&pthread->sigmask, sig)) { 905 /* Protect the scheduling queues: */ 906 _thread_kern_sig_defer(); 907 /* 908 * Perform any state changes due to signal 909 * arrival: 910 */ 911 thread_sig_add(pthread, sig, /* has args */ 0); 912 /* Unprotect the scheduling queues: */ 913 _thread_kern_sig_undefer(); 914 } else { 915 /* Increment the pending signal count. */ 916 sigaddset(&pthread->sigpend,sig); 917 } 918 } 919} 920 921/* 922 * User thread signal handler wrapper. 923 * 924 * thread - current running thread 925 */ 926void 927_thread_sig_wrapper(void) 928{ 929 void (*sigfunc)(int, siginfo_t *, void *); 930 struct pthread_signal_frame *psf; 931 struct pthread *thread = _get_curthread(); 932 933 /* Get the current frame and state: */ 934 psf = thread->curframe; 935 thread->curframe = NULL; 936 PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler"); 937 938 /* Check the threads previous state: */ 939 if (psf->saved_state.psd_state != PS_RUNNING) { 940 /* 941 * Do a little cleanup handling for those threads in 942 * queues before calling the signal handler. Signals 943 * for these threads are temporarily blocked until 944 * after cleanup handling. 945 */ 946 switch (psf->saved_state.psd_state) { 947 case PS_FDLR_WAIT: 948 case PS_FDLW_WAIT: 949 _fd_lock_backout(thread); 950 psf->saved_state.psd_state = PS_RUNNING; 951 break; 952 953 case PS_COND_WAIT: 954 _cond_wait_backout(thread); 955 psf->saved_state.psd_state = PS_RUNNING; 956 break; 957 958 case PS_JOIN: 959 _join_backout(thread); 960 psf->saved_state.psd_state = PS_RUNNING; 961 break; 962 963 case PS_MUTEX_WAIT: 964 _mutex_lock_backout(thread); 965 psf->saved_state.psd_state = PS_RUNNING; 966 break; 967 968 default: 969 break; 970 } 971 } 972 973 /* Unblock the signal in case we don't return from the handler: */ 974 _thread_sigq[psf->signo - 1].blocked = 0; 975 976 /* 977 * Lower the priority before calling the handler in case 978 * it never returns (longjmps back): 979 */ 980 thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY; 981 982 /* 983 * Reenable interruptions without checking for the need to 984 * context switch: 985 */ 986 thread->sig_defer_count = 0; 987 988 /* 989 * Check that a custom handler is installed and if the signal 990 * is not blocked: 991 */ 992 sigfunc = _thread_sigact[psf->signo - 1].sa_sigaction; 993 if (((__sighandler_t *)sigfunc != SIG_DFL) && 994 ((__sighandler_t *)sigfunc != SIG_IGN)) { 995 DBG_MSG("_thread_sig_wrapper: Calling signal handler for " 996 "thread 0x%p\n", thread); 997 /* 998 * Dispatch the signal via the custom signal 999 * handler: 1000 */ 1001 if (psf->sig_has_args == 0) 1002 (*(sigfunc))(psf->signo, NULL, NULL); 1003 else if ((_thread_sigact[psf->signo - 1].sa_flags & 1004 SA_SIGINFO) != 0) 1005 (*(sigfunc))(psf->signo, &psf->siginfo, &psf->uc); 1006 else 1007 (*(sigfunc))(psf->signo, 1008 (siginfo_t *)psf->siginfo.si_code, &psf->uc); 1009 } 1010 /* 1011 * Call the kernel scheduler to safely restore the frame and 1012 * schedule the next thread: 1013 */ 1014 _thread_kern_sched_frame(psf); 1015} 1016 1017static void 1018thread_sigframe_add(pthread_t thread, int sig, int has_args) 1019{ 1020 struct pthread_signal_frame *psf = NULL; 1021 unsigned long stackp = 0; 1022 1023 /* Get the top of the threads stack: */ 1024 switch (thread->ctxtype) { 1025 case CTX_JB: 1026 case CTX_JB_NOSIG: 1027 stackp = GET_STACK_JB(thread->ctx.jb); 1028 break; 1029 case CTX_SJB: 1030 stackp = GET_STACK_SJB(thread->ctx.sigjb); 1031 break; 1032 case CTX_UC: 1033 stackp = GET_STACK_UC(&thread->ctx.uc); 1034 break; 1035 default: 1036 PANIC("Invalid thread context type"); 1037 break; 1038 } 1039 1040 /* 1041 * Leave a little space on the stack and round down to the 1042 * nearest aligned word: 1043 */ 1044 stackp -= sizeof(double); 1045 stackp &= ~0x3UL; 1046 1047 /* Allocate room on top of the stack for a new signal frame: */ 1048 stackp -= sizeof(struct pthread_signal_frame); 1049 1050 psf = (struct pthread_signal_frame *) stackp; 1051 1052 /* Save the current context in the signal frame: */ 1053 thread_sigframe_save(thread, psf); 1054 1055 /* Set handler specific information: */ 1056 psf->sig_has_args = has_args; 1057 psf->signo = sig; 1058 if (has_args) { 1059 /* Copy the signal handler arguments to the signal frame: */ 1060 memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc, 1061 sizeof(psf->uc)); 1062 memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo, 1063 sizeof(psf->siginfo)); 1064 } 1065 1066 /* Setup the signal mask: */ 1067 SIGSETOR(thread->sigmask, _thread_sigact[sig - 1].sa_mask); 1068 sigaddset(&thread->sigmask, sig); 1069 1070 /* Set up the new frame: */ 1071 thread->curframe = psf; 1072 thread->ctxtype = CTX_JB_NOSIG; 1073 thread->longjmp_val = 1; 1074 thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE | 1075 PTHREAD_FLAGS_IN_SYNCQ; 1076 /* 1077 * Set up the context: 1078 */ 1079 stackp -= sizeof(double); 1080 _setjmp(thread->ctx.jb); 1081 SET_STACK_JB(thread->ctx.jb, stackp); 1082 SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper); 1083} 1084 1085void 1086_thread_sigframe_restore(pthread_t thread, struct pthread_signal_frame *psf) 1087{ 1088 thread->ctxtype = psf->ctxtype; 1089 memcpy(&thread->ctx.uc, &psf->ctx.uc, sizeof(thread->ctx.uc)); 1090 /* 1091 * Only restore the signal mask if it hasn't been changed 1092 * by the application during invocation of the signal handler: 1093 */ 1094 if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno) 1095 thread->sigmask = psf->saved_state.psd_sigmask; 1096 thread->curframe = psf->saved_state.psd_curframe; 1097 thread->wakeup_time = psf->saved_state.psd_wakeup_time; 1098 thread->data = psf->saved_state.psd_wait_data; 1099 thread->state = psf->saved_state.psd_state; 1100 thread->flags = psf->saved_state.psd_flags; 1101 thread->interrupted = psf->saved_state.psd_interrupted; 1102 thread->longjmp_val = psf->saved_state.psd_longjmp_val; 1103 thread->signo = psf->saved_state.psd_signo; 1104 thread->sig_defer_count = psf->saved_state.psd_sig_defer_count; 1105} 1106 1107static void 1108thread_sigframe_save(pthread_t thread, struct pthread_signal_frame *psf) 1109{ 1110 psf->ctxtype = thread->ctxtype; 1111 memcpy(&psf->ctx.uc, &thread->ctx.uc, sizeof(thread->ctx.uc)); 1112 psf->saved_state.psd_sigmask = thread->sigmask; 1113 psf->saved_state.psd_curframe = thread->curframe; 1114 psf->saved_state.psd_wakeup_time = thread->wakeup_time; 1115 psf->saved_state.psd_wait_data = thread->data; 1116 psf->saved_state.psd_state = thread->state; 1117 psf->saved_state.psd_flags = thread->flags & 1118 (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE); 1119 psf->saved_state.psd_interrupted = thread->interrupted; 1120 psf->saved_state.psd_longjmp_val = thread->longjmp_val; 1121 psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno; 1122 psf->saved_state.psd_signo = thread->signo; 1123 psf->saved_state.psd_sig_defer_count = thread->sig_defer_count; 1124} 1125 1126