Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib/libpthread More signal rearranging:
details: https://anonhg.NetBSD.org/src/rev/0e5de0f53e2e
branches: trunk
changeset: 542269:0e5de0f53e2e
user: nathanw <nathanw%NetBSD.org@localhost>
date: Sat Jan 25 00:43:38 2003 +0000
description:
More signal rearranging:
- Signal handlers now simply continue executing the current thread,
rather than trying to put themselves back on the queue that they came
from, which was rather fragile. As a result, all callers of
pthread__block() must be prepared to handle spurious wakeups.
- When a signal arrives for a thread that is blocked in the kernel,
note this in another field in pthread_st and set a flag. Process the
signal and set up the trampoline for the handler *after* the thread
unblocks, so that both the trampoline and the returned state from
the kernel are preserved.
- Factor out some code into a pthread__deliver_signal() routine;
the signal-taking code in pthread_sigmask() should be able to use this
soon.
This is still gross, and there are still some terrible MP issues lurking here,
but progress crawls along.
diffstat:
lib/libpthread/pthread_int.h | 14 ++-
lib/libpthread/pthread_sa.c | 23 ++++--
lib/libpthread/pthread_sig.c | 137 +++++++++++++++++-------------------------
3 files changed, 79 insertions(+), 95 deletions(-)
diffs (truncated from 327 to 300 lines):
diff -r 3047c6558547 -r 0e5de0f53e2e lib/libpthread/pthread_int.h
--- a/lib/libpthread/pthread_int.h Sat Jan 25 00:37:01 2003 +0000
+++ b/lib/libpthread/pthread_int.h Sat Jan 25 00:43:38 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_int.h,v 1.3 2003/01/18 18:45:54 christos Exp $ */
+/* $NetBSD: pthread_int.h,v 1.4 2003/01/25 00:43:38 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -71,6 +71,8 @@
struct pthread_st {
unsigned int pt_magic;
+ /* Identifier, for debugging and for preventing recycling. */
+ int pt_num;
int pt_type; /* normal, upcall, or idle */
int pt_state; /* running, blocked, etc. */
@@ -100,6 +102,7 @@
sigset_t pt_sigmask; /* Signals we won't take. */
sigset_t pt_siglist; /* Signals pending for us. */
+ sigset_t pt_sigblocked; /* Signals delivered while blocked. */
pthread_spin_t pt_siglock; /* Lock on above */
void * pt_exitval; /* Read by pthread_join() */
@@ -140,9 +143,6 @@
*/
pthread_spin_t* pt_heldlock;
- /* Identifier, for debugging. */
- int pt_num;
-
/* Thread-specific data */
void* pt_specific[PTHREAD_KEYS_MAX];
@@ -180,7 +180,7 @@
#define PT_FLAG_CS_DISABLED 0x0004 /* Cancellation disabled */
#define PT_FLAG_CS_ASYNC 0x0008 /* Cancellation is async */
#define PT_FLAG_CS_PENDING 0x0010
-#define PT_FLAG_SIGCATCH 0x0020 /* Interrupt sleep on a signal */
+#define PT_FLAG_SIGDEFERRED 0x0020 /* There are signals to take */
#define PT_MAGIC 0x11110001
#define PT_DEAD 0xDEAD0001
@@ -341,7 +341,9 @@
void pthread__signal_init(void);
-void pthread__signal(pthread_t t, int sig, int code);
+void pthread__signal(pthread_t self, pthread_t t, int sig, int code);
+void pthread__deliver_signal(pthread_t self, pthread_t t, int sig, int code);
+void pthread__signal_deferred(pthread_t self, pthread_t t);
void pthread__destroy_tsd(pthread_t self);
diff -r 3047c6558547 -r 0e5de0f53e2e lib/libpthread/pthread_sa.c
--- a/lib/libpthread/pthread_sa.c Sat Jan 25 00:37:01 2003 +0000
+++ b/lib/libpthread/pthread_sa.c Sat Jan 25 00:43:38 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_sa.c,v 1.3 2003/01/18 18:45:56 christos Exp $ */
+/* $NetBSD: pthread_sa.c,v 1.4 2003/01/25 00:43:38 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
{
pthread_t t, self, next, intqueue;
int first = 1;
- int deliversig = 0, runalarms = 0;
+ int runalarms = 0;
siginfo_t *si;
PTHREADD_ADD(PTHREADD_UPCALLS);
@@ -130,7 +130,6 @@
break;
case SA_UPCALL_SIGNAL:
PTHREADD_ADD(PTHREADD_UP_SIGNAL);
- deliversig = 1;
break;
case SA_UPCALL_SIGEV:
PTHREADD_ADD(PTHREADD_UP_SIGEV);
@@ -189,15 +188,23 @@
* This also means that a thread that was interrupted to take
* a signal will be on a run queue, and not in upcall limbo.
*/
- if (deliversig) {
+ if (type == SA_UPCALL_SIGNAL) {
si = arg;
if (ev)
- pthread__signal(pthread__sa_id(sas[1]), si->si_signo,
- si->si_code);
+ pthread__signal(self, pthread__sa_id(sas[1]),
+ si->si_signo, si->si_code);
else
- pthread__signal(NULL, si->si_signo, si->si_code);
+ pthread__signal(self, NULL, si->si_signo, si->si_code);
+ } else if (type == SA_UPCALL_UNBLOCKED) {
+ /*
+ * A signal may have been presented to this thread while
+ * it was in the kernel.
+ */
+ t = pthread__sa_id(sas[1]);
+ if (t->pt_flags & PT_FLAG_SIGDEFERRED)
+ pthread__signal_deferred(self, t);
}
-
+
/*
* At this point everything on our list should be scheduled
* (or was an upcall).
diff -r 3047c6558547 -r 0e5de0f53e2e lib/libpthread/pthread_sig.c
--- a/lib/libpthread/pthread_sig.c Sat Jan 25 00:37:01 2003 +0000
+++ b/lib/libpthread/pthread_sig.c Sat Jan 25 00:43:38 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_sig.c,v 1.4 2003/01/24 17:43:45 jdolecek Exp $ */
+/* $NetBSD: pthread_sig.c,v 1.5 2003/01/25 00:43:38 nathanw Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -90,8 +90,8 @@
static void
-pthread__signal_tramp(int, int, struct sigaction *, ucontext_t *, sigset_t *,
- int, struct pthread_queue_t *, pthread_spin_t *);
+pthread__signal_tramp(int, int, void (*)(int, int, struct sigcontext *),
+ ucontext_t *, sigset_t *);
__strong_alias(__libc_thr_sigsetmask,pthread_sigmask)
@@ -167,7 +167,6 @@
}
pthread_sigmask(SIG_SETMASK, sigmask, &oldmask);
- self->pt_flags |= PT_FLAG_SIGCATCH;
self->pt_state = PT_STATE_BLOCKED_QUEUE;
self->pt_sleepobj = &pt_sigsuspended_cond;
self->pt_sleepq = &pt_sigsuspended;
@@ -178,7 +177,6 @@
pthread__block(self, &pt_sigsuspended_lock);
pthread__testcancel(self);
- self->pt_flags &= ~PT_FLAG_SIGCATCH;
pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
@@ -353,13 +351,10 @@
* willing thread, if t is null.
*/
void
-pthread__signal(pthread_t t, int sig, int code)
+pthread__signal(pthread_t self, pthread_t t, int sig, int code)
{
- pthread_t self, target, good, okay;
- sigset_t oldmask, *maskp;
- ucontext_t *uc;
+ pthread_t target, good, okay;
- self = pthread__self();
if (t) {
target = t;
pthread_spinlock(self, &target->pt_siglock);
@@ -455,14 +450,6 @@
* target process is a bug.
*/
assert(target->pt_state != PT_STATE_RUNNING);
- /*
- * Prevent anyone else from considering this thread for handling
- * more instances of this signal.
- */
- oldmask = target->pt_sigmask;
- __sigplusset(&target->pt_sigmask, &pt_sigacts[sig].sa_mask);
- __sigaddset14(&target->pt_sigmask, sig);
- pthread_spinunlock(self, &target->pt_siglock);
/*
* Holding the state lock blocks out cancellation and any other
@@ -483,14 +470,41 @@
case PT_STATE_BLOCKED_SYS:
/*
* The target is not on a queue at all, and won't run
- * again for a while. Try to wake it from its torpor.
+ * again for a while. Try to wake it from its torpor, then
+ * mark the signal for later processing.
*/
+ __sigaddset14(&target->pt_sigblocked, sig);
+ __sigaddset14(&target->pt_sigmask, sig);
+ target->pt_flags |= PT_FLAG_SIGDEFERRED;
+ pthread_spinunlock(self, &target->pt_siglock);
+ pthread_spinunlock(self, &target->pt_statelock);
_lwp_wakeup(target->pt_blockedlwp);
- break;
+ return;
default:
;
}
+ pthread__deliver_signal(self, target, sig, code);
+ pthread__sched(self, target);
+ pthread_spinunlock(self, &target->pt_statelock);
+}
+
+/* Must be called with target's siglock held */
+void
+pthread__deliver_signal(pthread_t self, pthread_t target, int sig, int code)
+{
+ sigset_t oldmask, *maskp;
+ ucontext_t *uc;
+
+ /*
+ * Prevent anyone else from considering this thread for handling
+ * more instances of this signal.
+ */
+ oldmask = target->pt_sigmask;
+ __sigplusset(&target->pt_sigmask, &pt_sigacts[sig].sa_mask);
+ __sigaddset14(&target->pt_sigmask, sig);
+ pthread_spinunlock(self, &target->pt_siglock);
+
/*
* We'd like to just pass oldmask to the
* pthread__signal_tramp(), but makecontext() can't reasonably
@@ -519,38 +533,36 @@
SDPRINTF(("(makecontext %p): target %p: sig: %d %d uc: %p oldmask: %08x\n",
self, target, sig, code, target->pt_uc, maskp->__bits[0]));
- makecontext(uc, pthread__signal_tramp, 8,
- sig, code, &pt_sigacts[sig], target->pt_uc, maskp,
- target->pt_state, target->pt_sleepq, target->pt_sleeplock);
+ makecontext(uc, pthread__signal_tramp, 5,
+ sig, code, pt_sigacts[sig].sa_handler, target->pt_uc, maskp);
target->pt_uc = uc;
-
- if (target->pt_state != PT_STATE_BLOCKED_SYS)
- pthread__sched(self, target);
- pthread_spinunlock(self, &target->pt_statelock);
}
+void
+pthread__signal_deferred(pthread_t self, pthread_t t)
+{
+ int i;
+
+ pthread_spinlock(self, &t->pt_siglock);
+
+ while ((i = firstsig(&t->pt_sigblocked)) != 0) {
+ __sigdelset14(&t->pt_sigblocked, i);
+ pthread__deliver_signal(self, t, i, 0);
+ }
+ t->pt_flags &= ~PT_FLAG_SIGDEFERRED;
+
+ pthread_spinunlock(self, &t->pt_siglock);
+}
static void
-pthread__signal_tramp(int sig, int code, struct sigaction *act,
- ucontext_t *uc, sigset_t *oldmask, int oldstate,
- struct pthread_queue_t *oldsleepq, pthread_spin_t *oldsleeplock)
+pthread__signal_tramp(int sig, int code,
+ void (*handler)(int, int, struct sigcontext *),
+ ucontext_t *uc, sigset_t *oldmask)
{
- void (*handler)(int, int, struct sigcontext *);
struct pthread__sigcontext psc;
- pthread_t self, next;
-
- self = pthread__self();
- SDPRINTF(("(tramp %p) sig %d uc %p oldmask %08x oldstate %d q %p\n",
- self, sig, uc, oldmask->__bits[0], oldstate, oldsleepq));
-
- /*
- * We should only ever get here if a handler is set. Signal
- * actions are process-global; a signal set to SIG_DFL or
- * SIG_IGN should be handled in the kernel (by being ignored
- * or killing the process) and never get this far.
- */
- handler = (void (*)(int, int, struct sigcontext *)) act->sa_handler;
+ SDPRINTF(("(tramp %p) sig %d uc %p oldmask %08x\n",
+ pthread__self(), sig, uc, oldmask->__bits[0]));
/*
* XXX we don't support siginfo here yet.
@@ -568,43 +580,6 @@
pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
/*
- * Go back to whatever queue we were found on, unless SIGCATCH
- * is set. When we are continued, the first thing we do will
- * be to jump back to the previous context.
- */
- if (self->pt_flags & PT_FLAG_SIGCATCH)
- _setcontext_u(uc);
-
- next = pthread__next(self);
- next->pt_state = PT_STATE_RUNNING;
- pthread_spinlock(self, &self->pt_statelock);
- if (oldstate == PT_STATE_RUNNABLE) {
- pthread_spinlock(self, &pthread__runqueue_lock);
- self->pt_state = PT_STATE_RUNNABLE;
Home |
Main Index |
Thread Index |
Old Index