summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/libpthread/uthread/pthread_private.h15
-rw-r--r--lib/libpthread/uthread/uthread_kern.c78
-rw-r--r--lib/libpthread/uthread/uthread_kill.c170
-rw-r--r--lib/libpthread/uthread/uthread_mutex.c10
-rw-r--r--lib/libpthread/uthread/uthread_sig.c266
-rw-r--r--lib/libpthread/uthread/uthread_sigmask.c4
-rw-r--r--lib/libpthread/uthread/uthread_sigwait.c7
7 files changed, 167 insertions, 383 deletions
diff --git a/lib/libpthread/uthread/pthread_private.h b/lib/libpthread/uthread/pthread_private.h
index 78d34b82804..cae2335ef0d 100644
--- a/lib/libpthread/uthread/pthread_private.h
+++ b/lib/libpthread/uthread/pthread_private.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pthread_private.h,v 1.41 2003/01/24 21:03:15 marc Exp $ */
+/* $OpenBSD: pthread_private.h,v 1.42 2003/01/27 22:22:30 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
@@ -624,7 +624,6 @@ struct pthread {
sigset_t sigmask;
sigset_t sigpend;
int sigmask_seqno;
- int check_pending;
/* Thread state: */
enum pthread_state state;
@@ -1016,14 +1015,7 @@ SCLASS volatile int _spinblock_count
/* Used to maintain pending and active signals: */
struct sigstatus {
int pending; /* Is this a pending signal? */
- int blocked; /*
- * A handler is currently active for
- * this signal; ignore subsequent
- * signals until the handler is done.
- */
- int signo; /* arg 1 to signal handler */
siginfo_t siginfo; /* arg 2 to signal handler */
- struct sigcontext uc; /* arg 3 to signal handler */
};
SCLASS struct sigstatus _thread_sigq[NSIG];
@@ -1095,11 +1087,11 @@ void _waitq_clearactive(void);
__dead void _thread_exit(const char *, int, const char *) __attribute__((__noreturn__));
void *_thread_cleanup(pthread_t);
void _thread_cleanupspecific(void);
+void _thread_clear_pending(int, pthread_t);
void _thread_dump_data(const void *, int);
void _thread_dump_info(void);
void _thread_init(void);
void _thread_kern_sched(struct sigcontext *);
-void _thread_kern_sched_sig(void);
void _thread_kern_sched_state(enum pthread_state,char *fname,int lineno);
void _thread_kern_sched_state_unlock(enum pthread_state state,
spinlock_t *lock, char *fname, int lineno);
@@ -1107,9 +1099,8 @@ void _thread_kern_set_timeout(const struct timespec *);
void _thread_kern_sig_defer(void);
void _thread_kern_sig_undefer(void);
void _thread_sig_handler(int, siginfo_t *, struct sigcontext *);
-void _thread_sig_handle(int, struct sigcontext *);
+int _thread_sig_handle(int, struct sigcontext *);
void _thread_sig_init(void);
-void _thread_sig_process(int, struct sigcontext *);
void _thread_start(void);
void _thread_start_sig_handler(void);
void _thread_seterrno(pthread_t,int);
diff --git a/lib/libpthread/uthread/uthread_kern.c b/lib/libpthread/uthread/uthread_kern.c
index 9930098a974..d72e7b5ed9e 100644
--- a/lib/libpthread/uthread/uthread_kern.c
+++ b/lib/libpthread/uthread/uthread_kern.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_kern.c,v 1.24 2003/01/24 21:03:15 marc Exp $ */
+/* $OpenBSD: uthread_kern.c,v 1.25 2003/01/27 22:22:30 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -50,12 +50,6 @@
#include <pthread.h>
#include "pthread_private.h"
-#if defined(PTHREAD_TRACE_KERN)
-#define PTHREAD_TRACE(x) _thread_sys_write(-1, (void*) x, 0)
-#else
-#define PTHREAD_TRACE(x)
-#endif
-
/*
* local functions. Do NOT make these static... we want so see them in
* crash dumps.
@@ -68,16 +62,6 @@ inline void _thread_run_switch_hook(pthread_t, pthread_t);
static int last_tick = 0;
void
-_thread_kern_sched_sig(void)
-{
- struct pthread *curthread = _get_curthread();
-
- PTHREAD_TRACE(1);
- curthread->check_pending = 1;
- _thread_kern_sched(NULL);
-}
-
-void
_thread_kern_sched(struct sigcontext * scp)
{
struct timespec ts;
@@ -88,8 +72,6 @@ _thread_kern_sched(struct sigcontext * scp)
int add_to_prioq;
pthread_t old_thread_run;
- PTHREAD_TRACE(2);
-
/*
* Flag the pthread kernel as executing scheduler code
* to avoid a scheduler signal from interrupting this
@@ -257,23 +239,6 @@ _thread_kern_sched(struct sigcontext * scp)
PTHREAD_WORKQ_INSERT(curthread);
break;
}
-
- /*
- * Are there pending signals for this thread?
- *
- * This check has to be performed after the thread
- * has been placed in the queue(s) appropriate for
- * its state. The process of adding pending signals
- * can change a threads state, which in turn will
- * attempt to add or remove the thread from any
- * scheduling queue to which it belongs.
- */
-#ifdef notyet
- if (curthread->check_pending != 0) {
- curthread->check_pending = 0;
- _thread_sig_check_pending(curthread);
- }
-#endif
}
/*
@@ -502,18 +467,10 @@ _thread_kern_sched(struct sigcontext * scp)
/* Restore floating point state. */
_thread_machdep_restore_float_state(&curthread->_machdep);
- /*
- * Restore the new thread, saving current.
- */
+ /* Restore the new thread, saving current. */
_thread_machdep_switch(&curthread->_machdep,
&old_thread_run->_machdep);
-
- /*
- * Process any pending signals for the thread we
- * just switched to.
- */
_thread_kern_in_sched = 0;
- _dispatch_signals(scp);
/* run any installed switch-hooks */
if ((_sched_switch_hook != NULL) &&
@@ -529,6 +486,10 @@ _thread_kern_sched(struct sigcontext * scp)
PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
pthread_testcancel();
+ /* dispatch any pending signals if possible */
+ if (curthread->sig_defer_count == 0)
+ _dispatch_signals(scp);
+
/* Check if a signal context was saved: */
if (curthread->sig_saved == 1) {
/* return to signal handler. This code
@@ -556,7 +517,6 @@ _thread_kern_sched_state(enum pthread_state state, char *fname, int lineno)
{
struct pthread *curthread = _get_curthread();
- PTHREAD_TRACE(3);
/*
* Flag the pthread kernel as executing scheduler code
* to avoid a scheduler signal from interrupting this
@@ -585,8 +545,6 @@ _thread_kern_sched_state_unlock(enum pthread_state state,
{
struct pthread *curthread = _get_curthread();
- PTHREAD_TRACE(4);
-
/*
* Flag the pthread kernel as executing scheduler code
* to avoid a scheduler signal from interrupting this
@@ -624,8 +582,6 @@ _thread_kern_poll(int wait_reqd)
struct timespec ts;
struct timeval tv;
- PTHREAD_TRACE(5);
-
/* Check if the caller wants to wait: */
if (wait_reqd == 0) {
timeout_ms = 0;
@@ -948,8 +904,6 @@ _thread_kern_set_timeout(const struct timespec * timeout)
struct timespec current_time;
struct timeval tv;
- PTHREAD_TRACE(6);
-
/* Reset the timeout flag for the running thread: */
curthread->timeout = 0;
@@ -990,8 +944,6 @@ _thread_kern_sig_defer(void)
{
struct pthread *curthread = _get_curthread();
- PTHREAD_TRACE(7);
-
/* Allow signal deferral to be recursive. */
curthread->sig_defer_count++;
}
@@ -1001,8 +953,6 @@ _thread_kern_sig_undefer(void)
{
struct pthread *curthread = _get_curthread();
- PTHREAD_TRACE(8);
-
/*
* Perform checks to yield only if we are about to undefer
* signals.
@@ -1049,8 +999,6 @@ _dequeue_signals(void)
char bufr[128];
int i, num;
- PTHREAD_TRACE(9);
-
/*
* Enter a loop to read and handle queued signals from the
* pthread kernel pipe:
@@ -1062,16 +1010,8 @@ _dequeue_signals(void)
* each byte is the signal number.
*/
for (i = 0; i < num; i++) {
- if ((int) bufr[i] == _SCHED_SIGNAL) {
- /*
- * Scheduling signals shouldn't ever be
- * queued; just ignore it for now.
- */
- }
- else {
- /* Handle this signal: */
- _thread_sig_process((int) bufr[i], NULL);
- }
+ if ((int) bufr[i] != _SCHED_SIGNAL)
+ _thread_sig_handle((int) bufr[i], NULL);
}
}
if ((num < 0) && (errno != EAGAIN)) {
@@ -1089,8 +1029,6 @@ _thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in)
pthread_t tid_out = thread_out;
pthread_t tid_in = thread_in;
- PTHREAD_TRACE(10);
-
if ((tid_out != NULL) &&
(tid_out->flags & PTHREAD_FLAGS_PRIVATE) != 0)
tid_out = NULL;
diff --git a/lib/libpthread/uthread/uthread_kill.c b/lib/libpthread/uthread/uthread_kill.c
index 59d78b80ebf..9e94a7f0ee4 100644
--- a/lib/libpthread/uthread/uthread_kill.c
+++ b/lib/libpthread/uthread/uthread_kill.c
@@ -1,37 +1,6 @@
-/* $OpenBSD: uthread_kill.c,v 1.8 2002/10/30 19:11:56 marc Exp $ */
-/*
- * Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
- * 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 John Birrell.
- * 4. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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.
- *
- * $FreeBSD: uthread_kill.c,v 1.9 1999/08/28 00:03:38 peter Exp $
- */
+/* $OpenBSD: uthread_kill.c,v 1.9 2003/01/27 22:22:30 marc Exp $ */
+/* PUBLIC_DOMAIN <marc@snafu.org> */
+
#include <errno.h>
#include <signal.h>
#ifdef _THREAD_SAFE
@@ -39,132 +8,29 @@
#include "pthread_private.h"
/*
- * XXX THIS IS WRONG! The signal has to either come through the OS to
- * get the proper siginfo, context, etc., or we need to gen up a
- * siginfo (assuming needed). Signal reset and other semantics
- * also need to be obeyed.
+ * Validate the signal number and thread. If valid process the signal.
+ * ;;; need to fake up a siginfo_t and put it in the queue for this signal.
*/
int
pthread_kill(pthread_t pthread, int sig)
{
int ret;
- /* Check for invalid signal numbers: */
- if (sig < 0 || sig >= NSIG)
- /* Invalid signal: */
- ret = EINVAL;
-
- /*
- * Ensure the thread is in the list of active threads, and the
- * signal is valid (signal 0 specifies error checking only) and
- * not being ignored:
- */
- else if (((ret = _find_thread(pthread)) == 0) && (sig > 0) &&
- (_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
- /*
- * Defer signals to protect the scheduling queues from
- * access by the signal handler:
- */
- _thread_kern_sig_defer();
-
- switch (pthread->state) {
- case PS_SIGSUSPEND:
- /*
- * Only wake up the thread if the signal is unblocked
- * and there is a handler installed for the signal.
- */
- if (!sigismember(&pthread->sigmask, sig) &&
- _thread_sigact[sig - 1].sa_handler != SIG_DFL) {
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
-
- /* Return the signal number: */
- pthread->signo = sig;
- }
- sigaddset(&pthread->sigpend,sig);
- break;
-
- case PS_SIGWAIT:
- /* Wake up the thread if the signal is blocked. */
- if (sigismember(pthread->data.sigwait, sig)) {
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
-
- /* Return the signal number: */
- pthread->signo = sig;
- } else
- sigaddset(&pthread->sigpend,sig);
- break;
-
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- case PS_POLL_WAIT:
- case PS_SLEEP_WAIT:
- case PS_SELECT_WAIT:
- if (!sigismember(&pthread->sigmask, sig) &&
- (_thread_sigact[sig - 1].sa_handler != SIG_IGN)) {
- /* Flag the operation as interrupted: */
- pthread->interrupted = 1;
-
- if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ)
- PTHREAD_WORKQ_REMOVE(pthread);
-
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
-
- /* Return the signal number: */
- pthread->signo = sig;
- } else {
- sigaddset(&pthread->sigpend,sig);
+ if (sig >= 0 && sig < NSIG) {
+ ret = _find_thread(pthread);
+ if (sig != 0) {
+ if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
+ if (pthread->state == PS_SIGWAIT &&
+ sigismember(pthread->data.sigwait, sig)) {
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ pthread->signo = sig;
+ } else
+ _thread_signal(pthread,sig);
}
- break;
-
- default:
- /* Increment the pending signal count: */
- sigaddset(&pthread->sigpend,sig);
- break;
}
+ } else
+ ret = EINVAL;
-
- /*
- * Check that a custom handler is installed
- * and if the signal is not blocked:
- */
- if (_thread_sigact[sig - 1].sa_handler != SIG_DFL &&
- _thread_sigact[sig - 1].sa_handler != SIG_IGN &&
- sigismember(&pthread->sigpend, sig) &&
- !sigismember(&pthread->sigmask, sig)) {
- pthread_t pthread_saved = _thread_run;
-
- /* Current thread inside critical region? */
- if (_thread_run->sig_defer_count > 0)
- pthread->sig_defer_count++;
-
- _thread_run = pthread;
-
- /* Clear the pending signal: */
- sigdelset(&pthread->sigpend, sig);
-
- /*
- * Dispatch the signal via the custom signal
- * handler: ;;; what about SA_SIGINFO???
- */
- (*(_thread_sigact[sig - 1].sa_handler))(sig);
-
- _thread_run = pthread_saved;
-
- if (_thread_run->sig_defer_count > 0)
- pthread->sig_defer_count--;
- }
-
- /*
- * Undefer and handle pending signals, yielding if
- * necessary:
- */
- _thread_kern_sig_undefer();
- }
-
- /* Return the completion status: */
- return (ret);
+ return ret;
}
#endif
diff --git a/lib/libpthread/uthread/uthread_mutex.c b/lib/libpthread/uthread/uthread_mutex.c
index 79bd3573379..5845cf01a6b 100644
--- a/lib/libpthread/uthread/uthread_mutex.c
+++ b/lib/libpthread/uthread/uthread_mutex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_mutex.c,v 1.15 2002/10/30 19:11:56 marc Exp $ */
+/* $OpenBSD: uthread_mutex.c,v 1.16 2003/01/27 22:22:30 marc Exp $ */
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
@@ -114,11 +114,11 @@ int
pthread_mutex_init(pthread_mutex_t * mutex,
const pthread_mutexattr_t * mutex_attr)
{
- enum pthread_mutextype type;
- int protocol;
- int ceiling;
- int flags;
pthread_mutex_t pmutex;
+ enum pthread_mutextype type = 0;
+ int protocol = 0;
+ int ceiling = 0;
+ int flags = 0;
int ret = 0;
if (mutex == NULL)
diff --git a/lib/libpthread/uthread/uthread_sig.c b/lib/libpthread/uthread/uthread_sig.c
index 17eef3fa38e..d833465bf3a 100644
--- a/lib/libpthread/uthread/uthread_sig.c
+++ b/lib/libpthread/uthread/uthread_sig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_sig.c,v 1.17 2003/01/24 21:03:15 marc Exp $ */
+/* $OpenBSD: uthread_sig.c,v 1.18 2003/01/27 22:22:30 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -41,11 +41,6 @@
#include <pthread.h>
#include "pthread_private.h"
-/* Static variables: */
-static _spinlock_lock_t signal_lock = _SPINLOCK_UNLOCKED;
-siginfo_t info_queue[NSIG];
-volatile sig_atomic_t pending_sigs[NSIG];
-volatile sig_atomic_t check_pending = 0;
/* Initialize signal handling facility: */
void
@@ -55,32 +50,8 @@ _thread_sig_init(void)
/* Clear local state */
for (i = 1; i < NSIG; i++) {
- pending_sigs[i - 1] = 0;
+ _thread_sigq[i - 1].pending = 0;
}
-
- /* Clear the lock: */
- signal_lock = _SPINLOCK_UNLOCKED;
-}
-
-/*
- * Process a pending signal unless it is already in progress. If the
- * SA_NODEFER flag is on, process it any way.
- */
-void
-_thread_sig_process(int sig, struct sigcontext * scp)
-{
- int locked = 0;
-
- if (_atomic_lock(&signal_lock) == 0)
- locked = 1;
-
- if (locked || _thread_sigact[sig - 1].sa_flags & SA_NODEFER) {
- pending_sigs[sig - 1] = 0;
- _thread_sig_handle(sig, scp);
- } else
- check_pending = 1;
- if (locked)
- signal_lock = _SPINLOCK_UNLOCKED;
}
/*
@@ -93,17 +64,6 @@ _thread_sig_handler(int sig, siginfo_t *info, struct sigcontext * scp)
{
struct pthread *curthread = _get_curthread();
char c;
- int i;
-
- /*
- * save the info for this signal in a per signal queue of depth
- * one. Per a POSIX suggestion, only the info for the first
- * of multiple activations of the same signal is kept.
- */
- if (pending_sigs[sig - 1] == 0) {
- pending_sigs[sig - 1]++;
- memcpy(&info_queue[sig - 1], info, sizeof *info);
- }
if (sig == _SCHED_SIGNAL) {
/* Update the scheduling clock: */
@@ -138,59 +98,68 @@ _thread_sig_handler(int sig, siginfo_t *info, struct sigcontext * scp)
return;
}
}
- } else if ((_queue_signals != 0) ||
- ((_thread_kern_in_sched == 0) &&
- (curthread->sig_defer_count > 0))) {
- /*
- * The kernel has been interrupted while the scheduler
- * is accessing the scheduling queues or there is a currently
- * running thread that has deferred signals.
- *
- * Cast the signal number to a character variable and Write
- * the signal number to the kernel pipe so that it will be
- * ready to read when this signal handler returns.
- */
- c = sig;
- _thread_sys_write(_thread_kern_pipe[1], &c, 1);
- _sigq_check_reqd = 1;
} else {
- /* process the signal */
- _thread_sig_process(sig, scp);
/*
- * process pending signals unless a current signal handler
- * is running (signal_lock is locked). When locked
- * the pending signals will be processed when the running
- * handler returns.
+ * save the info for this signal in a per signal queue of depth
+ * one. Per a POSIX suggestion, only the info for the first
+ * of multiple activations of the same signal is kept.
*/
- while (check_pending != 0 && _atomic_lock(&signal_lock) == 0) {
- check_pending = 0;
- signal_lock = _SPINLOCK_UNLOCKED;
- for (i = 1; i < NSIG; i++)
- if (pending_sigs[i - 1])
- _thread_sig_process(i, scp);
+ if (_thread_sigq[sig - 1].pending == 0) {
+ sigaddset(&_process_sigpending, sig);
+ _thread_sigq[sig - 1].pending++;
+ memcpy(&_thread_sigq[sig - 1].siginfo, info,
+ sizeof *info);
}
- }
+ if ((_queue_signals != 0) ||
+ ((_thread_kern_in_sched == 0) &&
+ (curthread->sig_defer_count > 0))) {
+ /*
+ * The kernel has been interrupted while the scheduler
+ * is accessing the scheduling queues or there is a
+ * currently running thread that has deferred signals.
+ *
+ * Cast the signal number to a character variable
+ * and Write the signal number to the kernel pipe so
+ * that it will be ready to read when this signal
+ * handler returns.
+ */
+ c = sig;
+ _thread_sys_write(_thread_kern_pipe[1], &c, 1);
+ _sigq_check_reqd = 1;
+ } else {
+ if (_thread_sig_handle(sig, scp))
+ _dispatch_signals(scp);
+ }
+ }
}
/*
* Clear the pending flag for the given signal on all threads
+ * if per process, or only for the given thread if non null
+ * and the signal doesn't exist in _process_sigpending.
*/
void
-_clear_pending_flag(int sig)
+_thread_clear_pending(int sig, pthread_t thread)
{
pthread_t pthread;
- TAILQ_FOREACH(pthread, &_thread_list, tle) {
- sigdelset(&pthread->sigpend, sig);
- }
+ if (sigismember(&_process_sigpending, sig)) {
+ _thread_sigq[sig - 1].pending = 0;
+ sigdelset(&_process_sigpending, sig);
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ sigdelset(&pthread->sigpend, sig);
+ }
+ } else if (thread)
+ sigdelset(&thread->sigpend, sig);
}
/*
- * Process the given signal.
+ * Process the given signal. Returns 1 if the signal may be dispatched,
+ * otherwise 0.
*/
-void
+int
_thread_sig_handle(int sig, struct sigcontext * scp)
{
struct pthread *curthread = _get_curthread();
@@ -216,11 +185,27 @@ _thread_sig_handle(int sig, struct sigcontext * scp)
}
/*
- * POSIX says that pending SIGCONT signals are
- * discarded when one of these signals occurs.
+ * If the handler is SIG_IGN the signal never happened.
+ * remove it from the pending list and return.
+ */
+ if (_thread_sigact[sig - 1].sa_handler == SIG_IGN) {
+ _thread_clear_pending(sig, curthread);
+ return 0;
+ }
+
+ /*
+ * POSIX says that pending SIGCONT signals are discarded
+ * when one of these signals occurs and vice versa.
*/
- if (sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
- _clear_pending_flag(SIGCONT);
+ if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN ||
+ sig == SIGTTOU)
+ _thread_clear_pending(SIGCONT, curthread);
+ if (sig == SIGCONT) {
+ _thread_clear_pending(SIGSTOP, curthread);
+ _thread_clear_pending(SIGTSTP, curthread);
+ _thread_clear_pending(SIGTTIN, curthread);
+ _thread_clear_pending(SIGTTOU, curthread);
+ }
/*
* Enter a loop to process each thread in the waiting
@@ -239,61 +224,49 @@ _thread_sig_handle(int sig, struct sigcontext * scp)
if ((pthread->state == PS_SIGWAIT) &&
sigismember(pthread->data.sigwait, sig)) {
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
-
- /* Return the signal number: */
- pthread->signo = sig;
-
/*
- * Do not attempt to deliver this signal
- * to other threads.
+ * found a sigwaiter. Mark its state as
+ * running, save the signal that will be
+ * returned, and mark the signal as no
+ * longer pending.
*/
- return;
+ PTHREAD_NEW_STATE(pthread,PS_RUNNING);
+ pthread->signo = sig;
+ _thread_clear_pending(sig, pthread);
+ return 0;
}
}
- if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) {
- /*
- * mark the signal as pending for each thread
- * and give the thread a chance to update
- * its state.
- */
- TAILQ_FOREACH(pthread, &_thread_list, tle) {
- /* Current thread inside critical region? */
- if (curthread->sig_defer_count > 0)
- pthread->sig_defer_count++;
- _thread_signal(pthread,sig);
- if (curthread->sig_defer_count > 0)
- pthread->sig_defer_count--;
- }
- /*
- * Give the current thread a chance to dispatch
- * the signals. Other threads will get thier
- * chance (if the signal is still pending) later.
- */
- _dispatch_signals(scp);
-
+ /*
+ * mark the signal as pending for each thread
+ * and give the thread a chance to update
+ * its state.
+ */
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ /* Current thread inside critical region? */
+ if (curthread->sig_defer_count > 0)
+ pthread->sig_defer_count++;
+ _thread_signal(pthread,sig);
+ if (curthread->sig_defer_count > 0)
+ pthread->sig_defer_count--;
}
+ return 1;
}
+ return 0;
}
/* Perform thread specific actions in response to a signal: */
void
_thread_signal(pthread_t pthread, int sig)
{
- /*
- * Flag the signal as pending. It may be dispatched later.
- */
+ /* Flag the signal as pending. It may be dispatched later. */
sigaddset(&pthread->sigpend,sig);
/* skip this thread if signal is masked */
if (sigismember(&pthread->sigmask, sig))
return;
- /*
- * Process according to thread state:
- */
+ /* Process according to thread state: */
switch (pthread->state) {
/*
* States which do not change when a signal is trapped:
@@ -377,14 +350,49 @@ _thread_signal(pthread_t pthread, int sig)
}
/*
- * possibly dispatch a signal to the current thread.
+ * Dispatch a signal to the current thread after setting up the
+ * appropriate signal mask.
*/
void
-_dispatch_signals(struct sigcontext * scp)
+_dispatch_signal(int sig, struct sigcontext * scp)
{
struct pthread *curthread = _get_curthread();
+
+ sigset_t set;
+ sigset_t oset;
struct sigaction act;
void (*action)(int, siginfo_t *, void *);
+
+ _thread_clear_pending(sig, curthread);
+
+ /* save off the action and set the signal mask */
+ action = _thread_sigact[sig - 1].sa_sigaction;
+ set = _thread_sigact[sig - 1].sa_mask;
+ if ((_thread_sigact[sig-1].sa_flags & SA_NODEFER) == 0)
+ sigaddset(&set, sig);
+ oset = curthread->sigmask;
+ curthread->sigmask |= set;
+
+ /* clear custom handler if SA_RESETHAND set. */
+ if (_thread_sigact[sig - 1].sa_flags & SA_RESETHAND) {
+ act.sa_handler = SIG_DFL;
+ act.sa_flags = 0;
+ sigemptyset(&act.sa_mask);
+ sigaction(sig, &act, NULL);
+ }
+
+ /* call the action and reset the signal mask */
+ (*action)(sig, &_thread_sigq[sig - 1].siginfo, scp);
+ curthread->sigmask = oset;
+}
+
+/*
+ * possibly dispatch a signal to the current thread.
+ */
+void
+_dispatch_signals(struct sigcontext * scp)
+{
+ struct pthread *curthread = _get_curthread();
int i;
/*
@@ -401,24 +409,8 @@ _dispatch_signals(struct sigcontext * scp)
if (_thread_sigact[i - 1].sa_handler != SIG_DFL &&
_thread_sigact[i - 1].sa_handler != SIG_IGN &&
sigismember(&curthread->sigpend,i) &&
- !sigismember(&curthread->sigmask,i)) {
- action = _thread_sigact[i - 1].sa_sigaction;
- _clear_pending_flag(i);
-
- /* clear custom handler if SA_RESETHAND set. */
- if (_thread_sigact[i - 1].sa_flags &
- SA_RESETHAND) {
- act.sa_handler = SIG_DFL;
- act.sa_flags = 0;
- sigemptyset(&act.sa_mask);
- sigaction(i, &act, NULL);
- }
-
- /*
- * Dispatch the signal via the custom signal
- * handler.
- */
- (*action)(i, &info_queue[i - 1], scp);
- }
+ !sigismember(&curthread->sigmask,i))
+ /* dispatch */
+ _dispatch_signal(i, scp);
}
#endif
diff --git a/lib/libpthread/uthread/uthread_sigmask.c b/lib/libpthread/uthread/uthread_sigmask.c
index 12dd6ec3c69..0b2e54e0652 100644
--- a/lib/libpthread/uthread/uthread_sigmask.c
+++ b/lib/libpthread/uthread/uthread_sigmask.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_sigmask.c,v 1.5 2002/02/21 20:57:41 fgsch Exp $ */
+/* $OpenBSD: uthread_sigmask.c,v 1.6 2003/01/27 22:22:30 marc Exp $ */
/*
* Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
@@ -95,7 +95,7 @@ pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
* Call the kernel scheduler which will safely
* install a signal frame for the running thread:
*/
- _thread_kern_sched_sig();
+ _thread_kern_sched(NULL);
}
/* Return the completion status: */
diff --git a/lib/libpthread/uthread/uthread_sigwait.c b/lib/libpthread/uthread/uthread_sigwait.c
index b7b72c7ea09..6e4bc5fc8a9 100644
--- a/lib/libpthread/uthread/uthread_sigwait.c
+++ b/lib/libpthread/uthread/uthread_sigwait.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_sigwait.c,v 1.11 2002/10/30 19:11:56 marc Exp $ */
+/* $OpenBSD: uthread_sigwait.c,v 1.12 2003/01/27 22:22:30 marc Exp $ */
/*
* Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
@@ -82,10 +82,7 @@ sigwait(const sigset_t * set, int *sig)
}
/* Clear the pending signal: */
- if (sigismember(&curthread->sigpend, i))
- sigdelset(&curthread->sigpend, i);
- else
- sigdelset(&_process_sigpending, i);
+ _thread_clear_pending(i, curthread);
/* Return the signal number to the caller: */
*sig = i;