/* ==== sig.c ======================================================= * Copyright (c) 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 : All the thread signal functions. * * 1.32 94/06/12 proven * -Started coding this file. */ #ifndef lint static const char rcsid[] = "$Id: sig.c,v 1.1 1998/07/21 13:20:22 peter Exp $"; #endif #include #include #include #include #if defined(M_UNIX) #define signal(A,B) machdep_sys_signal((A),(B)) #endif extern void sig_handler_real(); struct pthread * pthread_sigwait; static sigset_t pending_signals; struct pthread_sigvec { void (*vector)(); sigset_t mask; int flags; } pthread_sigvec[SIGMAX]; /* ========================================================================== * pthread_sig_register() * * Assumes the kernel is locked. */ int pthread_sig_register(int sig) { struct pthread ** pthread_ptr, * pthread; int ret; /* * If we have a siginfo structure and the signal is synchronous then * only deliver the signal to the current thread. */ /* Check waiting threads for delivery */ for (pthread_ptr = &pthread_sigwait; (*pthread_ptr); pthread_ptr = &((*pthread_ptr)->next)) { if (sigismember((*pthread_ptr)->data.sigwait, sig)) { pthread=*pthread_ptr; *pthread_ptr=(*pthread_ptr)->next; pthread_prio_queue_enq(pthread_current_prio_queue, pthread); ret = pthread->pthread_priority; *(int *)(pthread->ret) = sig; pthread->state = PS_RUNNING; return(ret); } } /* Check current running thread */ if (pthread_run) { if (!sigismember(&pthread_run->sigmask, sig)) { sigaddset(&pthread_run->sigpending, sig); pthread_run->sigcount++; return(0); } } /* Check any running thread */ for (pthread = pthread_current_prio_queue->next; pthread; pthread = pthread->next) { if (!sigismember(&pthread->sigmask, sig)) { sigaddset(&pthread->sigpending, sig); pthread->sigcount++; return(0); } } /* Check any thread */ for (pthread = pthread_link_list; pthread; pthread = pthread->pll) { if (!sigismember(&pthread->sigmask, sig)) { sigaddset(&pthread->sigpending, sig); pthread->sigcount++; return(0); } } sigaddset(&pending_signals, sig); return(0); } /* ========================================================================== * pthread_sig_default() */ void pthread_sig_default(int sig) { sigset_t mask, omask; if (pthread_sigvec[sig].vector == SIG_DFL) { /* Set the signal handler to default before issueing the kill */ signal(sig, SIG_DFL); kill(getpid(), sig); sigemptyset(&mask); sigaddset(&mask, sig); machdep_sys_sigprocmask(SIG_UNBLOCK, &mask, &omask); signal(sig, sig_handler_real); } } /* ========================================================================== * pthread_sig_process() * * Assumes the kernel is locked. */ void pthread_sig_process() { void (*vector)(); int i, j; for (i = 1; i < SIGMAX; i++) { if (sigismember(&(pthread_run->sigpending), i)) { if (! sigismember(&(pthread_run->sigmask), i)) { sigdelset(&(pthread_run->sigpending), i); pthread_run->sigcount--; if (pthread_sigvec[i].vector == SIG_IGN) { continue; } if (pthread_sigvec[i].vector == SIG_DFL) { pthread_sig_default(i); continue; } { sigset_t omask; sigemptyset(&omask); /* Save old mask */ for (j = 1; j < SIGMAX; j++) { if (sigismember(&(pthread_run->sigmask), j)) { if (sigismember(&(pthread_sigvec[i].mask), j)) sigaddset(&(pthread_run->sigmask), j); sigaddset(&omask, j); } } /* The signal is masked while handling the signal */ sigaddset(&(pthread_run->sigmask), i); /* * Allow interrupts during a signal, * but not a change in the vector */ vector = pthread_sigvec[i].vector; if (--pthread_kernel_lock) { PANIC(); } vector(i); pthread_run->sighandled=1; /* Mark for select; Monty */ pthread_kernel_lock++; memcpy(&(pthread_run->sigmask), &omask, sizeof(omask)); } } } } } /* ========================================================================== * pthread_sigmask() * * It is unclear wheather this call should be implemented as an atomic * operation. The resulting mask could be wrong if in the signal * handler the thread calls sigprocmask for any signal other than the * signal the handler is dealing with. */ int pthread_sigmask(int how, const sigset_t *set, sigset_t * oset) { int i; if (oset) { sigemptyset(oset); for (i = 1; i < SIGMAX; i++) { if (sigismember(&(pthread_run->sigmask), i)) { sigaddset(oset, i); } } } if (set) { switch(how) { case SIG_BLOCK: for (i = 1; i < SIGMAX; i++) { if (sigismember(set, i)) { sigaddset(&(pthread_run->sigmask), i); } } break; case SIG_UNBLOCK: pthread_sched_prevent(); for (i = 1; i < SIGMAX; i++) { if (sigismember(set, i)) { sigdelset(&(pthread_run->sigmask), i); if (sigismember(&pending_signals, i)) { sigaddset(&(pthread_run->sigpending), i); sigdelset(&pending_signals, i); pthread_run->sigcount++; } } } pthread_sched_resume(); break; case SIG_SETMASK: sigfillset(&(pthread_run->sigmask)); pthread_sched_prevent(); for (i = 1; i < SIGMAX; i++) { if (! sigismember(set, i)) { sigdelset(&(pthread_run->sigmask), i); if (sigismember(&pending_signals, i)) { sigaddset(&(pthread_run->sigpending), i); sigdelset(&pending_signals, i); pthread_run->sigcount++; } } } pthread_sched_resume(); break; default: SET_ERRNO(EINVAL); return(NOTOK); } } return(OK); } int sigprocmask(int how, const sigset_t *set, sigset_t * oset) { return(pthread_sigmask(how, set, oset)); } /* ========================================================================== * sigwait() */ int sigwait(const sigset_t * set, int * sig) { int i; /* Check that sig is valid */ *sig = 0; pthread_sched_prevent(); for (i = 1; i < SIGMAX; i++) { if (sigismember(set, i)) { /* Check personal signals */ if (sigismember(&(pthread_run->sigpending), i)) { sigdelset(&(pthread_run->sigpending), i); pthread_sched_resume(); *sig = i; return(OK); } /* Check kernel signals */ if (sigismember(&pending_signals, i)) { sigdelset(&pending_signals, i); pthread_sched_resume(); *sig = i; return(OK); } } } /* No pending signals, wait for one */ pthread_run->next = pthread_sigwait; pthread_sigwait = pthread_run; pthread_run->data.sigwait = set; pthread_run->ret = sig; SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */ pthread_resched_resume(PS_SIGWAIT); CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */ return(OK); } /* ========================================================================== * raise() */ int raise(int sig) { return(pthread_kill(pthread_self(), sig)); } /* ========================================================================== * sigsuspend() */ int sigsuspend(const sigset_t * mask) { int ret_sig, ret; sigset_t nm, om; sigfillset(&nm); for(ret_sig = 1; ret_sig < SIGMAX; ret_sig++) { if (sigismember(mask, ret_sig)) { sigdelset(&nm, ret_sig); } } pthread_sigmask(SIG_BLOCK, &nm, &om); if ((ret = sigwait(&nm, &ret_sig)) == OK) { sigemptyset(&nm); sigaddset(&nm, ret_sig); pthread_kill(pthread_self(), ret_sig); pthread_sigmask(SIG_UNBLOCK, &nm, NULL); /* There is a race condition here, it's not worth worring about */ pthread_sigmask(SIG_BLOCK, &nm, NULL); SET_ERRNO(EINTR); ret = NOTOK; } pthread_sigmask(SIG_SETMASK, &om, NULL); return(ret); } /* ========================================================================== * pthread_signal() */ void (*pthread_signal(int sig, void (*dispatch)(int)))() { void (*odispatch)(int); odispatch = pthread_sigvec[sig].vector; if ((sig > 0) && (sig < SIGMAX)) { pthread_sigvec[sig].vector = dispatch; sigemptyset(&(pthread_sigvec[sig].mask)); pthread_sigvec[sig].flags = 0; } return(odispatch); } /* ========================================================================== * pthread_sigprocmask() */ int pthread_sigaction(int sig, const struct sigaction * act, struct sigaction * oact) { if ((sig > 0) && (sig < SIGMAX)) { if (oact) { memcpy(&(oact->sa_mask), &(pthread_sigvec[sig].mask), sizeof(sigset_t)); oact->sa_handler = pthread_sigvec[sig].vector; oact->sa_flags = pthread_sigvec[sig].flags; } if (act) { memcpy(&(pthread_sigvec[sig].mask), &(act->sa_mask), sizeof(sigset_t)); pthread_sigvec[sig].vector = act->sa_handler; pthread_sigvec[sig].flags = act->sa_flags; } return(OK); } SET_ERRNO(EINVAL); return(NOTOK); } /* * The following here are stolen from BSD because I get mutiply defined * symbols between sig.o and posix_sig.o in Sun's libc.a under Sunos 4.1.3. * The problem is that sigprocmask() is defined in posix_sig.o, in the same * module that a lot of other sigset-primitives are defined, and we have * our definition of sigprocmask() here, but use those other primitives. */ #undef sigemptyset #undef sigfillset #undef sigaddset #undef sigdelset #undef sigismember static const sigset_t __sigemptyset = __SIGEMPTYSET; int sigemptyset(sigset_t *set) { *set = __sigemptyset; return (0); } static const sigset_t __sigfillset = __SIGFILLSET; int sigfillset(sigset_t * set) { *set = __sigfillset; return (0); } #define _MAXIMUM_SIG NSIG int sigaddset(sigset_t *set, int signo) { if (signo <= 0 || signo >= _MAXIMUM_SIG) { errno = EINVAL; return -1; } __SIGADDSET(set, signo); return (0); } int sigdelset(sigset_t *set, int signo) { if (signo <= 0 || signo >= _MAXIMUM_SIG) { errno = EINVAL; return -1; } __SIGDELSET(set, signo); return (0); } int sigismember(const sigset_t *set, int signo) { if (signo <= 0 || signo >= _MAXIMUM_SIG) { errno = EINVAL; return -1; } return(__SIGISMEMBER(set, signo)); }