summaryrefslogtreecommitdiff
path: root/lib/libpthread
diff options
context:
space:
mode:
authorcl <cl@NetBSD.org>2003-12-31 16:45:48 +0000
committercl <cl@NetBSD.org>2003-12-31 16:45:48 +0000
commit82b6b2dbdaf6abb10e0e7eb156395d705dece3bd (patch)
tree8c693675d750fa35be7448e43fc2ef27eb55e2b9 /lib/libpthread
parent01c51dab616b2fabe8a7485bc2df2eb47390879b (diff)
Handle block/unblock for threads in critical section without
sa_unblockyield. XXX g/c sa_unblockyield in kernel later
Diffstat (limited to 'lib/libpthread')
-rw-r--r--lib/libpthread/pthread.c20
-rw-r--r--lib/libpthread/pthread_int.h7
-rw-r--r--lib/libpthread/pthread_sa.c120
-rw-r--r--lib/libpthread/pthread_sig.c39
4 files changed, 80 insertions, 106 deletions
diff --git a/lib/libpthread/pthread.c b/lib/libpthread/pthread.c
index 4f3df6fbb12..f7b099e7689 100644
--- a/lib/libpthread/pthread.c
+++ b/lib/libpthread/pthread.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread.c,v 1.31 2003/12/18 15:39:56 christos Exp $ */
+/* $NetBSD: pthread.c,v 1.32 2003/12/31 16:45:48 cl Exp $ */
/*-
* Copyright (c) 2001,2002,2003 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread.c,v 1.31 2003/12/18 15:39:56 christos Exp $");
+__RCSID("$NetBSD: pthread.c,v 1.32 2003/12/31 16:45:48 cl Exp $");
#include <err.h>
#include <errno.h>
@@ -397,6 +397,12 @@ pthread_suspend_np(pthread_t thread)
SDPRINTF(("(pthread_suspend_np %p) Suspend thread %p (state %d).\n",
self, thread, thread->pt_state));
pthread_spinlock(self, &thread->pt_statelock);
+ if (thread->pt_blockgen != thread->pt_unblockgen) {
+ /* XXX flaglock? */
+ thread->pt_flags |= PT_FLAG_SUSPENDED;
+ pthread_spinunlock(self, &thread->pt_statelock);
+ return 0;
+ }
switch (thread->pt_state) {
case PT_STATE_RUNNING:
pthread__abort(); /* XXX */
@@ -414,11 +420,6 @@ pthread_suspend_np(pthread_t thread)
PTQ_REMOVE(thread->pt_sleepq, thread, pt_sleep);
pthread_spinunlock(self, thread->pt_sleeplock);
break;
- case PT_STATE_BLOCKED_SYS:
- /* XXX flaglock? */
- thread->pt_flags |= PT_FLAG_SUSPENDED;
- pthread_spinunlock(self, &thread->pt_statelock);
- return 0;
default:
break; /* XXX */
}
@@ -787,8 +788,7 @@ pthread_cancel(pthread_t thread)
if (!(thread->pt_state == PT_STATE_RUNNING ||
thread->pt_state == PT_STATE_RUNNABLE ||
- thread->pt_state == PT_STATE_BLOCKED_QUEUE ||
- thread->pt_state == PT_STATE_BLOCKED_SYS))
+ thread->pt_state == PT_STATE_BLOCKED_QUEUE))
return ESRCH;
self = pthread__self();
@@ -799,7 +799,7 @@ pthread_cancel(pthread_t thread)
thread->pt_cancel = 1;
pthread_spinunlock(self, &thread->pt_flaglock);
pthread_spinlock(self, &thread->pt_statelock);
- if (thread->pt_state == PT_STATE_BLOCKED_SYS) {
+ if (thread->pt_blockgen != thread->pt_unblockgen) {
/*
* It's sleeping in the kernel. If we can wake
* it up, it will notice the cancellation when
diff --git a/lib/libpthread/pthread_int.h b/lib/libpthread/pthread_int.h
index 9675cfaa60a..7c0c659ead0 100644
--- a/lib/libpthread/pthread_int.h
+++ b/lib/libpthread/pthread_int.h
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_int.h,v 1.22 2003/11/27 16:30:54 cl Exp $ */
+/* $NetBSD: pthread_int.h,v 1.23 2003/12/31 16:45:48 cl Exp $ */
/*-
* Copyright (c) 2001,2002,2003 The NetBSD Foundation, Inc.
@@ -92,6 +92,8 @@ struct __pthread_st {
int pt_cancel; /* Deferred cancellation */
int pt_spinlocks; /* Number of spinlocks held. */
int pt_blockedlwp; /* LWP/SA number when blocked */
+ int pt_blockgen; /* SA_UPCALL_BLOCKED counter */
+ int pt_unblockgen; /* SA_UPCALL_UNBLOCKED counter */
int pt_errno; /* Thread-specific errno. */
@@ -111,6 +113,7 @@ struct __pthread_st {
stack_t pt_stack; /* Our stack */
ucontext_t *pt_uc; /* Saved context when we're stopped */
ucontext_t *pt_trapuc; /* Kernel-saved context */
+ ucontext_t *pt_blockuc; /* Kernel-saved context when blocked */
sigset_t pt_sigmask; /* Signals we won't take. */
sigset_t pt_siglist; /* Signals pending for us. */
@@ -179,7 +182,7 @@ struct pthread_lock_ops {
/* Thread states */
#define PT_STATE_RUNNING 1
#define PT_STATE_RUNNABLE 2
-#define PT_STATE_BLOCKED_SYS 3
+#define _PT_STATE_BLOCKED_SYS 3 /* Only used in libpthread_dbg */
#define PT_STATE_BLOCKED_QUEUE 4
#define PT_STATE_ZOMBIE 5
#define PT_STATE_DEAD 6
diff --git a/lib/libpthread/pthread_sa.c b/lib/libpthread/pthread_sa.c
index bc77ce4adb1..98e5bd6e67b 100644
--- a/lib/libpthread/pthread_sa.c
+++ b/lib/libpthread/pthread_sa.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_sa.c,v 1.21 2003/11/17 22:59:00 cl Exp $ */
+/* $NetBSD: pthread_sa.c,v 1.22 2003/12/31 16:45:48 cl Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread_sa.c,v 1.21 2003/11/17 22:59:00 cl Exp $");
+__RCSID("$NetBSD: pthread_sa.c,v 1.22 2003/12/31 16:45:48 cl Exp $");
#include <err.h>
#include <errno.h>
@@ -65,6 +65,8 @@ __RCSID("$NetBSD: pthread_sa.c,v 1.21 2003/11/17 22:59:00 cl Exp $");
#define PUC(t) ((t)->pt_trapuc ? 'T':'U') , UC(t)
extern struct pthread_queue_t pthread__allqueue;
+extern pthread_spin_t pthread__deadqueue_lock;
+extern struct pthread_queue_t pthread__reidlequeue;
#define PTHREAD_RRTIMER_INTERVAL_DEFAULT 100
static pthread_mutex_t rrtimer_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -108,48 +110,13 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
/* Don't handle this SA in the usual processing. */
t = pthread__sa_id(sas[1]);
pthread__assert(self->pt_spinlocks == 0);
- if (t->pt_spinlocks > 0 || t->pt_next ||
- t->pt_type == PT_THREAD_UPCALL ||
- t->pt_blockedlwp == -1) {
- if (t->pt_blockedlwp != -1) {
- SDPRINTF(("(up %p) unblocking %p "
- "(uc: T %p pc: %lx sp: %lx) "
- "spinlocks: %d, pt_next: %p\n",
- self, t, sas[1]->sa_context,
- pthread__uc_pc(sas[1]->sa_context),
- pthread__uc_sp(sas[1]->sa_context),
- t->pt_spinlocks, t->pt_next));
- if (sa_unblockyield(sas[1]->sa_id, &self->pt_next,
- &self->pt_stack) != 0)
- pthread__abort();
- /* maybe NOTREACHED */
- }
- pthread__assert(t->pt_blockedlwp == -1);
- t->pt_blockedlwp = 0;
- SDPRINTF(("(up %p) unblocking switchto to %p(%d) "
- "(uc: T %p pc: %lx) chain %p "
- "spinlocks: %d, pt_next: %p\n",
- self, t, t->pt_type, sas[1]->sa_context,
- pthread__uc_pc(sas[1]->sa_context),
- self->pt_next, t->pt_spinlocks,
- t->pt_next));
- self->pt_switchtouc = t->pt_trapuc;
- self->pt_switchto = t;
- pthread__switch(self, self->pt_next);
- /*NOTREACHED*/
- pthread__abort();
- }
- /* We can take spinlocks now */
if (t->pt_type == PT_THREAD_IDLE) {
- SDPRINTF(("(up %p) unblocking idle %p (uc: %c %p)\n",
- self, t, PUC(t)));
- if (sa_unblockyield(sas[1]->sa_id, NULL,
- &self->pt_stack) != 0)
- pthread__abort();
- t->pt_blockedlwp = 0;
- /* XXX need flaglock? */
- if ((t->pt_flags & PT_FLAG_IDLED) == 0)
- pthread__sched_bulk(self, t);
+ pthread_spinlock(self, &pthread__deadqueue_lock);
+ if (t->pt_flags & PT_FLAG_IDLED) {
+ PTQ_REMOVE(&pthread__reidlequeue, t, pt_runq);
+ t->pt_flags &= PT_FLAG_IDLED;
+ }
+ pthread_spinunlock(self, &pthread__deadqueue_lock);
}
} else {
/*
@@ -167,35 +134,24 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
pthread__sched_bulk(self, intqueue);
if (schedqueue != self)
pthread__sched_bulk(self, schedqueue);
- }
- pthread__sched_idle2(self);
+ pthread__sched_idle2(self);
+ }
switch (type) {
case SA_UPCALL_BLOCKED:
PTHREADD_ADD(PTHREADD_UP_BLOCK);
t = pthread__sa_id(sas[1]);
- pthread__assert(t->pt_type != PT_THREAD_UPCALL);
- if (t->pt_type == PT_THREAD_IDLE)
- break;
- pthread_spinlock(self, &t->pt_statelock);
- t->pt_state = PT_STATE_BLOCKED_SYS;
+ SDPRINTF(("(up %p) blocker %d %p(%d)\n", self, 1, t,
+ t->pt_type));
+ t->pt_blockuc = sas[1]->sa_context;
t->pt_blockedlwp = sas[1]->sa_id;
+ t->pt_blockgen++;
if (t->pt_cancel)
_lwp_wakeup(t->pt_blockedlwp);
- pthread_spinunlock(self, &t->pt_statelock);
#ifdef PTHREAD__DEBUG
t->blocks++;
#endif
- /*
- * Because we might be preempted between the check and
- * the set, we set the unblocked thread trapuc again
- * below in the SA_UPCALL_UNBLOCKED case.
- */
- if (t->pt_trapuc == NULL)
- t->pt_trapuc = sas[1]->sa_context;
- SDPRINTF(("(up %p) blocker %d %p(%d)\n", self, 1, t,
- t->pt_type));
break;
case SA_UPCALL_NEWPROC:
PTHREADD_ADD(PTHREADD_UP_NEW);
@@ -208,13 +164,6 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
schedqueue = NULL;
for (i = 0; i < ev; i++) {
t = pthread__sa_id(sas[1 + i]);
- if (t->pt_blockedlwp != 0) {
- /* Set unblocked thread trapuc again. */
- t->pt_trapuc = sas[1 + i]->sa_context;
- t->pt_next = schedqueue;
- schedqueue = t;
- t->pt_blockedlwp = 0;
- }
/*
* A signal may have been presented to this
* thread while it was in the kernel.
@@ -275,6 +224,16 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
* (or was an upcall).
*/
pthread__assert(self->pt_spinlocks == 0);
+ if (self->pt_next) {
+ SDPRINTF(("(up %p) chain switching to %p (uc: %c %p pc: %lx)\n",
+ self, self->pt_next, PUC(self->pt_next),
+ pthread__uc_pc(UC(self->pt_next))));
+ self->pt_switchtouc = UC(self);
+ self->pt_switchto = self;
+ pthread__switch(self, self->pt_next);
+ /*NOTREACHED*/
+ pthread__abort();
+ }
next = pthread__next(self);
next->pt_state = PT_STATE_RUNNING;
SDPRINTF(("(up %p) switching to %p (uc: %c %p pc: %lx)\n",
@@ -309,12 +268,18 @@ pthread__find_interrupted(int type, struct sa_t *sas[], int ev, int intr,
SDPRINTF(("(fi %p) victim %d %p(%d)", self, i, victim,
victim->pt_type));
if (type == SA_UPCALL_UNBLOCKED && i < ev) {
- if (victim->pt_blockedlwp == 0) {
- SDPRINTF((" unblock before block\n"));
- victim->pt_blockedlwp = -1;
- } else
- SDPRINTF((" event\n"));
- continue;
+ victim->pt_unblockgen++;
+#ifdef PTHREAD__DEBUG
+ if (victim->pt_blockgen != victim->pt_unblockgen) {
+ SDPRINTF((" unblock before block"));
+ } else if (victim->pt_type == PT_THREAD_UPCALL ||
+ victim->pt_spinlocks > 0 ||
+ victim->pt_next) {
+ SDPRINTF((" critical"));
+ } else {
+ SDPRINTF((" event"));
+ }
+#endif
}
if (victim->pt_type == PT_THREAD_UPCALL) {
/* Case 1: Upcall. Must be resumed. */
@@ -417,7 +382,7 @@ pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
PTHREADD_ADD(PTHREADD_RESOLVELOCKS);
recycleq = NULL;
- runq = NULL;
+ runq = self;
intqueue = *intqueuep;
switchto = NULL;
victim = intqueue;
@@ -507,6 +472,11 @@ pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
intqueue = next;
victim->pt_next = recycleq;
recycleq = victim;
+ if (victim->pt_switchto == victim) {
+ victim->pt_switchto = NULL;
+ victim->pt_switchtouc = NULL;
+ SDPRINTF((" switchto self"));
+ }
} else {
/*
* Not finished yet.
@@ -618,7 +588,6 @@ pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
self, intqueue, PUC(intqueue),
pthread__uc_pc(UC(intqueue)),
pthread__uc_sp(UC(intqueue))));
- pthread__assert(intqueue->pt_state != PT_STATE_BLOCKED_SYS);
pthread__switch(self, intqueue);
SDPRINTF(("(rl %p) returned from chain\n",
self));
@@ -636,7 +605,6 @@ pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
PUC(self->pt_next),
pthread__uc_pc(UC(self->pt_next)),
pthread__uc_sp(UC(self->pt_next))));
- pthread__assert(self->pt_next->pt_state != PT_STATE_BLOCKED_SYS);
pthread__switch(self, self->pt_next);
}
diff --git a/lib/libpthread/pthread_sig.c b/lib/libpthread/pthread_sig.c
index 54ead0a432f..d866b0a042f 100644
--- a/lib/libpthread/pthread_sig.c
+++ b/lib/libpthread/pthread_sig.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pthread_sig.c,v 1.31 2003/11/25 23:55:27 cl Exp $ */
+/* $NetBSD: pthread_sig.c,v 1.32 2003/12/31 16:45:48 cl Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: pthread_sig.c,v 1.31 2003/11/25 23:55:27 cl Exp $");
+__RCSID("$NetBSD: pthread_sig.c,v 1.32 2003/12/31 16:45:48 cl Exp $");
/* We're interposing a specific version of the signal interface. */
#define __LIBC12_SOURCE__
@@ -658,7 +658,7 @@ pthread__signal(pthread_t self, pthread_t t, siginfo_t *si)
self, target, target->pt_state, target->pt_sigmask.__bits[0]));
if (!__sigismember14(&target->pt_sigmask,
si->si_signo)) {
- if (target->pt_state != PT_STATE_BLOCKED_SYS) {
+ if (target->pt_blockgen == target->pt_unblockgen) {
good = target;
/* Leave target locked */
break;
@@ -775,13 +775,30 @@ pthread__kill(pthread_t self, pthread_t target, siginfo_t *si)
* XXX As long as this is uniprocessor, encountering a running
* target process is a bug.
*/
- pthread__assert(target->pt_state != PT_STATE_RUNNING);
+ pthread__assert(target->pt_state != PT_STATE_RUNNING ||
+ target->pt_blockgen != target->pt_unblockgen);
/*
* Holding the state lock blocks out cancellation and any other
* attempts to set this thread up to take a signal.
*/
pthread_spinlock(self, &target->pt_statelock);
+ if (target->pt_blockgen != target->pt_unblockgen) {
+ /*
+ * The target is not on a queue at all, and
+ * won't run again for a while. Try to wake it
+ * from its torpor, then mark the signal for
+ * later processing.
+ */
+ __sigaddset14(&target->pt_sigblocked, si->si_signo);
+ __sigaddset14(&target->pt_sigmask, si->si_signo);
+ pthread_spinlock(self, &target->pt_flaglock);
+ target->pt_flags |= PT_FLAG_SIGDEFERRED;
+ pthread_spinunlock(self, &target->pt_flaglock);
+ pthread_spinunlock(self, &target->pt_statelock);
+ _lwp_wakeup(target->pt_blockedlwp);
+ return;
+ }
switch (target->pt_state) {
case PT_STATE_SUSPENDED:
pthread_spinlock(self, &pthread__runqueue_lock);
@@ -798,20 +815,6 @@ pthread__kill(pthread_t self, pthread_t target, siginfo_t *si)
PTQ_REMOVE(target->pt_sleepq, target, pt_sleep);
pthread_spinunlock(self, target->pt_sleeplock);
break;
- 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, then
- * mark the signal for later processing.
- */
- __sigaddset14(&target->pt_sigblocked, si->si_signo);
- __sigaddset14(&target->pt_sigmask, si->si_signo);
- pthread_spinlock(self, &target->pt_flaglock);
- target->pt_flags |= PT_FLAG_SIGDEFERRED;
- pthread_spinunlock(self, &target->pt_flaglock);
- pthread_spinunlock(self, &target->pt_statelock);
- _lwp_wakeup(target->pt_blockedlwp);
- return;
default:
;
}