summaryrefslogtreecommitdiff
path: root/mit-pthreads/pthreads/sig.c
diff options
context:
space:
mode:
Diffstat (limited to 'mit-pthreads/pthreads/sig.c')
-rw-r--r--mit-pthreads/pthreads/sig.c452
1 files changed, 452 insertions, 0 deletions
diff --git a/mit-pthreads/pthreads/sig.c b/mit-pthreads/pthreads/sig.c
new file mode 100644
index 00000000000..85d4465bf1c
--- /dev/null
+++ b/mit-pthreads/pthreads/sig.c
@@ -0,0 +1,452 @@
+/* ==== 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$";
+#endif
+
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+
+#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));
+}
+