* Recycle upcall stacks as soon as possible rather than waiting to
accumulate half of the total number. There are too many ways for the SA subsystem to deadlock waiting for stacks that userland has no reason to recycle. * Consolidate switchto handling in pthread_resolve_locks(). * Add code to re-chain the preempting parents of switchtos. * Tweak debuglog output in a couple of cases.
This commit is contained in:
parent
c7bcda3906
commit
5faa7f5bef
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: pthread_sa.c,v 1.7 2003/03/08 08:03:35 lukem Exp $ */
|
/* $NetBSD: pthread_sa.c,v 1.8 2003/05/26 19:41:03 nathanw Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__RCSID("$NetBSD: pthread_sa.c,v 1.7 2003/03/08 08:03:35 lukem Exp $");
|
__RCSID("$NetBSD: pthread_sa.c,v 1.8 2003/05/26 19:41:03 nathanw Exp $");
|
||||||
|
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -62,12 +62,6 @@ __RCSID("$NetBSD: pthread_sa.c,v 1.7 2003/03/08 08:03:35 lukem Exp $");
|
||||||
|
|
||||||
extern struct pthread_queue_t pthread__allqueue;
|
extern struct pthread_queue_t pthread__allqueue;
|
||||||
|
|
||||||
static stack_t recyclable[2][(PT_UPCALLSTACKS/2)+1];
|
|
||||||
static int recycle_count;
|
|
||||||
static int recycle_threshold;
|
|
||||||
static int recycle_side;
|
|
||||||
static pthread_spin_t recycle_lock;
|
|
||||||
|
|
||||||
#define PTHREAD_RRTIMER_INTERVAL_DEFAULT 100
|
#define PTHREAD_RRTIMER_INTERVAL_DEFAULT 100
|
||||||
static pthread_mutex_t rrtimer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t rrtimer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static timer_t pthread_rrtimer;
|
static timer_t pthread_rrtimer;
|
||||||
|
@ -138,6 +132,9 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
|
||||||
t->blocks++;
|
t->blocks++;
|
||||||
#endif
|
#endif
|
||||||
t->pt_uc = sas[1]->sa_context;
|
t->pt_uc = sas[1]->sa_context;
|
||||||
|
SDPRINTF(("(up %p) blocker %d %p(%d)\n", self, 1, t,
|
||||||
|
t->pt_type));
|
||||||
|
|
||||||
PTHREADD_ADD(PTHREADD_UP_BLOCK);
|
PTHREADD_ADD(PTHREADD_UP_BLOCK);
|
||||||
break;
|
break;
|
||||||
case SA_UPCALL_NEWPROC:
|
case SA_UPCALL_NEWPROC:
|
||||||
|
@ -325,6 +322,7 @@ void
|
||||||
pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
|
pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
|
||||||
{
|
{
|
||||||
pthread_t victim, prev, next, switchto, runq, recycleq, intqueue;
|
pthread_t victim, prev, next, switchto, runq, recycleq, intqueue;
|
||||||
|
pthread_t tmp;
|
||||||
pthread_spin_t *lock;
|
pthread_spin_t *lock;
|
||||||
|
|
||||||
PTHREADD_ADD(PTHREADD_RESOLVELOCKS);
|
PTHREADD_ADD(PTHREADD_RESOLVELOCKS);
|
||||||
|
@ -349,14 +347,6 @@ pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
|
||||||
next = victim->pt_next;
|
next = victim->pt_next;
|
||||||
SDPRINTF(("(rl %p) victim %p (uc %p)", self,
|
SDPRINTF(("(rl %p) victim %p (uc %p)", self,
|
||||||
victim, victim->pt_uc));
|
victim, victim->pt_uc));
|
||||||
if (victim->pt_switchto) {
|
|
||||||
PTHREADD_ADD(PTHREADD_SWITCHTO);
|
|
||||||
switchto = victim->pt_switchto;
|
|
||||||
switchto->pt_uc = victim->pt_switchtouc;
|
|
||||||
victim->pt_switchto = NULL;
|
|
||||||
victim->pt_switchtouc = NULL;
|
|
||||||
SDPRINTF((" switchto: %p", switchto));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (victim->pt_type == PT_THREAD_NORMAL) {
|
if (victim->pt_type == PT_THREAD_NORMAL) {
|
||||||
SDPRINTF((" normal"));
|
SDPRINTF((" normal"));
|
||||||
|
@ -458,7 +448,15 @@ pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switchto) {
|
if (victim->pt_switchto) {
|
||||||
|
PTHREADD_ADD(PTHREADD_SWITCHTO);
|
||||||
|
switchto = victim->pt_switchto;
|
||||||
|
switchto->pt_uc = victim->pt_switchtouc;
|
||||||
|
victim->pt_switchto = NULL;
|
||||||
|
victim->pt_switchtouc = NULL;
|
||||||
|
SDPRINTF((" switchto: %p (uc %p)", switchto,
|
||||||
|
switchto->pt_uc));
|
||||||
|
|
||||||
pthread__assert(switchto->pt_spinlocks == 0);
|
pthread__assert(switchto->pt_spinlocks == 0);
|
||||||
/*
|
/*
|
||||||
* Threads can have switchto set to themselves
|
* Threads can have switchto set to themselves
|
||||||
|
@ -466,9 +464,27 @@ pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
|
||||||
* on the run queue twice.
|
* on the run queue twice.
|
||||||
*/
|
*/
|
||||||
if (switchto != victim) {
|
if (switchto != victim) {
|
||||||
|
if (switchto->pt_next) {
|
||||||
|
/*
|
||||||
|
* The thread being switched
|
||||||
|
* to was preempted and
|
||||||
|
* continued. Find the
|
||||||
|
* preempter and put it on
|
||||||
|
* our continuation chain.
|
||||||
|
*/
|
||||||
|
SDPRINTF((" switchto chained"));
|
||||||
|
for ( tmp = switchto;
|
||||||
|
tmp->pt_parent != NULL;
|
||||||
|
tmp = tmp->pt_parent)
|
||||||
|
SDPRINTF((" parent: %p", tmp));
|
||||||
|
tmp->pt_parent = self;
|
||||||
|
tmp->pt_next = intqueue;
|
||||||
|
intqueue = tmp;
|
||||||
|
} else {
|
||||||
switchto->pt_next = runq;
|
switchto->pt_next = runq;
|
||||||
runq = switchto;
|
runq = switchto;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
switchto = NULL;
|
switchto = NULL;
|
||||||
}
|
}
|
||||||
SDPRINTF(("\n"));
|
SDPRINTF(("\n"));
|
||||||
|
@ -515,45 +531,24 @@ pthread__resolve_locks(pthread_t self, pthread_t *intqueuep)
|
||||||
void
|
void
|
||||||
pthread__recycle_bulk(pthread_t self, pthread_t qhead)
|
pthread__recycle_bulk(pthread_t self, pthread_t qhead)
|
||||||
{
|
{
|
||||||
int do_recycle, my_side, ret;
|
int count, ret;
|
||||||
pthread_t upcall;
|
pthread_t upcall;
|
||||||
|
stack_t recyclable[PT_UPCALLSTACKS];
|
||||||
|
|
||||||
|
count = 0;
|
||||||
while(qhead != NULL) {
|
while(qhead != NULL) {
|
||||||
pthread_spinlock(self, &recycle_lock);
|
|
||||||
my_side = recycle_side;
|
|
||||||
do_recycle = 0;
|
|
||||||
while ((qhead != NULL) &&
|
|
||||||
(recycle_count < recycle_threshold)) {
|
|
||||||
upcall = qhead;
|
upcall = qhead;
|
||||||
qhead = qhead->pt_next;
|
qhead = qhead->pt_next;
|
||||||
upcall->pt_state = PT_STATE_RUNNABLE;
|
upcall->pt_state = PT_STATE_RUNNABLE;
|
||||||
upcall->pt_next = NULL;
|
upcall->pt_next = NULL;
|
||||||
upcall->pt_parent = NULL;
|
upcall->pt_parent = NULL;
|
||||||
recyclable[my_side][recycle_count] = upcall->pt_stack;
|
recyclable[count] = upcall->pt_stack;
|
||||||
recycle_count++;
|
count++;
|
||||||
}
|
|
||||||
SDPRINTF(("(recycle_bulk %p) count %d\n", self, recycle_count));
|
|
||||||
if (recycle_count == recycle_threshold) {
|
|
||||||
recycle_side = 1 - recycle_side;
|
|
||||||
recycle_count = 0;
|
|
||||||
do_recycle = 1;
|
|
||||||
}
|
|
||||||
pthread_spinunlock(self, &recycle_lock);
|
|
||||||
if (do_recycle) {
|
|
||||||
SDPRINTF(("(recycle_bulk %p) recycled %d stacks\n", self, recycle_threshold));
|
|
||||||
|
|
||||||
ret = sa_stacks(recycle_threshold,
|
|
||||||
recyclable[my_side]);
|
|
||||||
if (ret != recycle_threshold) {
|
|
||||||
printf("Error: recycle_threshold\n");
|
|
||||||
printf("ret: %d threshold: %d\n",
|
|
||||||
ret, recycle_threshold);
|
|
||||||
/*CONSTCOND*/
|
|
||||||
pthread__assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = sa_stacks(count, recyclable);
|
||||||
|
pthread__assert(ret == count);
|
||||||
|
SDPRINTF(("(recycle_bulk %p) recycled %d stacks\n", self, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -563,37 +558,13 @@ pthread__recycle_bulk(pthread_t self, pthread_t qhead)
|
||||||
void
|
void
|
||||||
pthread__sa_recycle(pthread_t old, pthread_t new)
|
pthread__sa_recycle(pthread_t old, pthread_t new)
|
||||||
{
|
{
|
||||||
int do_recycle, my_side, ret;
|
|
||||||
|
|
||||||
do_recycle = 0;
|
|
||||||
|
|
||||||
old->pt_next = NULL;
|
old->pt_next = NULL;
|
||||||
old->pt_parent = NULL;
|
old->pt_parent = NULL;
|
||||||
old->pt_state = PT_STATE_RUNNABLE;
|
old->pt_state = PT_STATE_RUNNABLE;
|
||||||
|
|
||||||
pthread_spinlock(new, &recycle_lock);
|
sa_stacks(1, &old->pt_stack);
|
||||||
|
SDPRINTF(("(recycle %p) recycled %p\n", new, old));
|
||||||
my_side = recycle_side;
|
|
||||||
recyclable[my_side][recycle_count] = old->pt_stack;
|
|
||||||
recycle_count++;
|
|
||||||
SDPRINTF(("(recycle %p) count %d\n", new, recycle_count));
|
|
||||||
|
|
||||||
if (recycle_count == recycle_threshold) {
|
|
||||||
/* Switch */
|
|
||||||
recycle_side = 1 - recycle_side;
|
|
||||||
recycle_count = 0;
|
|
||||||
do_recycle = 1;
|
|
||||||
}
|
|
||||||
pthread_spinunlock(new, &recycle_lock);
|
|
||||||
|
|
||||||
if (do_recycle) {
|
|
||||||
ret = sa_stacks(recycle_threshold, recyclable[my_side]);
|
|
||||||
SDPRINTF(("(recycle %p) recycled %d stacks\n", new, recycle_threshold));
|
|
||||||
if (ret != recycle_threshold) {
|
|
||||||
/*CONSTCOND*/
|
|
||||||
pthread__assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -678,8 +649,6 @@ pthread__sa_start(void)
|
||||||
PTQ_INSERT_HEAD(&pthread__allqueue, t, pt_allq);
|
PTQ_INSERT_HEAD(&pthread__allqueue, t, pt_allq);
|
||||||
}
|
}
|
||||||
|
|
||||||
recycle_threshold = PT_UPCALLSTACKS/2;
|
|
||||||
|
|
||||||
ret = sa_stacks(i, upcall_stacks);
|
ret = sa_stacks(i, upcall_stacks);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
abort();
|
abort();
|
||||||
|
|
Loading…
Reference in New Issue