diff options
Diffstat (limited to 'mit-pthreads/pthreads/signal.c')
-rw-r--r-- | mit-pthreads/pthreads/signal.c | 653 |
1 files changed, 0 insertions, 653 deletions
diff --git a/mit-pthreads/pthreads/signal.c b/mit-pthreads/pthreads/signal.c deleted file mode 100644 index 7da4183c1cb..00000000000 --- a/mit-pthreads/pthreads/signal.c +++ /dev/null @@ -1,653 +0,0 @@ -/* ==== signal.c ============================================================ - * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Chris Provenzano. - * 4. The name of Chris Provenzano may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Description : Queue functions. - * - * 1.00 93/07/21 proven - * -Started coding this file. - */ - -#ifndef lint -static const char rcsid[] = "$Id$"; -#endif - -#include <config.h> -#include <pthread.h> -#include <signal.h> - -/* This will force init.o to get dragged in; if you've got support for - C++ initialization, that'll cause pthread_init to be called at - program startup automatically, so the application won't need to - call it explicitly. */ - -extern char __pthread_init_hack; -char *__pthread_init_hack_2 = &__pthread_init_hack; - -/* - * Time which select in fd_kern_wait() will sleep. - * If there are no threads to run we sleep for an hour or until - * we get an interrupt or an fd thats awakens. To make sure we - * don't miss an interrupt this variable gets reset too zero in - * sig_handler_real(). - */ -struct timeval __fd_kern_wait_timeout = { 0, 0 }; - -/* - * Global for user-kernel lock, and blocked signals - */ - -static sig_atomic_t signum_to_process[SIGMAX + 1] = { 0, }; -volatile sig_atomic_t sig_to_process = 0; - -/* static volatile sigset_t sig_to_process; */ -static volatile int sig_count = 0; - -static void sig_handler(int signal); -static void set_thread_timer(); -static void __cleanup_after_resume( void ); -void sig_prevent(void); -void sig_resume(void); - -/* ========================================================================== - * context_switch() - * - * This routine saves the current state of the running thread gets - * the next thread to run and restores it's state. To allow different - * processors to work with this routine, I allow the machdep_restore_state() - * to either return or have it return from machdep_save_state with a value - * other than 0, this is for implementations which use setjmp/longjmp. - */ -static void context_switch() -{ - struct pthread **current, *next, *last, **dead; - - if (pthread_run->state == PS_RUNNING) { - /* Put current thread back on the queue */ - pthread_prio_queue_enq(pthread_current_prio_queue, pthread_run); - } - - /* save floating point registers if necessary */ - if (!(pthread_run->attr.flags & PTHREAD_NOFLOAT)) { - machdep_save_float_state(pthread_run); - } - /* save state of current thread */ - if (machdep_save_state()) { - return; - } - - last = pthread_run; - - /* Poll all fds */ - fd_kern_poll(); - -context_switch_reschedule:; - /* Are there any threads to run */ - if (pthread_run = pthread_prio_queue_deq(pthread_current_prio_queue)) { - /* restore floating point registers if necessary */ - if (!(pthread_run->attr.flags & PTHREAD_NOFLOAT)) { - machdep_restore_float_state(); - } - uthread_sigmask = &(pthread_run->sigmask); - /* restore state of new current thread */ - machdep_restore_state(); - return; - } - - /* Are there any threads at all */ - for (next = pthread_link_list; next; next = next->pll) { - if ((next->state != PS_UNALLOCED) && (next->state != PS_DEAD)) { - sigset_t sig_to_block, oset; - - sigfillset(&sig_to_block); - - /* - * Check sig_to_process before calling fd_kern_wait, to handle - * things like zero timeouts to select() which would register - * a signal with the sig_handler_fake() call. - * - * This case should ignore SIGVTALRM - */ - machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset); - signum_to_process[SIGVTALRM] = 0; - if (sig_to_process) { - /* Process interrupts */ - /* - * XXX pthread_run should not be set! - * Places where it dumps core should be fixed to - * check for the existance of pthread_run --proven - */ - sig_handler(0); - } else { - machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); - /* - * Do a wait, timeout is set to a hour unless we get an - * intr. before the select in wich case it polls. - */ - fd_kern_wait(); - machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset); - /* Check for interrupts, but ignore SIGVTALR */ - signum_to_process[SIGVTALRM] = 0; - if (sig_to_process) { - /* Process interrupts */ - sig_handler(0); - } - } - machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); - goto context_switch_reschedule; - } - } - - /* There are no threads alive. */ - pthread_run = last; - exit(0); -} - -#if !defined(HAVE_SYSCALL_SIGSUSPEND) && defined(HAVE_SYSCALL_SIGPAUSE) - -/* ========================================================================== - * machdep_sys_sigsuspend() - */ -int machdep_sys_sigsuspend(sigset_t * set) -{ - return(machdep_sys_sigpause(* set)); -} - -#endif - -/* ========================================================================== - * sig_handler_pause() - * - * Wait until a signal is sent to the process. - */ -void sig_handler_pause() -{ - sigset_t sig_to_block, sig_to_pause, oset; - - sigfillset(&sig_to_block); - sigemptyset(&sig_to_pause); - machdep_sys_sigprocmask(SIG_BLOCK, &sig_to_block, &oset); -/* if (!(SIG_ANY(sig_to_process))) { */ - if (!sig_to_process) { - machdep_sys_sigsuspend(&sig_to_pause); - } - machdep_sys_sigprocmask(SIG_UNBLOCK, &sig_to_block, &oset); -} - -/* ========================================================================== - * context_switch_done() - * - * This routine does all the things that are necessary after a context_switch() - * calls the machdep_restore_state(). DO NOT put this in the context_switch() - * routine because sometimes the machdep_restore_state() doesn't return - * to context_switch() but instead ends up in machdep_thread_start() or - * some such routine, which will need to call this routine and - * sig_check_and_resume(). - */ -void context_switch_done() -{ - /* sigdelset((sigset_t *)&sig_to_process, SIGVTALRM); */ - signum_to_process[SIGVTALRM] = 0; - set_thread_timer(); -} - -/* ========================================================================== - * set_thread_timer() - * - * Assums kernel is locked. - */ -static void set_thread_timer() -{ - static int last_sched_attr = SCHED_RR; - - switch (pthread_run->attr.schedparam_policy) { - case SCHED_RR: - machdep_set_thread_timer(&(pthread_run->machdep_data)); - break; - case SCHED_FIFO: - if (last_sched_attr != SCHED_FIFO) { - machdep_unset_thread_timer(NULL); - } - break; - case SCHED_IO: - if ((last_sched_attr != SCHED_IO) && (!sig_count)) { - machdep_set_thread_timer(&(pthread_run->machdep_data)); - } - break; - default: - machdep_set_thread_timer(&(pthread_run->machdep_data)); - break; - } - last_sched_attr = pthread_run->attr.schedparam_policy; -} - -/* ========================================================================== - * sigvtalrm() - */ -static inline void sigvtalrm() -{ - if (sig_count) { - sigset_t sigall, oset; - - sig_count = 0; - - /* Unblock all signals */ - sigemptyset(&sigall); - machdep_sys_sigprocmask(SIG_SETMASK, &sigall, &oset); - } - context_switch(); - context_switch_done(); -} - -/* ========================================================================== - * sigdefault() - */ -static inline void sigdefault(int sig) -{ - int ret; - - ret = pthread_sig_register(sig); - if (pthread_run && (ret > pthread_run->pthread_priority)) { - sigvtalrm(); - } -} - -/* ========================================================================== - * sig_handler_switch() - */ -static inline void sig_handler_switch(int sig) -{ - int ret; - - switch(sig) { - case 0: - break; - case SIGVTALRM: - sigvtalrm(); - break; - case SIGALRM: -/* sigdelset((sigset_t *)&sig_to_process, SIGALRM); */ - signum_to_process[SIGALRM] = 0; - switch (ret = sleep_wakeup()) { - default: - if (pthread_run && (ret > pthread_run->pthread_priority)) { - sigvtalrm(); - } - case 0: - break; - case NOTOK: - /* Do the registered action, no threads were sleeping */ - /* There is a timing window that gets - * here when no threads are on the - * sleep queue. This is a quick fix. - * The real problem is possibly related - * to heavy use of condition variables - * with time outs. - * (mevans) - *sigdefault(sig); - */ - break; - } - break; - case SIGCHLD: -/* sigdelset((sigset_t *)&sig_to_process, SIGCHLD); */ - signum_to_process[SIGCHLD] = 0; - switch (ret = wait_wakeup()) { - default: - if (pthread_run && (ret > pthread_run->pthread_priority)) { - sigvtalrm(); - } - case 0: - break; - case NOTOK: - /* Do the registered action, no threads were waiting */ - sigdefault(sig); - break; - } - break; - -#ifdef SIGINFO - case SIGINFO: - pthread_dump_info (); - /* Then fall through, invoking the application's - signal handler after printing our info out. - - I'm not convinced that this is right, but I'm not - 100% convinced that it is wrong, and this is how - Chris wants it done... */ -#endif - - default: - /* Do the registered action */ - if (!sigismember(uthread_sigmask, sig)) { - /* - * If the signal isn't masked by the last running thread and - * the signal behavior is default or ignore then we can - * execute it immediatly. --proven - */ - pthread_sig_default(sig); - } - signum_to_process[sig] = 0; - sigdefault(sig); - break; - } - -} - -/* ========================================================================== - * sig_handler() - * - * Process signal that just came in, plus any pending on the signal mask. - * All of these must be resolved. - * - * Assumes the kernel is locked. - */ -static void sig_handler(int sig) -{ - if (pthread_kernel_lock != 1) { - PANIC(); - } - - if (sig) { - sig_handler_switch(sig); - } - - while (sig_to_process) { - for (sig_to_process = 0, sig = 1; sig <= SIGMAX; sig++) { - if (signum_to_process[sig]) { - sig_handler_switch(sig); - } - } - } - - -/* - if (SIG_ANY(sig_to_process)) { - for (sig = 1; sig <= SIGMAX; sig++) { - if (sigismember((sigset_t *)&sig_to_process, sig)) { - goto sig_handler_top; - } - } - } -*/ -} - -/* ========================================================================== - * sig_handler_real() - * - * On a multi-processor this would need to use the test and set instruction - * otherwise the following will work. - */ -void sig_handler_real(int sig) -{ - /* - * Get around systems with BROKEN signal handlers. - * - * Some systems will reissue SIGCHLD if the handler explicitly - * clear the signal pending by either doing a wait() or - * ignoring the signal. - */ -#if defined BROKEN_SIGNALS - if (sig == SIGCHLD) { - sigignore(SIGCHLD); - signal(SIGCHLD, sig_handler_real); - } -#endif - - if (pthread_kernel_lock) { - /* sigaddset((sigset_t *)&sig_to_process, sig); */ - __fd_kern_wait_timeout.tv_sec = 0; - signum_to_process[sig] = 1; - sig_to_process = 1; - return; - } - pthread_kernel_lock++; - - sig_count++; - sig_handler(sig); - - /* Handle any signals the current thread might have just gotten */ - if (pthread_run && pthread_run->sigcount) { - pthread_sig_process(); - } - pthread_kernel_lock--; -} - -/* ========================================================================== - * sig_handler_fake() - */ -void sig_handler_fake(int sig) -{ - if (pthread_kernel_lock) { - /* sigaddset((sigset_t *)&sig_to_process, sig); */ - signum_to_process[sig] = 1; - sig_to_process = 1; - return; - } - pthread_kernel_lock++; - sig_handler(sig); - while (!(--pthread_kernel_lock)) { - if (sig_to_process) { - /* if (SIG_ANY(sig_to_process)) { */ - pthread_kernel_lock++; - sig_handler(0); - } else { - break; - } - } -} - -/* ========================================================================== - * __pthread_signal_delete(int sig) - * - * Assumes the kernel is locked. - */ -void __pthread_signal_delete(int sig) -{ - signum_to_process[sig] = 0; -} - -/* ========================================================================== - * pthread_sched_other_resume() - * - * Check if thread to be resumed is of higher priority and if so - * stop current thread and start new thread. - */ -pthread_sched_other_resume(struct pthread * pthread) -{ - pthread->state = PS_RUNNING; - pthread_prio_queue_enq(pthread_current_prio_queue, pthread); - - if (pthread->pthread_priority > pthread_run->pthread_priority) { - if (pthread_kernel_lock == 1) { - sig_handler(SIGVTALRM); - } - } - - __cleanup_after_resume(); -} - -/* ========================================================================== - * pthread_resched_resume() - * - * This routine assumes that the caller is the current pthread, pthread_run - * and that it has a lock the kernel thread and it wants to reschedule itself. - */ -void pthread_resched_resume(enum pthread_state state) -{ - pthread_run->state = state; - - /* Since we are about to block this thread, lets see if we are - * at a cancel point and if we've been cancelled. - * Avoid cancelling dead or unalloced threads. - */ - if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) && - TEST_PTHREAD_IS_CANCELLABLE(pthread_run) && - state != PS_DEAD && state != PS_UNALLOCED ) { - - /* Set this flag to avoid recursively calling pthread_exit */ - /* We have to set this flag here because we will unlock the - * kernel prior to calling pthread_cancel_internal. - */ - SET_PF_RUNNING_TO_CANCEL(pthread_run); - - pthread_run->old_state = state; /* unlock needs this data */ - pthread_sched_resume(); /* Unlock kernel before cancel */ - pthread_cancel_internal( 1 ); /* free locks and exit */ - } - - sig_handler(SIGVTALRM); - - __cleanup_after_resume(); -} - -/* ========================================================================== - * pthread_sched_resume() - */ -void pthread_sched_resume() -{ - __cleanup_after_resume(); -} - -/*---------------------------------------------------------------------- - * Function: __cleanup_after_resume - * Purpose: cleanup kernel locks after a resume - * Args: void - * Returns: void - * Notes: - *----------------------------------------------------------------------*/ -static void -__cleanup_after_resume( void ) -{ - /* Only bother if we are truely unlocking the kernel */ - while (!(--pthread_kernel_lock)) { - /* if (SIG_ANY(sig_to_process)) { */ - if (sig_to_process) { - pthread_kernel_lock++; - sig_handler(0); - continue; - } - if (pthread_run && pthread_run->sigcount) { - pthread_kernel_lock++; - pthread_sig_process(); - continue; - } - break; - } - - if( pthread_run == NULL ) - return; /* Must be during init processing */ - - /* Test for cancel that should be handled now */ - - if( ! TEST_PF_RUNNING_TO_CANCEL(pthread_run) && - TEST_PTHREAD_IS_CANCELLABLE(pthread_run) ) { - /* Kernel is already unlocked */ - pthread_cancel_internal( 1 ); /* free locks and exit */ - } -} - -/* ========================================================================== - * pthread_sched_prevent() - */ -void pthread_sched_prevent(void) -{ - pthread_kernel_lock++; -} - -/* ========================================================================== - * sig_init() - * - * SIGVTALRM (NOT POSIX) needed for thread timeslice timeouts. - * Since it's not POSIX I will replace it with a - * virtual timer for threads. - * SIGALRM (IS POSIX) so some special handling will be - * necessary to fake SIGALRM signals - */ -#ifndef SIGINFO -#define SIGINFO 0 -#endif -void sig_init(void) -{ - static const int signum_to_initialize[] = - { SIGCHLD, SIGALRM, SIGVTALRM, SIGINFO, 0 }; - static const int signum_to_ignore[] = { SIGKILL, SIGSTOP, 0 }; - int i, j; - -#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION) - struct sigaction act; - - act.sa_handler = sig_handler_real; - sigemptyset(&(act.sa_mask)); - act.sa_flags = 0; -#endif - - /* Initialize the important signals */ - for (i = 0; signum_to_initialize[i]; i++) { - -#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION) - if (sigaction(signum_to_initialize[i], &act, NULL)) { -#else - if (signal(signum_to_initialize[i], sig_handler_real)) { -#endif - PANIC(); - } - } - - /* Initialize the rest of the signals */ - for (j = 1; j < SIGMAX; j++) { - for (i = 0; signum_to_initialize[i]; i++) { - if (signum_to_initialize[i] == j) { - goto sig_next; - } - } - /* Because Solaris 2.4 can't deal -- proven */ - for (i = 0; signum_to_ignore[i]; i++) { - if (signum_to_ignore[i] == j) { - goto sig_next; - } - } - pthread_signal(j, SIG_DFL); - -#if defined(HAVE_SYSCALL_SIGACTION) || defined(HAVE_SYSCALL_KSIGACTION) - sigaction(j, &act, NULL); -#else - signal(j, sig_handler_real); -#endif - - sig_next:; - } - -#if defined BROKEN_SIGNALS - signal(SIGCHLD, sig_handler_real); -#endif - -} - |