summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormini <mini@FreeBSD.org>2003-02-17 10:05:18 +0000
committermini <mini@FreeBSD.org>2003-02-17 10:05:18 +0000
commitf410bbff9bdafda36fadec4dfcd193618bf28eaf (patch)
treec24155922d6dce25dde63eab941dbc318206ebdf
parent6ebeaa8ec8a84c0fe2ebf0392ae3386ba9840a81 (diff)
downloadFreeBSD-src-f410bbff9bdafda36fadec4dfcd193618bf28eaf.zip
FreeBSD-src-f410bbff9bdafda36fadec4dfcd193618bf28eaf.tar.gz
Deliver signals posted via an upcall to the appropriate thread.
-rw-r--r--lib/libkse/thread/thr_cancel.c2
-rw-r--r--lib/libkse/thread/thr_init.c31
-rw-r--r--lib/libkse/thread/thr_kern.c9
-rw-r--r--lib/libkse/thread/thr_private.h30
-rw-r--r--lib/libkse/thread/thr_sig.c725
-rw-r--r--lib/libkse/thread/thr_sigpending.c2
-rw-r--r--lib/libpthread/thread/thr_cancel.c2
-rw-r--r--lib/libpthread/thread/thr_init.c31
-rw-r--r--lib/libpthread/thread/thr_kern.c9
-rw-r--r--lib/libpthread/thread/thr_private.h30
-rw-r--r--lib/libpthread/thread/thr_sig.c725
-rw-r--r--lib/libpthread/thread/thr_sigpending.c2
12 files changed, 548 insertions, 1050 deletions
diff --git a/lib/libkse/thread/thr_cancel.c b/lib/libkse/thread/thr_cancel.c
index e4e0216..8b0b4c0 100644
--- a/lib/libkse/thread/thr_cancel.c
+++ b/lib/libkse/thread/thr_cancel.c
@@ -51,6 +51,8 @@ _pthread_cancel(pthread_t pthread)
/* Fall through: */
case PS_SLEEP_WAIT:
case PS_WAIT_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SIGWAIT:
/* Interrupt and resume: */
pthread->interrupted = 1;
pthread->cancelflags |= PTHREAD_CANCELLING;
diff --git a/lib/libkse/thread/thr_init.c b/lib/libkse/thread/thr_init.c
index 9f2f894..8e19924 100644
--- a/lib/libkse/thread/thr_init.c
+++ b/lib/libkse/thread/thr_init.c
@@ -162,6 +162,12 @@ _thread_init(void)
int sched_stack_size; /* Size of scheduler stack. */
struct clockinfo clockinfo;
+ struct sigaction act;
+
+ /* Check if this function has already been called: */
+ if (_thread_initial)
+ /* Only initialise the threaded application once. */
+ return;
_pthread_page_size = getpagesize();
_pthread_guard_default = getpagesize();
@@ -338,6 +344,31 @@ _thread_init(void)
TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle);
_set_curthread(_thread_initial);
+ /* Clear the pending signals for the process. */
+ sigemptyset(&_thread_sigpending);
+
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i < NSIG; i++) {
+ /* Check for signals which cannot be trapped. */
+ if (i == SIGKILL || i == SIGSTOP)
+ continue;
+
+ /* Get the signal handler details. */
+ if (__sys_sigaction(i, NULL,
+ &_thread_sigact[i - 1]) != 0)
+ PANIC("Cannot read signal handler info");
+ }
+
+ /* Register SIGCHLD (needed for wait(2)). */
+ sigfillset(&act.sa_mask);
+ act.sa_handler = (void (*) ()) _thread_sig_handler;
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ if (__sys_sigaction(SIGCHLD, &act, NULL) != 0)
+ PANIC("Can't initialize signal handler");
+
+ /* Get the process signal mask. */
+ __sys_sigprocmask(SIG_SETMASK, NULL, &_thread_sigmask);
+
/* Get the kernel clockrate: */
mib[0] = CTL_KERN;
mib[1] = KERN_CLOCKRATE;
diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c
index 0747cff..c14d44a 100644
--- a/lib/libkse/thread/thr_kern.c
+++ b/lib/libkse/thread/thr_kern.c
@@ -248,6 +248,8 @@ _thread_kern_scheduler(struct kse_mailbox *km)
pthread_t td, pthread, pthread_h;
unsigned int current_tick;
struct kse_thr_mailbox *tm, *p;
+ sigset_t sigset;
+ int i;
DBG_MSG("entering\n");
while (!TAILQ_EMPTY(&_thread_list)) {
@@ -280,8 +282,13 @@ _thread_kern_scheduler(struct kse_mailbox *km)
}
/* Deliver posted signals. */
- /* XXX: Not yet. */
DBG_MSG("Picking up signals\n");
+ bcopy(&km->km_sigscaught, &sigset, sizeof(sigset_t));
+ sigemptyset(&km->km_sigscaught); /* XXX */
+ if (SIGNOTEMPTY(sigset))
+ for (i = 1; i < NSIG; i++)
+ if (sigismember(&sigset, i) != 0)
+ _thread_sig_dispatch(i);
if (_spinblock_count != 0) {
/*
diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h
index 8aacdc0..7c5cc87 100644
--- a/lib/libkse/thread/thr_private.h
+++ b/lib/libkse/thread/thr_private.h
@@ -426,6 +426,8 @@ enum pthread_state {
PS_COND_WAIT,
PS_SLEEP_WAIT,
PS_WAIT_WAIT,
+ PS_SIGSUSPEND,
+ PS_SIGWAIT,
PS_SPINBLOCK,
PS_JOIN,
PS_SUSPENDED,
@@ -445,6 +447,7 @@ enum pthread_state {
union pthread_wait_data {
pthread_mutex_t mutex;
pthread_cond_t cond;
+ const sigset_t *sigwait; /* Waiting on a signal in sigwait */
spinlock_t *spinlock;
struct pthread *thread;
};
@@ -461,6 +464,15 @@ struct join_status {
int error;
};
+struct pthread_state_data {
+ struct timespec psd_wakeup_time;
+ union pthread_wait_data psd_wait_data;
+ enum pthread_state psd_state;
+ int psd_flags;
+ int psd_interrupted;
+ int psd_sig_defer_count;
+};
+
struct pthread_specific_elem {
const void *data;
int seqno;
@@ -515,6 +527,9 @@ struct pthread {
thread_continuation_t continuation;
+ /* Currently pending signals. */
+ sigset_t sigpend;
+
/* Thread state: */
enum pthread_state state;
@@ -590,6 +605,9 @@ struct pthread {
*/
int interrupted;
+ /* Signal number when in state PS_SIGWAIT: */
+ int signo;
+
/*
* Set to non-zero when this thread has deferred signals.
* We allow for recursive deferral.
@@ -774,6 +792,11 @@ SCLASS pthread_cond_t _gc_cond
;
/*
+ * Array of signal actions for this process.
+ */
+SCLASS struct sigaction _thread_sigact[NSIG];
+
+/*
* Scheduling queues:
*/
SCLASS pq_queue_t _readyq;
@@ -799,6 +822,12 @@ SCLASS pthread_switch_routine_t _sched_switch_hook
;
/*
+ * Signals pending and masked.
+ */
+SCLASS sigset_t _thread_sigpending;
+SCLASS sigset_t _thread_sigmask;
+
+/*
* Declare the kernel scheduler jump buffer and stack:
*/
SCLASS struct kse_mailbox _thread_kern_kse_mailbox;
@@ -893,6 +922,7 @@ void _thread_kern_sched_state_unlock(enum pthread_state state,
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 *, ucontext_t *);
void _thread_printf(int fd, const char *, ...);
void _thread_start(void);
void _thread_seterrno(pthread_t, int);
diff --git a/lib/libkse/thread/thr_sig.c b/lib/libkse/thread/thr_sig.c
index 5baaab9..a93b406 100644
--- a/lib/libkse/thread/thr_sig.c
+++ b/lib/libkse/thread/thr_sig.c
@@ -43,262 +43,62 @@
#include "thr_private.h"
/* Prototypes: */
+static void thread_sig_handle_special(int sig);
+
static void thread_sig_add(struct pthread *pthread, int sig, int has_args);
static void thread_sig_check_state(struct pthread *pthread, int sig);
static struct pthread *thread_sig_find(int sig);
-static void thread_sig_handle_special(int sig);
static void thread_sigframe_add(struct pthread *thread, int sig,
int has_args);
static void thread_sigframe_save(struct pthread *thread,
- struct pthread_signal_frame *psf);
-static void thread_sig_invoke_handler(int sig, siginfo_t *info,
- ucontext_t *ucp);
+ struct pthread_state_data *psd);
+static void thread_sigframe_restore(struct pthread *thread,
+ struct pthread_state_data *psd);
-/*#define DEBUG_SIGNAL*/
+/* #define DEBUG_SIGNAL */
#ifdef DEBUG_SIGNAL
#define DBG_MSG stdout_debug
#else
#define DBG_MSG(x...)
#endif
-#if defined(_PTHREADS_INVARIANTS)
-#define SIG_SET_ACTIVE() _sig_in_handler = 1
-#define SIG_SET_INACTIVE() _sig_in_handler = 0
-#else
-#define SIG_SET_ACTIVE()
-#define SIG_SET_INACTIVE()
-#endif
-
+/*
+ * Dispatch a signal to a thread, if appropriate.
+ */
void
-_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+_thread_sig_dispatch(int sig)
{
- struct pthread *curthread = _get_curthread();
- struct pthread *pthread, *pthread_h;
- int in_sched = _thread_kern_in_sched;
- char c;
-
- if (ucp == NULL)
- PANIC("Thread signal handler received null context");
- DBG_MSG("Got signal %d, current thread %p\n", sig, curthread);
-
- /* Check if an interval timer signal: */
- if (sig == _SCHED_SIGNAL) {
- /* Update the scheduling clock: */
- gettimeofday((struct timeval *)&_sched_tod, NULL);
- _sched_ticks++;
-
- if (in_sched != 0) {
- /*
- * The scheduler is already running; ignore this
- * signal.
- */
- }
- /*
- * Check if the scheduler interrupt has come when
- * the currently running thread has deferred thread
- * signals.
- */
- else if (curthread->sig_defer_count > 0)
- curthread->yield_on_sig_undefer = 1;
- else {
- /* Schedule the next thread: */
- _thread_kern_sched(ucp);
-
- /*
- * This point should not be reached, so abort the
- * process:
- */
- PANIC("Returned to signal function from scheduler");
- }
- }
- /*
- * Check if the kernel has been interrupted while the scheduler
- * is accessing the scheduling queues or if there is a currently
- * running thread that has deferred signals.
- */
- else if ((in_sched != 0) || (curthread->sig_defer_count > 0)) {
- /* Cast the signal number to a character variable: */
- c = sig;
-
- /*
- * Write the signal number to the kernel pipe so that it will
- * be ready to read when this signal handler returns.
- */
- if (_queue_signals != 0) {
- __sys_write(_thread_kern_pipe[1], &c, 1);
- DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig);
- }
- if (_thread_sigq[sig - 1].blocked == 0) {
- DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig);
- /*
- * Do not block this signal; it will be blocked
- * when the pending signals are run down.
- */
- /* _thread_sigq[sig - 1].blocked = 1; */
-
- /*
- * Queue the signal, saving siginfo and sigcontext
- * (ucontext).
- *
- * XXX - Do we need to copy siginfo and ucp?
- */
- _thread_sigq[sig - 1].signo = sig;
- if (info != NULL)
- memcpy(&_thread_sigq[sig - 1].siginfo, info,
- sizeof(*info));
- memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
-
- /* Indicate that there are queued signals: */
- _thread_sigq[sig - 1].pending = 1;
- _sigq_check_reqd = 1;
- }
- /* These signals need special handling: */
- else if (sig == SIGCHLD || sig == SIGTSTP ||
- sig == SIGTTIN || sig == SIGTTOU) {
- _thread_sigq[sig - 1].pending = 1;
- _thread_sigq[sig - 1].signo = sig;
- _sigq_check_reqd = 1;
- }
- else
- DBG_MSG("Got signal %d, ignored.\n", sig);
- }
- /*
- * The signal handlers should have been installed so that they
- * cannot be interrupted by other signals.
- */
- else if (_thread_sigq[sig - 1].blocked == 0) {
- /*
- * The signal is not blocked; handle the signal.
- *
- * Ignore subsequent occurrences of this signal
- * until the current signal is handled:
- */
- _thread_sigq[sig - 1].blocked = 1;
-
- /* This signal will be handled; clear the pending flag: */
- _thread_sigq[sig - 1].pending = 0;
-
- /*
- * Save siginfo and sigcontext (ucontext).
- *
- * XXX - Do we need to copy siginfo and ucp?
- */
- _thread_sigq[sig - 1].signo = sig;
-
- if (info != NULL)
- memcpy(&_thread_sigq[sig - 1].siginfo, info,
- sizeof(*info));
- memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
- SIG_SET_ACTIVE();
-
- /* Handle special signals: */
- thread_sig_handle_special(sig);
-
- pthread_h = NULL;
- if ((pthread = thread_sig_find(sig)) == NULL)
- DBG_MSG("No thread to handle signal %d\n", sig);
- else if (pthread == curthread) {
- /*
- * Unblock the signal and restore the process signal
- * mask in case we don't return from the handler:
- */
- _thread_sigq[sig - 1].blocked = 0;
- __sys_sigprocmask(SIG_SETMASK, &_process_sigmask, NULL);
-
- /* Call the signal handler for the current thread: */
- thread_sig_invoke_handler(sig, info, ucp);
-
- /*
- * Set the process signal mask in the context; it
- * could have changed by the handler.
- */
- ucp->uc_sigmask = _process_sigmask;
-
- /* Resume the interrupted thread: */
- __sys_sigreturn(ucp);
- } else {
- DBG_MSG("Got signal %d, adding frame to thread %p\n",
- sig, pthread);
-
- /* Setup the target thread to receive the signal: */
- thread_sig_add(pthread, sig, /*has_args*/ 1);
-
- /* Take a peek at the next ready to run thread: */
- pthread_h = PTHREAD_PRIOQ_FIRST();
- DBG_MSG("Finished adding frame, head of prio list %p\n",
- pthread_h);
- }
- SIG_SET_INACTIVE();
+ struct pthread *pthread;
- /*
- * Switch to a different context if the currently running
- * thread takes a signal, or if another thread takes a
- * signal and the currently running thread is not in a
- * signal handler.
- */
- if ((pthread_h != NULL) &&
- (pthread_h->active_priority > curthread->active_priority)) {
- /* Enter the kernel scheduler: */
- _thread_kern_sched(ucp);
- }
- }
- else {
- SIG_SET_ACTIVE();
- thread_sig_handle_special(sig);
- SIG_SET_INACTIVE();
- }
-}
+ DBG_MSG(">>> _thread_sig_dispatch(%d)\n", sig);
-static void
-thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp)
- {
- struct pthread *curthread = _get_curthread();
- void (*sigfunc)(int, siginfo_t *, void *);
- int saved_seqno;
- sigset_t saved_sigmask;
+ thread_sig_handle_special(sig);
+ if (sigismember(&_thread_sigmask, sig))
+ /* Don't deliver the signal if it's masked. */
+ return;
+ /* Mask the signal until it's handled. */
+ sigaddset(&_thread_sigmask, sig);
+ /* This signal will be handled; clear the pending flag. */
+ sigdelset(&_thread_sigpending, sig);
- /* Invoke the signal handler without going through the scheduler:
- */
- DBG_MSG("Got signal %d, calling handler for current thread %p\n",
- sig, curthread);
-
- /* Save the threads signal mask: */
- saved_sigmask = curthread->sigmask;
- saved_seqno = curthread->sigmask_seqno;
-
- /* Setup the threads signal mask: */
- SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
- sigaddset(&curthread->sigmask, sig);
-
/*
- * Check that a custom handler is installed and if
- * the signal is not blocked:
+ * Deliver the signal to a thread.
*/
- sigfunc = _thread_sigact[sig - 1].sa_sigaction;
- if (((__sighandler_t *)sigfunc != SIG_DFL) &&
- ((__sighandler_t *)sigfunc != SIG_IGN)) {
- if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
- (info == NULL))
- (*(sigfunc))(sig, info, ucp);
- else
- (*(sigfunc))(sig, (siginfo_t *)info->si_code, ucp);
+ if ((pthread = thread_sig_find(sig)) == NULL) {
+ DBG_MSG("No thread to handle signal %d\n", sig);
+ return;
}
- /*
- * Only restore the signal mask if it hasn't been changed by the
- * application during invocation of the signal handler:
- */
- if (curthread->sigmask_seqno == saved_seqno)
- curthread->sigmask = saved_sigmask;
+ DBG_MSG("Got signal %d, selecting thread %p\n", sig, pthread);
+ thread_sig_add(pthread, sig, /*has_args*/ 1);
}
/*
* Find a thread that can handle the signal.
*/
-struct pthread *
+static struct pthread *
thread_sig_find(int sig)
{
struct pthread *curthread = _get_curthread();
- int handler_installed;
struct pthread *pthread, *pthread_next;
struct pthread *suspended_thread, *signaled_thread;
@@ -309,138 +109,116 @@ thread_sig_find(int sig)
_thread_dump_info();
/* Unblock this signal to allow further dumps: */
- _thread_sigq[sig - 1].blocked = 0;
+ sigdelset(&_thread_sigmask, sig);
}
- /* Check if an interval timer signal: */
- else if (sig == _SCHED_SIGNAL) {
- /*
- * This shouldn't ever occur (should this panic?).
- */
- } else {
+
+ /*
+ * Enter a loop to look for threads that have the signal
+ * unmasked. POSIX specifies that a thread in a sigwait
+ * will get the signal over any other threads. Second
+ * preference will be threads in in a sigsuspend. Third
+ * preference will be the current thread. If none of the
+ * above, then the signal is delivered to the first thread
+ * that is found. Note that if a custom handler is not
+ * installed, the signal only affects threads in sigwait.
+ */
+ suspended_thread = NULL;
+ if ((curthread != &_thread_kern_thread) &&
+ !sigismember(&curthread->mailbox.tm_context.uc_sigmask, sig))
+ signaled_thread = curthread;
+ else
+ signaled_thread = NULL;
+
+ for (pthread = TAILQ_FIRST(&_waitingq);
+ pthread != NULL; pthread = pthread_next) {
/*
- * Enter a loop to look for threads that have the signal
- * unmasked. POSIX specifies that a thread in a sigwait
- * will get the signal over any other threads. Second
- * preference will be threads in in a sigsuspend. Third
- * preference will be the current thread. If none of the
- * above, then the signal is delivered to the first thread
- * that is found. Note that if a custom handler is not
- * installed, the signal only affects threads in sigwait.
+ * Grab the next thread before possibly destroying
+ * the link entry.
*/
- suspended_thread = NULL;
- if ((curthread != &_thread_kern_thread) &&
- !sigismember(&curthread->sigmask, sig))
- signaled_thread = curthread;
- else
- signaled_thread = NULL;
- if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) ||
- (_thread_sigact[sig - 1].sa_handler == SIG_DFL))
- handler_installed = 0;
- else
- handler_installed = 1;
+ pthread_next = TAILQ_NEXT(pthread, pqe);
+
+ if ((pthread->state == PS_SIGWAIT) &&
+ sigismember(pthread->data.sigwait, sig)) {
+ /* Change the state of the thread to run: */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
- for (pthread = TAILQ_FIRST(&_waitingq);
- pthread != NULL; pthread = pthread_next) {
/*
- * Grab the next thread before possibly destroying
- * the link entry.
+ * A signal handler is not invoked for threads
+ * in sigwait. Clear the blocked and pending
+ * flags.
*/
- pthread_next = TAILQ_NEXT(pthread, pqe);
+ sigdelset(&_thread_sigmask, sig);
+ sigdelset(&_thread_sigpending, sig);
- if ((pthread->state == PS_SIGWAIT) &&
- sigismember(pthread->data.sigwait, sig)) {
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
- /*
- * A signal handler is not invoked for threads
- * in sigwait. Clear the blocked and pending
- * flags.
- */
- _thread_sigq[sig - 1].blocked = 0;
- _thread_sigq[sig - 1].pending = 0;
-
- /* Return the signal number: */
- pthread->signo = sig;
+ /* Return the signal number: */
+ pthread->signo = sig;
- /*
- * POSIX doesn't doesn't specify which thread
- * will get the signal if there are multiple
- * waiters, so we give it to the first thread
- * we find.
- *
- * Do not attempt to deliver this signal
- * to other threads and do not add the signal
- * to the process pending set.
- */
- return (NULL);
- }
- else if ((handler_installed != 0) &&
- !sigismember(&pthread->sigmask, sig) &&
- ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
- if (pthread->state == PS_SIGSUSPEND) {
- if (suspended_thread == NULL)
- suspended_thread = pthread;
- } else if (signaled_thread == NULL)
- signaled_thread = pthread;
- }
+ /*
+ * POSIX doesn't doesn't specify which thread
+ * will get the signal if there are multiple
+ * waiters, so we give it to the first thread
+ * we find.
+ *
+ * Do not attempt to deliver this signal
+ * to other threads and do not add the signal
+ * to the process pending set.
+ */
+ return (NULL);
+ }
+ if (!sigismember(
+ &pthread->mailbox.tm_context.uc_sigmask, sig) &&
+ ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
+ if (pthread->state == PS_SIGSUSPEND) {
+ if (suspended_thread == NULL)
+ suspended_thread = pthread;
+ } else if (signaled_thread == NULL)
+ signaled_thread = pthread;
}
+ }
+ /*
+ * If we didn't find a thread in the waiting queue,
+ * check the all threads queue:
+ */
+ if (suspended_thread == NULL &&
+ signaled_thread == NULL) {
/*
- * Only perform wakeups and signal delivery if there is a
- * custom handler installed:
+ * Enter a loop to look for other threads
+ * capable of receiving the signal:
*/
- if (handler_installed == 0) {
- /*
- * There is no handler installed. Unblock the
- * signal so that if a handler _is_ installed, any
- * subsequent signals can be handled.
- */
- _thread_sigq[sig - 1].blocked = 0;
- } else {
- /*
- * If we didn't find a thread in the waiting queue,
- * check the all threads queue:
- */
- if (suspended_thread == NULL &&
- signaled_thread == NULL) {
- /*
- * Enter a loop to look for other threads
- * capable of receiving the signal:
- */
- TAILQ_FOREACH(pthread, &_thread_list, tle) {
- if (!sigismember(&pthread->sigmask,
- sig)) {
- signaled_thread = pthread;
- break;
- }
- }
- }
-
- if (suspended_thread == NULL &&
- signaled_thread == NULL)
- /*
- * Add it to the set of signals pending
- * on the process:
- */
- sigaddset(&_process_sigpending, sig);
- else {
- /*
- * We only deliver the signal to one thread;
- * give preference to the suspended thread:
- */
- if (suspended_thread != NULL)
- pthread = suspended_thread;
- else
- pthread = signaled_thread;
- return (pthread);
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (!sigismember(
+ &pthread->mailbox.tm_context.uc_sigmask, sig)) {
+ signaled_thread = pthread;
+ break;
}
}
}
+ if (suspended_thread == NULL &&
+ signaled_thread == NULL)
+ /*
+ * Add it to the set of signals pending
+ * on the process:
+ */
+ sigaddset(&_thread_sigpending, sig);
+ else {
+ /*
+ * We only deliver the signal to one thread;
+ * give preference to the suspended thread:
+ */
+ if (suspended_thread != NULL)
+ pthread = suspended_thread;
+ else
+ pthread = signaled_thread;
+ return (pthread);
+ }
+
/* Returns nothing. */
return (NULL);
}
+#if __XXX_NOT_YET__
void
_thread_sig_check_pending(struct pthread *pthread)
{
@@ -452,8 +230,9 @@ _thread_sig_check_pending(struct pthread *pthread)
* thread or process that aren't blocked:
*/
sigset = pthread->sigpend;
- SIGSETOR(sigset, _process_sigpending);
+ SIGSETOR(sigset, _thread_sigpending);
SIGSETNAND(sigset, pthread->sigmask);
+ SIGSETNAND(sigset, _thread_sigmask);
if (SIGNOTEMPTY(sigset)) {
for (i = 1; i < NSIG; i++) {
if (sigismember(&sigset, i) != 0) {
@@ -463,13 +242,15 @@ _thread_sig_check_pending(struct pthread *pthread)
else {
thread_sig_add(pthread, i,
/*has_args*/ 1);
- sigdelset(&_process_sigpending, i);
+ sigdelset(&_thread_sigpending, i);
}
}
}
}
}
+#endif
+#if __XXX_NOT_YET__
/*
* This can only be called from the kernel scheduler. It assumes that
* all thread contexts are saved and that a signal frame can safely be
@@ -479,30 +260,20 @@ void
_thread_sig_handle_pending(void)
{
struct pthread *pthread;
- int i, sig;
+ int sig;
- PTHREAD_ASSERT(_thread_kern_in_sched != 0,
- "_thread_sig_handle_pending called from outside kernel schedule");
/*
* Check the array of pending signals:
*/
- for (i = 0; i < NSIG; i++) {
- if (_thread_sigq[i].pending != 0) {
+ for (sig = 1; sig <= NSIG; sig++) {
+ if (sigismember(&_thread_sigpending, sig)) {
/* This signal is no longer pending. */
- _thread_sigq[i].pending = 0;
-
- sig = _thread_sigq[i].signo;
-
- /* Some signals need special handling: */
+ sigdelset(&_thread_sigpending, sig);
+ /* Some signals need special handling. */
thread_sig_handle_special(sig);
-
- if (_thread_sigq[i].blocked == 0) {
- /*
- * Block future signals until this one
- * is handled:
- */
- _thread_sigq[i].blocked = 1;
-
+ /* Deliver the signal. */
+ if (sigismember(&_thread_sigmask, sig)) {
+ sigaddset(&_thread_sigmask, sig);
if ((pthread = thread_sig_find(sig)) != NULL) {
/*
* Setup the target thread to receive
@@ -515,7 +286,12 @@ _thread_sig_handle_pending(void)
}
}
}
+#endif
+/*
+ * Do special processing to the thread states before we deliver
+ * a signal to the application.
+ */
static void
thread_sig_handle_special(int sig)
{
@@ -525,21 +301,6 @@ thread_sig_handle_special(int sig)
switch (sig) {
case SIGCHLD:
/*
- * Go through the file list and set all files
- * to non-blocking again in case the child
- * set some of them to block. Sigh.
- */
- for (i = 0; i < _thread_dtablesize; i++) {
- /* Check if this file is used: */
- if (_thread_fd_table[i] != NULL) {
- /*
- * Set the file descriptor to non-blocking:
- */
- __sys_fcntl(i, F_SETFL,
- _thread_fd_getflags(i) | O_NONBLOCK);
- }
- }
- /*
* Enter a loop to wake up all threads waiting
* for a process to complete:
*/
@@ -595,12 +356,9 @@ thread_sig_handle_special(int sig)
static void
thread_sig_add(struct pthread *pthread, int sig, int has_args)
{
- int restart;
int suppress_handler = 0;
int thread_is_active = 0;
- restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
-
/* Make sure this signal isn't still in the pending set: */
sigdelset(&pthread->sigpend, sig);
@@ -614,7 +372,6 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
case PS_DEAD:
case PS_DEADLOCK:
case PS_STATE_MAX:
- case PS_SIGTHREAD:
/*
* You can't call a signal handler for threads in these
* states.
@@ -685,8 +442,6 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
* Mark the thread as interrupted only if the
* restart flag is not set on the signal action:
*/
- if (restart == 0)
- pthread->interrupted = 1;
PTHREAD_WAITQ_REMOVE(pthread);
PTHREAD_SET_STATE(pthread, PS_RUNNING);
}
@@ -717,50 +472,10 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
PTHREAD_SET_STATE(pthread, PS_RUNNING);
break;
- /*
- * States which are interruptible but may need to be removed
- * from queues before any signal handler is called.
- *
- * XXX - We may not need to handle this condition, but will
- * mark it as a potential problem.
- */
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- case PS_FILE_WAIT:
- if (restart == 0)
- pthread->interrupted = 1;
- /*
- * Remove the thread from the wait queue. Our
- * signal handler hook will remove this thread
- * from the fd or file queue before invoking
- * the actual handler.
- */
- PTHREAD_WAITQ_REMOVE(pthread);
- break;
-
- /*
- * States which are interruptible:
- */
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- if (restart == 0) {
- /*
- * Flag the operation as interrupted and
- * set the state to running:
- */
- pthread->interrupted = 1;
- PTHREAD_SET_STATE(pthread, PS_RUNNING);
- }
- PTHREAD_WORKQ_REMOVE(pthread);
- PTHREAD_WAITQ_REMOVE(pthread);
- break;
-
- case PS_POLL_WAIT:
- case PS_SELECT_WAIT:
case PS_SLEEP_WAIT:
/*
- * Unmasked signals always cause poll, select, and sleep
- * to terminate early, regardless of SA_RESTART:
+ * Unmasked signals always cause sleep to terminate early,
+ * regardless of SA_RESTART:
*/
pthread->interrupted = 1;
/* Remove threads in poll and select from the workq: */
@@ -776,6 +491,9 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
break;
}
+ DBG_MSG(">>> suppress_handler = %d, thread_is_active = %d\n",
+ suppress_handler, thread_is_active);
+
if (suppress_handler == 0) {
/* Setup a signal frame and save the current threads state: */
thread_sigframe_add(pthread, sig, has_args);
@@ -807,6 +525,7 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
}
}
+#if __XXX_NOT_YET__
static void
thread_sig_check_state(struct pthread *pthread, int sig)
{
@@ -820,7 +539,6 @@ thread_sig_check_state(struct pthread *pthread, int sig)
case PS_DEAD:
case PS_DEADLOCK:
case PS_STATE_MAX:
- case PS_SIGTHREAD:
case PS_RUNNING:
case PS_SUSPENDED:
case PS_SPINBLOCK:
@@ -893,7 +611,9 @@ thread_sig_check_state(struct pthread *pthread, int sig)
break;
}
}
+#endif
+#if __XXX_NOT_YET__
/*
* Send a signal to a specific thread (ala pthread_kill):
*/
@@ -950,6 +670,7 @@ _thread_sig_send(struct pthread *pthread, int sig)
}
}
}
+#endif
/*
* User thread signal handler wrapper.
@@ -957,45 +678,32 @@ _thread_sig_send(struct pthread *pthread, int sig)
* thread - current running thread
*/
void
-_thread_sig_wrapper(void)
+_thread_sig_wrapper(int sig, siginfo_t *info, ucontext_t *context)
{
- struct pthread_signal_frame *psf;
+ struct pthread_state_data psd;
struct pthread *thread = _get_curthread();
+ __siginfohandler_t *handler;
- /* Get the current frame and state: */
- psf = thread->curframe;
- thread->curframe = NULL;
- PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler");
-
- /*
- * We're coming from the kernel scheduler; clear the in
- * scheduler flag:
- */
- _thread_kern_in_sched = 0;
+ /* Save the thread's previous state. */
+ thread_sigframe_save(thread, &psd);
/* Check the threads previous state: */
- if (psf->saved_state.psd_state != PS_RUNNING) {
+ if (psd.psd_state != PS_RUNNING) {
/*
* Do a little cleanup handling for those threads in
* queues before calling the signal handler. Signals
* for these threads are temporarily blocked until
* after cleanup handling.
*/
- switch (psf->saved_state.psd_state) {
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- _fd_lock_backout(thread);
- psf->saved_state.psd_state = PS_RUNNING;
- break;
-
+ switch (psd.psd_state) {
case PS_COND_WAIT:
_cond_wait_backout(thread);
- psf->saved_state.psd_state = PS_RUNNING;
+ psd.psd_state = PS_RUNNING;
break;
case PS_MUTEX_WAIT:
_mutex_lock_backout(thread);
- psf->saved_state.psd_state = PS_RUNNING;
+ psd.psd_state = PS_RUNNING;
break;
default:
@@ -1003,8 +711,12 @@ _thread_sig_wrapper(void)
}
}
- /* Unblock the signal in case we don't return from the handler: */
- _thread_sigq[psf->signo - 1].blocked = 0;
+ /* Unblock the signal in case we don't return from the handler. */
+ /*
+ * XXX - This is totally bogus. We need to lock the signal mask
+ * somehow.
+ */
+ sigdelset(&_thread_sigmask, sig);
/*
* Lower the priority before calling the handler in case
@@ -1014,23 +726,21 @@ _thread_sig_wrapper(void)
/*
* Reenable interruptions without checking for the need to
- * context switch:
+ * context switch.
*/
thread->sig_defer_count = 0;
- /*
- * Dispatch the signal via the custom signal handler:
- */
- if (psf->sig_has_args == 0)
- thread_sig_invoke_handler(psf->signo, NULL, NULL);
- else
- thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc);
+ if (_thread_sigact[sig -1].sa_handler != NULL) {
+ handler = (__siginfohandler_t *)
+ _thread_sigact[sig - 1].sa_handler;
+ handler(sig, info, context);
+ }
- /*
- * Call the kernel scheduler to safely restore the frame and
- * schedule the next thread:
- */
- _thread_kern_sched_frame(psf);
+ /* Restore the signal frame. */
+ thread_sigframe_restore(thread, &psd);
+
+ /* The signal mask was restored; check for any pending signals. */
+ /* XXX - thread->check_pending = 1; */
}
static void
@@ -1039,43 +749,20 @@ thread_sigframe_add(struct pthread *thread, int sig, int has_args)
struct pthread_signal_frame *psf = NULL;
unsigned long stackp;
- /* Get the top of the threads stack: */
- stackp = GET_STACK_JB(thread->ctx.jb);
-
- /*
- * Leave a little space on the stack and round down to the
- * nearest aligned word:
- */
- stackp -= sizeof(double);
- stackp &= ~0x3UL;
-
- /* Allocate room on top of the stack for a new signal frame: */
- stackp -= sizeof(struct pthread_signal_frame);
-
- psf = (struct pthread_signal_frame *) stackp;
-
- /* Save the current context in the signal frame: */
- thread_sigframe_save(thread, psf);
-
- /* Set handler specific information: */
- psf->sig_has_args = has_args;
- psf->signo = sig;
- if (has_args) {
- /* Copy the signal handler arguments to the signal frame: */
- memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
- sizeof(psf->uc));
- memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo,
- sizeof(psf->siginfo));
- }
-
- /* Setup the signal mask: */
- SIGSETOR(thread->sigmask, _thread_sigact[sig - 1].sa_mask);
- sigaddset(&thread->sigmask, sig);
+ /* Add a signal frame to the stack, pointing to our signal wrapper. */
+ signalcontext(&thread->mailbox.tm_context, sig,
+ (__sighandler_t *)_thread_sig_wrapper);
- /* Set up the new frame: */
+ /* Setup the new signal mask. */
+ SIGSETOR(thread->mailbox.tm_context.uc_sigmask,
+ _thread_sigact[sig - 1].sa_mask);
+ sigaddset(&thread->mailbox.tm_context.uc_sigmask, sig);
+#if 0
+ /* Set up the new frame. */
thread->curframe = psf;
thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
PTHREAD_FLAGS_IN_SYNCQ;
+
/*
* Set up the context:
*/
@@ -1083,43 +770,35 @@ thread_sigframe_add(struct pthread *thread, int sig, int has_args)
_setjmp(thread->ctx.jb);
SET_STACK_JB(thread->ctx.jb, stackp);
SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
+#endif
}
-void
-_thread_sigframe_restore(struct pthread *thread,
- struct pthread_signal_frame *psf)
+static void
+thread_sigframe_restore(struct pthread *thread, struct pthread_state_data *psd)
{
- memcpy(&thread->ctx, &psf->ctx, sizeof(thread->ctx));
- /*
- * Only restore the signal mask if it hasn't been changed
- * by the application during invocation of the signal handler:
- */
- if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno)
- thread->sigmask = psf->saved_state.psd_sigmask;
- thread->curframe = psf->saved_state.psd_curframe;
- thread->wakeup_time = psf->saved_state.psd_wakeup_time;
- thread->data = psf->saved_state.psd_wait_data;
- thread->state = psf->saved_state.psd_state;
- thread->flags = psf->saved_state.psd_flags;
- thread->interrupted = psf->saved_state.psd_interrupted;
- thread->signo = psf->saved_state.psd_signo;
- thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
+ thread->wakeup_time = psd->psd_wakeup_time;
+ thread->data = psd->psd_wait_data;
+ thread->state = psd->psd_state;
+ thread->flags = psd->psd_flags;
+ thread->interrupted = psd->psd_interrupted;
+ thread->sig_defer_count = psd->psd_sig_defer_count;
}
static void
-thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf)
+thread_sigframe_save(struct pthread *thread, struct pthread_state_data *psd)
{
- memcpy(&psf->ctx, &thread->ctx, sizeof(thread->ctx));
- psf->saved_state.psd_sigmask = thread->sigmask;
- psf->saved_state.psd_curframe = thread->curframe;
- psf->saved_state.psd_wakeup_time = thread->wakeup_time;
- psf->saved_state.psd_wait_data = thread->data;
- psf->saved_state.psd_state = thread->state;
- psf->saved_state.psd_flags = thread->flags &
+ psd->psd_wakeup_time = thread->wakeup_time;
+ psd->psd_wait_data = thread->data;
+ psd->psd_state = thread->state;
+ psd->psd_flags = thread->flags &
(PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
- psf->saved_state.psd_interrupted = thread->interrupted;
- psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
- psf->saved_state.psd_signo = thread->signo;
- psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
+ psd->psd_interrupted = thread->interrupted;
+ psd->psd_sig_defer_count = thread->sig_defer_count;
}
+void
+_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *context)
+{
+
+ /* Nothing. */
+}
diff --git a/lib/libkse/thread/thr_sigpending.c b/lib/libkse/thread/thr_sigpending.c
index 71c6771..5b3c02f 100644
--- a/lib/libkse/thread/thr_sigpending.c
+++ b/lib/libkse/thread/thr_sigpending.c
@@ -54,7 +54,7 @@ _sigpending(sigset_t *set)
}
else {
*set = curthread->sigpend;
- SIGSETOR(*set, _process_sigpending);
+ SIGSETOR(*set, _thread_sigpending);
}
/* Return the completion status: */
return (ret);
diff --git a/lib/libpthread/thread/thr_cancel.c b/lib/libpthread/thread/thr_cancel.c
index e4e0216..8b0b4c0 100644
--- a/lib/libpthread/thread/thr_cancel.c
+++ b/lib/libpthread/thread/thr_cancel.c
@@ -51,6 +51,8 @@ _pthread_cancel(pthread_t pthread)
/* Fall through: */
case PS_SLEEP_WAIT:
case PS_WAIT_WAIT:
+ case PS_SIGSUSPEND:
+ case PS_SIGWAIT:
/* Interrupt and resume: */
pthread->interrupted = 1;
pthread->cancelflags |= PTHREAD_CANCELLING;
diff --git a/lib/libpthread/thread/thr_init.c b/lib/libpthread/thread/thr_init.c
index 9f2f894..8e19924 100644
--- a/lib/libpthread/thread/thr_init.c
+++ b/lib/libpthread/thread/thr_init.c
@@ -162,6 +162,12 @@ _thread_init(void)
int sched_stack_size; /* Size of scheduler stack. */
struct clockinfo clockinfo;
+ struct sigaction act;
+
+ /* Check if this function has already been called: */
+ if (_thread_initial)
+ /* Only initialise the threaded application once. */
+ return;
_pthread_page_size = getpagesize();
_pthread_guard_default = getpagesize();
@@ -338,6 +344,31 @@ _thread_init(void)
TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle);
_set_curthread(_thread_initial);
+ /* Clear the pending signals for the process. */
+ sigemptyset(&_thread_sigpending);
+
+ /* Enter a loop to get the existing signal status: */
+ for (i = 1; i < NSIG; i++) {
+ /* Check for signals which cannot be trapped. */
+ if (i == SIGKILL || i == SIGSTOP)
+ continue;
+
+ /* Get the signal handler details. */
+ if (__sys_sigaction(i, NULL,
+ &_thread_sigact[i - 1]) != 0)
+ PANIC("Cannot read signal handler info");
+ }
+
+ /* Register SIGCHLD (needed for wait(2)). */
+ sigfillset(&act.sa_mask);
+ act.sa_handler = (void (*) ()) _thread_sig_handler;
+ act.sa_flags = SA_SIGINFO | SA_RESTART;
+ if (__sys_sigaction(SIGCHLD, &act, NULL) != 0)
+ PANIC("Can't initialize signal handler");
+
+ /* Get the process signal mask. */
+ __sys_sigprocmask(SIG_SETMASK, NULL, &_thread_sigmask);
+
/* Get the kernel clockrate: */
mib[0] = CTL_KERN;
mib[1] = KERN_CLOCKRATE;
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
index 0747cff..c14d44a 100644
--- a/lib/libpthread/thread/thr_kern.c
+++ b/lib/libpthread/thread/thr_kern.c
@@ -248,6 +248,8 @@ _thread_kern_scheduler(struct kse_mailbox *km)
pthread_t td, pthread, pthread_h;
unsigned int current_tick;
struct kse_thr_mailbox *tm, *p;
+ sigset_t sigset;
+ int i;
DBG_MSG("entering\n");
while (!TAILQ_EMPTY(&_thread_list)) {
@@ -280,8 +282,13 @@ _thread_kern_scheduler(struct kse_mailbox *km)
}
/* Deliver posted signals. */
- /* XXX: Not yet. */
DBG_MSG("Picking up signals\n");
+ bcopy(&km->km_sigscaught, &sigset, sizeof(sigset_t));
+ sigemptyset(&km->km_sigscaught); /* XXX */
+ if (SIGNOTEMPTY(sigset))
+ for (i = 1; i < NSIG; i++)
+ if (sigismember(&sigset, i) != 0)
+ _thread_sig_dispatch(i);
if (_spinblock_count != 0) {
/*
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
index 8aacdc0..7c5cc87 100644
--- a/lib/libpthread/thread/thr_private.h
+++ b/lib/libpthread/thread/thr_private.h
@@ -426,6 +426,8 @@ enum pthread_state {
PS_COND_WAIT,
PS_SLEEP_WAIT,
PS_WAIT_WAIT,
+ PS_SIGSUSPEND,
+ PS_SIGWAIT,
PS_SPINBLOCK,
PS_JOIN,
PS_SUSPENDED,
@@ -445,6 +447,7 @@ enum pthread_state {
union pthread_wait_data {
pthread_mutex_t mutex;
pthread_cond_t cond;
+ const sigset_t *sigwait; /* Waiting on a signal in sigwait */
spinlock_t *spinlock;
struct pthread *thread;
};
@@ -461,6 +464,15 @@ struct join_status {
int error;
};
+struct pthread_state_data {
+ struct timespec psd_wakeup_time;
+ union pthread_wait_data psd_wait_data;
+ enum pthread_state psd_state;
+ int psd_flags;
+ int psd_interrupted;
+ int psd_sig_defer_count;
+};
+
struct pthread_specific_elem {
const void *data;
int seqno;
@@ -515,6 +527,9 @@ struct pthread {
thread_continuation_t continuation;
+ /* Currently pending signals. */
+ sigset_t sigpend;
+
/* Thread state: */
enum pthread_state state;
@@ -590,6 +605,9 @@ struct pthread {
*/
int interrupted;
+ /* Signal number when in state PS_SIGWAIT: */
+ int signo;
+
/*
* Set to non-zero when this thread has deferred signals.
* We allow for recursive deferral.
@@ -774,6 +792,11 @@ SCLASS pthread_cond_t _gc_cond
;
/*
+ * Array of signal actions for this process.
+ */
+SCLASS struct sigaction _thread_sigact[NSIG];
+
+/*
* Scheduling queues:
*/
SCLASS pq_queue_t _readyq;
@@ -799,6 +822,12 @@ SCLASS pthread_switch_routine_t _sched_switch_hook
;
/*
+ * Signals pending and masked.
+ */
+SCLASS sigset_t _thread_sigpending;
+SCLASS sigset_t _thread_sigmask;
+
+/*
* Declare the kernel scheduler jump buffer and stack:
*/
SCLASS struct kse_mailbox _thread_kern_kse_mailbox;
@@ -893,6 +922,7 @@ void _thread_kern_sched_state_unlock(enum pthread_state state,
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 *, ucontext_t *);
void _thread_printf(int fd, const char *, ...);
void _thread_start(void);
void _thread_seterrno(pthread_t, int);
diff --git a/lib/libpthread/thread/thr_sig.c b/lib/libpthread/thread/thr_sig.c
index 5baaab9..a93b406 100644
--- a/lib/libpthread/thread/thr_sig.c
+++ b/lib/libpthread/thread/thr_sig.c
@@ -43,262 +43,62 @@
#include "thr_private.h"
/* Prototypes: */
+static void thread_sig_handle_special(int sig);
+
static void thread_sig_add(struct pthread *pthread, int sig, int has_args);
static void thread_sig_check_state(struct pthread *pthread, int sig);
static struct pthread *thread_sig_find(int sig);
-static void thread_sig_handle_special(int sig);
static void thread_sigframe_add(struct pthread *thread, int sig,
int has_args);
static void thread_sigframe_save(struct pthread *thread,
- struct pthread_signal_frame *psf);
-static void thread_sig_invoke_handler(int sig, siginfo_t *info,
- ucontext_t *ucp);
+ struct pthread_state_data *psd);
+static void thread_sigframe_restore(struct pthread *thread,
+ struct pthread_state_data *psd);
-/*#define DEBUG_SIGNAL*/
+/* #define DEBUG_SIGNAL */
#ifdef DEBUG_SIGNAL
#define DBG_MSG stdout_debug
#else
#define DBG_MSG(x...)
#endif
-#if defined(_PTHREADS_INVARIANTS)
-#define SIG_SET_ACTIVE() _sig_in_handler = 1
-#define SIG_SET_INACTIVE() _sig_in_handler = 0
-#else
-#define SIG_SET_ACTIVE()
-#define SIG_SET_INACTIVE()
-#endif
-
+/*
+ * Dispatch a signal to a thread, if appropriate.
+ */
void
-_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp)
+_thread_sig_dispatch(int sig)
{
- struct pthread *curthread = _get_curthread();
- struct pthread *pthread, *pthread_h;
- int in_sched = _thread_kern_in_sched;
- char c;
-
- if (ucp == NULL)
- PANIC("Thread signal handler received null context");
- DBG_MSG("Got signal %d, current thread %p\n", sig, curthread);
-
- /* Check if an interval timer signal: */
- if (sig == _SCHED_SIGNAL) {
- /* Update the scheduling clock: */
- gettimeofday((struct timeval *)&_sched_tod, NULL);
- _sched_ticks++;
-
- if (in_sched != 0) {
- /*
- * The scheduler is already running; ignore this
- * signal.
- */
- }
- /*
- * Check if the scheduler interrupt has come when
- * the currently running thread has deferred thread
- * signals.
- */
- else if (curthread->sig_defer_count > 0)
- curthread->yield_on_sig_undefer = 1;
- else {
- /* Schedule the next thread: */
- _thread_kern_sched(ucp);
-
- /*
- * This point should not be reached, so abort the
- * process:
- */
- PANIC("Returned to signal function from scheduler");
- }
- }
- /*
- * Check if the kernel has been interrupted while the scheduler
- * is accessing the scheduling queues or if there is a currently
- * running thread that has deferred signals.
- */
- else if ((in_sched != 0) || (curthread->sig_defer_count > 0)) {
- /* Cast the signal number to a character variable: */
- c = sig;
-
- /*
- * Write the signal number to the kernel pipe so that it will
- * be ready to read when this signal handler returns.
- */
- if (_queue_signals != 0) {
- __sys_write(_thread_kern_pipe[1], &c, 1);
- DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig);
- }
- if (_thread_sigq[sig - 1].blocked == 0) {
- DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig);
- /*
- * Do not block this signal; it will be blocked
- * when the pending signals are run down.
- */
- /* _thread_sigq[sig - 1].blocked = 1; */
-
- /*
- * Queue the signal, saving siginfo and sigcontext
- * (ucontext).
- *
- * XXX - Do we need to copy siginfo and ucp?
- */
- _thread_sigq[sig - 1].signo = sig;
- if (info != NULL)
- memcpy(&_thread_sigq[sig - 1].siginfo, info,
- sizeof(*info));
- memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
-
- /* Indicate that there are queued signals: */
- _thread_sigq[sig - 1].pending = 1;
- _sigq_check_reqd = 1;
- }
- /* These signals need special handling: */
- else if (sig == SIGCHLD || sig == SIGTSTP ||
- sig == SIGTTIN || sig == SIGTTOU) {
- _thread_sigq[sig - 1].pending = 1;
- _thread_sigq[sig - 1].signo = sig;
- _sigq_check_reqd = 1;
- }
- else
- DBG_MSG("Got signal %d, ignored.\n", sig);
- }
- /*
- * The signal handlers should have been installed so that they
- * cannot be interrupted by other signals.
- */
- else if (_thread_sigq[sig - 1].blocked == 0) {
- /*
- * The signal is not blocked; handle the signal.
- *
- * Ignore subsequent occurrences of this signal
- * until the current signal is handled:
- */
- _thread_sigq[sig - 1].blocked = 1;
-
- /* This signal will be handled; clear the pending flag: */
- _thread_sigq[sig - 1].pending = 0;
-
- /*
- * Save siginfo and sigcontext (ucontext).
- *
- * XXX - Do we need to copy siginfo and ucp?
- */
- _thread_sigq[sig - 1].signo = sig;
-
- if (info != NULL)
- memcpy(&_thread_sigq[sig - 1].siginfo, info,
- sizeof(*info));
- memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp));
- SIG_SET_ACTIVE();
-
- /* Handle special signals: */
- thread_sig_handle_special(sig);
-
- pthread_h = NULL;
- if ((pthread = thread_sig_find(sig)) == NULL)
- DBG_MSG("No thread to handle signal %d\n", sig);
- else if (pthread == curthread) {
- /*
- * Unblock the signal and restore the process signal
- * mask in case we don't return from the handler:
- */
- _thread_sigq[sig - 1].blocked = 0;
- __sys_sigprocmask(SIG_SETMASK, &_process_sigmask, NULL);
-
- /* Call the signal handler for the current thread: */
- thread_sig_invoke_handler(sig, info, ucp);
-
- /*
- * Set the process signal mask in the context; it
- * could have changed by the handler.
- */
- ucp->uc_sigmask = _process_sigmask;
-
- /* Resume the interrupted thread: */
- __sys_sigreturn(ucp);
- } else {
- DBG_MSG("Got signal %d, adding frame to thread %p\n",
- sig, pthread);
-
- /* Setup the target thread to receive the signal: */
- thread_sig_add(pthread, sig, /*has_args*/ 1);
-
- /* Take a peek at the next ready to run thread: */
- pthread_h = PTHREAD_PRIOQ_FIRST();
- DBG_MSG("Finished adding frame, head of prio list %p\n",
- pthread_h);
- }
- SIG_SET_INACTIVE();
+ struct pthread *pthread;
- /*
- * Switch to a different context if the currently running
- * thread takes a signal, or if another thread takes a
- * signal and the currently running thread is not in a
- * signal handler.
- */
- if ((pthread_h != NULL) &&
- (pthread_h->active_priority > curthread->active_priority)) {
- /* Enter the kernel scheduler: */
- _thread_kern_sched(ucp);
- }
- }
- else {
- SIG_SET_ACTIVE();
- thread_sig_handle_special(sig);
- SIG_SET_INACTIVE();
- }
-}
+ DBG_MSG(">>> _thread_sig_dispatch(%d)\n", sig);
-static void
-thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp)
- {
- struct pthread *curthread = _get_curthread();
- void (*sigfunc)(int, siginfo_t *, void *);
- int saved_seqno;
- sigset_t saved_sigmask;
+ thread_sig_handle_special(sig);
+ if (sigismember(&_thread_sigmask, sig))
+ /* Don't deliver the signal if it's masked. */
+ return;
+ /* Mask the signal until it's handled. */
+ sigaddset(&_thread_sigmask, sig);
+ /* This signal will be handled; clear the pending flag. */
+ sigdelset(&_thread_sigpending, sig);
- /* Invoke the signal handler without going through the scheduler:
- */
- DBG_MSG("Got signal %d, calling handler for current thread %p\n",
- sig, curthread);
-
- /* Save the threads signal mask: */
- saved_sigmask = curthread->sigmask;
- saved_seqno = curthread->sigmask_seqno;
-
- /* Setup the threads signal mask: */
- SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask);
- sigaddset(&curthread->sigmask, sig);
-
/*
- * Check that a custom handler is installed and if
- * the signal is not blocked:
+ * Deliver the signal to a thread.
*/
- sigfunc = _thread_sigact[sig - 1].sa_sigaction;
- if (((__sighandler_t *)sigfunc != SIG_DFL) &&
- ((__sighandler_t *)sigfunc != SIG_IGN)) {
- if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) ||
- (info == NULL))
- (*(sigfunc))(sig, info, ucp);
- else
- (*(sigfunc))(sig, (siginfo_t *)info->si_code, ucp);
+ if ((pthread = thread_sig_find(sig)) == NULL) {
+ DBG_MSG("No thread to handle signal %d\n", sig);
+ return;
}
- /*
- * Only restore the signal mask if it hasn't been changed by the
- * application during invocation of the signal handler:
- */
- if (curthread->sigmask_seqno == saved_seqno)
- curthread->sigmask = saved_sigmask;
+ DBG_MSG("Got signal %d, selecting thread %p\n", sig, pthread);
+ thread_sig_add(pthread, sig, /*has_args*/ 1);
}
/*
* Find a thread that can handle the signal.
*/
-struct pthread *
+static struct pthread *
thread_sig_find(int sig)
{
struct pthread *curthread = _get_curthread();
- int handler_installed;
struct pthread *pthread, *pthread_next;
struct pthread *suspended_thread, *signaled_thread;
@@ -309,138 +109,116 @@ thread_sig_find(int sig)
_thread_dump_info();
/* Unblock this signal to allow further dumps: */
- _thread_sigq[sig - 1].blocked = 0;
+ sigdelset(&_thread_sigmask, sig);
}
- /* Check if an interval timer signal: */
- else if (sig == _SCHED_SIGNAL) {
- /*
- * This shouldn't ever occur (should this panic?).
- */
- } else {
+
+ /*
+ * Enter a loop to look for threads that have the signal
+ * unmasked. POSIX specifies that a thread in a sigwait
+ * will get the signal over any other threads. Second
+ * preference will be threads in in a sigsuspend. Third
+ * preference will be the current thread. If none of the
+ * above, then the signal is delivered to the first thread
+ * that is found. Note that if a custom handler is not
+ * installed, the signal only affects threads in sigwait.
+ */
+ suspended_thread = NULL;
+ if ((curthread != &_thread_kern_thread) &&
+ !sigismember(&curthread->mailbox.tm_context.uc_sigmask, sig))
+ signaled_thread = curthread;
+ else
+ signaled_thread = NULL;
+
+ for (pthread = TAILQ_FIRST(&_waitingq);
+ pthread != NULL; pthread = pthread_next) {
/*
- * Enter a loop to look for threads that have the signal
- * unmasked. POSIX specifies that a thread in a sigwait
- * will get the signal over any other threads. Second
- * preference will be threads in in a sigsuspend. Third
- * preference will be the current thread. If none of the
- * above, then the signal is delivered to the first thread
- * that is found. Note that if a custom handler is not
- * installed, the signal only affects threads in sigwait.
+ * Grab the next thread before possibly destroying
+ * the link entry.
*/
- suspended_thread = NULL;
- if ((curthread != &_thread_kern_thread) &&
- !sigismember(&curthread->sigmask, sig))
- signaled_thread = curthread;
- else
- signaled_thread = NULL;
- if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) ||
- (_thread_sigact[sig - 1].sa_handler == SIG_DFL))
- handler_installed = 0;
- else
- handler_installed = 1;
+ pthread_next = TAILQ_NEXT(pthread, pqe);
+
+ if ((pthread->state == PS_SIGWAIT) &&
+ sigismember(pthread->data.sigwait, sig)) {
+ /* Change the state of the thread to run: */
+ PTHREAD_NEW_STATE(pthread, PS_RUNNING);
- for (pthread = TAILQ_FIRST(&_waitingq);
- pthread != NULL; pthread = pthread_next) {
/*
- * Grab the next thread before possibly destroying
- * the link entry.
+ * A signal handler is not invoked for threads
+ * in sigwait. Clear the blocked and pending
+ * flags.
*/
- pthread_next = TAILQ_NEXT(pthread, pqe);
+ sigdelset(&_thread_sigmask, sig);
+ sigdelset(&_thread_sigpending, sig);
- if ((pthread->state == PS_SIGWAIT) &&
- sigismember(pthread->data.sigwait, sig)) {
- /* Change the state of the thread to run: */
- PTHREAD_NEW_STATE(pthread,PS_RUNNING);
- /*
- * A signal handler is not invoked for threads
- * in sigwait. Clear the blocked and pending
- * flags.
- */
- _thread_sigq[sig - 1].blocked = 0;
- _thread_sigq[sig - 1].pending = 0;
-
- /* Return the signal number: */
- pthread->signo = sig;
+ /* Return the signal number: */
+ pthread->signo = sig;
- /*
- * POSIX doesn't doesn't specify which thread
- * will get the signal if there are multiple
- * waiters, so we give it to the first thread
- * we find.
- *
- * Do not attempt to deliver this signal
- * to other threads and do not add the signal
- * to the process pending set.
- */
- return (NULL);
- }
- else if ((handler_installed != 0) &&
- !sigismember(&pthread->sigmask, sig) &&
- ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
- if (pthread->state == PS_SIGSUSPEND) {
- if (suspended_thread == NULL)
- suspended_thread = pthread;
- } else if (signaled_thread == NULL)
- signaled_thread = pthread;
- }
+ /*
+ * POSIX doesn't doesn't specify which thread
+ * will get the signal if there are multiple
+ * waiters, so we give it to the first thread
+ * we find.
+ *
+ * Do not attempt to deliver this signal
+ * to other threads and do not add the signal
+ * to the process pending set.
+ */
+ return (NULL);
+ }
+ if (!sigismember(
+ &pthread->mailbox.tm_context.uc_sigmask, sig) &&
+ ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) {
+ if (pthread->state == PS_SIGSUSPEND) {
+ if (suspended_thread == NULL)
+ suspended_thread = pthread;
+ } else if (signaled_thread == NULL)
+ signaled_thread = pthread;
}
+ }
+ /*
+ * If we didn't find a thread in the waiting queue,
+ * check the all threads queue:
+ */
+ if (suspended_thread == NULL &&
+ signaled_thread == NULL) {
/*
- * Only perform wakeups and signal delivery if there is a
- * custom handler installed:
+ * Enter a loop to look for other threads
+ * capable of receiving the signal:
*/
- if (handler_installed == 0) {
- /*
- * There is no handler installed. Unblock the
- * signal so that if a handler _is_ installed, any
- * subsequent signals can be handled.
- */
- _thread_sigq[sig - 1].blocked = 0;
- } else {
- /*
- * If we didn't find a thread in the waiting queue,
- * check the all threads queue:
- */
- if (suspended_thread == NULL &&
- signaled_thread == NULL) {
- /*
- * Enter a loop to look for other threads
- * capable of receiving the signal:
- */
- TAILQ_FOREACH(pthread, &_thread_list, tle) {
- if (!sigismember(&pthread->sigmask,
- sig)) {
- signaled_thread = pthread;
- break;
- }
- }
- }
-
- if (suspended_thread == NULL &&
- signaled_thread == NULL)
- /*
- * Add it to the set of signals pending
- * on the process:
- */
- sigaddset(&_process_sigpending, sig);
- else {
- /*
- * We only deliver the signal to one thread;
- * give preference to the suspended thread:
- */
- if (suspended_thread != NULL)
- pthread = suspended_thread;
- else
- pthread = signaled_thread;
- return (pthread);
+ TAILQ_FOREACH(pthread, &_thread_list, tle) {
+ if (!sigismember(
+ &pthread->mailbox.tm_context.uc_sigmask, sig)) {
+ signaled_thread = pthread;
+ break;
}
}
}
+ if (suspended_thread == NULL &&
+ signaled_thread == NULL)
+ /*
+ * Add it to the set of signals pending
+ * on the process:
+ */
+ sigaddset(&_thread_sigpending, sig);
+ else {
+ /*
+ * We only deliver the signal to one thread;
+ * give preference to the suspended thread:
+ */
+ if (suspended_thread != NULL)
+ pthread = suspended_thread;
+ else
+ pthread = signaled_thread;
+ return (pthread);
+ }
+
/* Returns nothing. */
return (NULL);
}
+#if __XXX_NOT_YET__
void
_thread_sig_check_pending(struct pthread *pthread)
{
@@ -452,8 +230,9 @@ _thread_sig_check_pending(struct pthread *pthread)
* thread or process that aren't blocked:
*/
sigset = pthread->sigpend;
- SIGSETOR(sigset, _process_sigpending);
+ SIGSETOR(sigset, _thread_sigpending);
SIGSETNAND(sigset, pthread->sigmask);
+ SIGSETNAND(sigset, _thread_sigmask);
if (SIGNOTEMPTY(sigset)) {
for (i = 1; i < NSIG; i++) {
if (sigismember(&sigset, i) != 0) {
@@ -463,13 +242,15 @@ _thread_sig_check_pending(struct pthread *pthread)
else {
thread_sig_add(pthread, i,
/*has_args*/ 1);
- sigdelset(&_process_sigpending, i);
+ sigdelset(&_thread_sigpending, i);
}
}
}
}
}
+#endif
+#if __XXX_NOT_YET__
/*
* This can only be called from the kernel scheduler. It assumes that
* all thread contexts are saved and that a signal frame can safely be
@@ -479,30 +260,20 @@ void
_thread_sig_handle_pending(void)
{
struct pthread *pthread;
- int i, sig;
+ int sig;
- PTHREAD_ASSERT(_thread_kern_in_sched != 0,
- "_thread_sig_handle_pending called from outside kernel schedule");
/*
* Check the array of pending signals:
*/
- for (i = 0; i < NSIG; i++) {
- if (_thread_sigq[i].pending != 0) {
+ for (sig = 1; sig <= NSIG; sig++) {
+ if (sigismember(&_thread_sigpending, sig)) {
/* This signal is no longer pending. */
- _thread_sigq[i].pending = 0;
-
- sig = _thread_sigq[i].signo;
-
- /* Some signals need special handling: */
+ sigdelset(&_thread_sigpending, sig);
+ /* Some signals need special handling. */
thread_sig_handle_special(sig);
-
- if (_thread_sigq[i].blocked == 0) {
- /*
- * Block future signals until this one
- * is handled:
- */
- _thread_sigq[i].blocked = 1;
-
+ /* Deliver the signal. */
+ if (sigismember(&_thread_sigmask, sig)) {
+ sigaddset(&_thread_sigmask, sig);
if ((pthread = thread_sig_find(sig)) != NULL) {
/*
* Setup the target thread to receive
@@ -515,7 +286,12 @@ _thread_sig_handle_pending(void)
}
}
}
+#endif
+/*
+ * Do special processing to the thread states before we deliver
+ * a signal to the application.
+ */
static void
thread_sig_handle_special(int sig)
{
@@ -525,21 +301,6 @@ thread_sig_handle_special(int sig)
switch (sig) {
case SIGCHLD:
/*
- * Go through the file list and set all files
- * to non-blocking again in case the child
- * set some of them to block. Sigh.
- */
- for (i = 0; i < _thread_dtablesize; i++) {
- /* Check if this file is used: */
- if (_thread_fd_table[i] != NULL) {
- /*
- * Set the file descriptor to non-blocking:
- */
- __sys_fcntl(i, F_SETFL,
- _thread_fd_getflags(i) | O_NONBLOCK);
- }
- }
- /*
* Enter a loop to wake up all threads waiting
* for a process to complete:
*/
@@ -595,12 +356,9 @@ thread_sig_handle_special(int sig)
static void
thread_sig_add(struct pthread *pthread, int sig, int has_args)
{
- int restart;
int suppress_handler = 0;
int thread_is_active = 0;
- restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART;
-
/* Make sure this signal isn't still in the pending set: */
sigdelset(&pthread->sigpend, sig);
@@ -614,7 +372,6 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
case PS_DEAD:
case PS_DEADLOCK:
case PS_STATE_MAX:
- case PS_SIGTHREAD:
/*
* You can't call a signal handler for threads in these
* states.
@@ -685,8 +442,6 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
* Mark the thread as interrupted only if the
* restart flag is not set on the signal action:
*/
- if (restart == 0)
- pthread->interrupted = 1;
PTHREAD_WAITQ_REMOVE(pthread);
PTHREAD_SET_STATE(pthread, PS_RUNNING);
}
@@ -717,50 +472,10 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
PTHREAD_SET_STATE(pthread, PS_RUNNING);
break;
- /*
- * States which are interruptible but may need to be removed
- * from queues before any signal handler is called.
- *
- * XXX - We may not need to handle this condition, but will
- * mark it as a potential problem.
- */
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- case PS_FILE_WAIT:
- if (restart == 0)
- pthread->interrupted = 1;
- /*
- * Remove the thread from the wait queue. Our
- * signal handler hook will remove this thread
- * from the fd or file queue before invoking
- * the actual handler.
- */
- PTHREAD_WAITQ_REMOVE(pthread);
- break;
-
- /*
- * States which are interruptible:
- */
- case PS_FDR_WAIT:
- case PS_FDW_WAIT:
- if (restart == 0) {
- /*
- * Flag the operation as interrupted and
- * set the state to running:
- */
- pthread->interrupted = 1;
- PTHREAD_SET_STATE(pthread, PS_RUNNING);
- }
- PTHREAD_WORKQ_REMOVE(pthread);
- PTHREAD_WAITQ_REMOVE(pthread);
- break;
-
- case PS_POLL_WAIT:
- case PS_SELECT_WAIT:
case PS_SLEEP_WAIT:
/*
- * Unmasked signals always cause poll, select, and sleep
- * to terminate early, regardless of SA_RESTART:
+ * Unmasked signals always cause sleep to terminate early,
+ * regardless of SA_RESTART:
*/
pthread->interrupted = 1;
/* Remove threads in poll and select from the workq: */
@@ -776,6 +491,9 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
break;
}
+ DBG_MSG(">>> suppress_handler = %d, thread_is_active = %d\n",
+ suppress_handler, thread_is_active);
+
if (suppress_handler == 0) {
/* Setup a signal frame and save the current threads state: */
thread_sigframe_add(pthread, sig, has_args);
@@ -807,6 +525,7 @@ thread_sig_add(struct pthread *pthread, int sig, int has_args)
}
}
+#if __XXX_NOT_YET__
static void
thread_sig_check_state(struct pthread *pthread, int sig)
{
@@ -820,7 +539,6 @@ thread_sig_check_state(struct pthread *pthread, int sig)
case PS_DEAD:
case PS_DEADLOCK:
case PS_STATE_MAX:
- case PS_SIGTHREAD:
case PS_RUNNING:
case PS_SUSPENDED:
case PS_SPINBLOCK:
@@ -893,7 +611,9 @@ thread_sig_check_state(struct pthread *pthread, int sig)
break;
}
}
+#endif
+#if __XXX_NOT_YET__
/*
* Send a signal to a specific thread (ala pthread_kill):
*/
@@ -950,6 +670,7 @@ _thread_sig_send(struct pthread *pthread, int sig)
}
}
}
+#endif
/*
* User thread signal handler wrapper.
@@ -957,45 +678,32 @@ _thread_sig_send(struct pthread *pthread, int sig)
* thread - current running thread
*/
void
-_thread_sig_wrapper(void)
+_thread_sig_wrapper(int sig, siginfo_t *info, ucontext_t *context)
{
- struct pthread_signal_frame *psf;
+ struct pthread_state_data psd;
struct pthread *thread = _get_curthread();
+ __siginfohandler_t *handler;
- /* Get the current frame and state: */
- psf = thread->curframe;
- thread->curframe = NULL;
- PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler");
-
- /*
- * We're coming from the kernel scheduler; clear the in
- * scheduler flag:
- */
- _thread_kern_in_sched = 0;
+ /* Save the thread's previous state. */
+ thread_sigframe_save(thread, &psd);
/* Check the threads previous state: */
- if (psf->saved_state.psd_state != PS_RUNNING) {
+ if (psd.psd_state != PS_RUNNING) {
/*
* Do a little cleanup handling for those threads in
* queues before calling the signal handler. Signals
* for these threads are temporarily blocked until
* after cleanup handling.
*/
- switch (psf->saved_state.psd_state) {
- case PS_FDLR_WAIT:
- case PS_FDLW_WAIT:
- _fd_lock_backout(thread);
- psf->saved_state.psd_state = PS_RUNNING;
- break;
-
+ switch (psd.psd_state) {
case PS_COND_WAIT:
_cond_wait_backout(thread);
- psf->saved_state.psd_state = PS_RUNNING;
+ psd.psd_state = PS_RUNNING;
break;
case PS_MUTEX_WAIT:
_mutex_lock_backout(thread);
- psf->saved_state.psd_state = PS_RUNNING;
+ psd.psd_state = PS_RUNNING;
break;
default:
@@ -1003,8 +711,12 @@ _thread_sig_wrapper(void)
}
}
- /* Unblock the signal in case we don't return from the handler: */
- _thread_sigq[psf->signo - 1].blocked = 0;
+ /* Unblock the signal in case we don't return from the handler. */
+ /*
+ * XXX - This is totally bogus. We need to lock the signal mask
+ * somehow.
+ */
+ sigdelset(&_thread_sigmask, sig);
/*
* Lower the priority before calling the handler in case
@@ -1014,23 +726,21 @@ _thread_sig_wrapper(void)
/*
* Reenable interruptions without checking for the need to
- * context switch:
+ * context switch.
*/
thread->sig_defer_count = 0;
- /*
- * Dispatch the signal via the custom signal handler:
- */
- if (psf->sig_has_args == 0)
- thread_sig_invoke_handler(psf->signo, NULL, NULL);
- else
- thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc);
+ if (_thread_sigact[sig -1].sa_handler != NULL) {
+ handler = (__siginfohandler_t *)
+ _thread_sigact[sig - 1].sa_handler;
+ handler(sig, info, context);
+ }
- /*
- * Call the kernel scheduler to safely restore the frame and
- * schedule the next thread:
- */
- _thread_kern_sched_frame(psf);
+ /* Restore the signal frame. */
+ thread_sigframe_restore(thread, &psd);
+
+ /* The signal mask was restored; check for any pending signals. */
+ /* XXX - thread->check_pending = 1; */
}
static void
@@ -1039,43 +749,20 @@ thread_sigframe_add(struct pthread *thread, int sig, int has_args)
struct pthread_signal_frame *psf = NULL;
unsigned long stackp;
- /* Get the top of the threads stack: */
- stackp = GET_STACK_JB(thread->ctx.jb);
-
- /*
- * Leave a little space on the stack and round down to the
- * nearest aligned word:
- */
- stackp -= sizeof(double);
- stackp &= ~0x3UL;
-
- /* Allocate room on top of the stack for a new signal frame: */
- stackp -= sizeof(struct pthread_signal_frame);
-
- psf = (struct pthread_signal_frame *) stackp;
-
- /* Save the current context in the signal frame: */
- thread_sigframe_save(thread, psf);
-
- /* Set handler specific information: */
- psf->sig_has_args = has_args;
- psf->signo = sig;
- if (has_args) {
- /* Copy the signal handler arguments to the signal frame: */
- memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc,
- sizeof(psf->uc));
- memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo,
- sizeof(psf->siginfo));
- }
-
- /* Setup the signal mask: */
- SIGSETOR(thread->sigmask, _thread_sigact[sig - 1].sa_mask);
- sigaddset(&thread->sigmask, sig);
+ /* Add a signal frame to the stack, pointing to our signal wrapper. */
+ signalcontext(&thread->mailbox.tm_context, sig,
+ (__sighandler_t *)_thread_sig_wrapper);
- /* Set up the new frame: */
+ /* Setup the new signal mask. */
+ SIGSETOR(thread->mailbox.tm_context.uc_sigmask,
+ _thread_sigact[sig - 1].sa_mask);
+ sigaddset(&thread->mailbox.tm_context.uc_sigmask, sig);
+#if 0
+ /* Set up the new frame. */
thread->curframe = psf;
thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE |
PTHREAD_FLAGS_IN_SYNCQ;
+
/*
* Set up the context:
*/
@@ -1083,43 +770,35 @@ thread_sigframe_add(struct pthread *thread, int sig, int has_args)
_setjmp(thread->ctx.jb);
SET_STACK_JB(thread->ctx.jb, stackp);
SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
+#endif
}
-void
-_thread_sigframe_restore(struct pthread *thread,
- struct pthread_signal_frame *psf)
+static void
+thread_sigframe_restore(struct pthread *thread, struct pthread_state_data *psd)
{
- memcpy(&thread->ctx, &psf->ctx, sizeof(thread->ctx));
- /*
- * Only restore the signal mask if it hasn't been changed
- * by the application during invocation of the signal handler:
- */
- if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno)
- thread->sigmask = psf->saved_state.psd_sigmask;
- thread->curframe = psf->saved_state.psd_curframe;
- thread->wakeup_time = psf->saved_state.psd_wakeup_time;
- thread->data = psf->saved_state.psd_wait_data;
- thread->state = psf->saved_state.psd_state;
- thread->flags = psf->saved_state.psd_flags;
- thread->interrupted = psf->saved_state.psd_interrupted;
- thread->signo = psf->saved_state.psd_signo;
- thread->sig_defer_count = psf->saved_state.psd_sig_defer_count;
+ thread->wakeup_time = psd->psd_wakeup_time;
+ thread->data = psd->psd_wait_data;
+ thread->state = psd->psd_state;
+ thread->flags = psd->psd_flags;
+ thread->interrupted = psd->psd_interrupted;
+ thread->sig_defer_count = psd->psd_sig_defer_count;
}
static void
-thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf)
+thread_sigframe_save(struct pthread *thread, struct pthread_state_data *psd)
{
- memcpy(&psf->ctx, &thread->ctx, sizeof(thread->ctx));
- psf->saved_state.psd_sigmask = thread->sigmask;
- psf->saved_state.psd_curframe = thread->curframe;
- psf->saved_state.psd_wakeup_time = thread->wakeup_time;
- psf->saved_state.psd_wait_data = thread->data;
- psf->saved_state.psd_state = thread->state;
- psf->saved_state.psd_flags = thread->flags &
+ psd->psd_wakeup_time = thread->wakeup_time;
+ psd->psd_wait_data = thread->data;
+ psd->psd_state = thread->state;
+ psd->psd_flags = thread->flags &
(PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE);
- psf->saved_state.psd_interrupted = thread->interrupted;
- psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno;
- psf->saved_state.psd_signo = thread->signo;
- psf->saved_state.psd_sig_defer_count = thread->sig_defer_count;
+ psd->psd_interrupted = thread->interrupted;
+ psd->psd_sig_defer_count = thread->sig_defer_count;
}
+void
+_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *context)
+{
+
+ /* Nothing. */
+}
diff --git a/lib/libpthread/thread/thr_sigpending.c b/lib/libpthread/thread/thr_sigpending.c
index 71c6771..5b3c02f 100644
--- a/lib/libpthread/thread/thr_sigpending.c
+++ b/lib/libpthread/thread/thr_sigpending.c
@@ -54,7 +54,7 @@ _sigpending(sigset_t *set)
}
else {
*set = curthread->sigpend;
- SIGSETOR(*set, _process_sigpending);
+ SIGSETOR(*set, _thread_sigpending);
}
/* Return the completion status: */
return (ret);
OpenPOWER on IntegriCloud