Simplify pthread__upcall() a bit by moving lock resolution before the big
switch statement, and moving upcall-type-specific code into that switch. Beneficial side effect: don't manipulate a statelock before lock resolution occurs.
This commit is contained in:
parent
7d8ac1f6c2
commit
a8773f45f8
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: pthread_sa.c,v 1.4 2003/01/25 00:43:38 nathanw Exp $ */
|
/* $NetBSD: pthread_sa.c,v 1.5 2003/01/30 01:04:50 nathanw Exp $ */
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||||
|
@ -90,7 +90,6 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
|
||||||
{
|
{
|
||||||
pthread_t t, self, next, intqueue;
|
pthread_t t, self, next, intqueue;
|
||||||
int first = 1;
|
int first = 1;
|
||||||
int runalarms = 0;
|
|
||||||
siginfo_t *si;
|
siginfo_t *si;
|
||||||
|
|
||||||
PTHREADD_ADD(PTHREADD_UPCALLS);
|
PTHREADD_ADD(PTHREADD_UPCALLS);
|
||||||
|
@ -100,55 +99,13 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
|
||||||
|
|
||||||
if (sas[0]->sa_id > pthread__maxlwps)
|
if (sas[0]->sa_id > pthread__maxlwps)
|
||||||
pthread__maxlwps = sas[0]->sa_id;
|
pthread__maxlwps = sas[0]->sa_id;
|
||||||
|
|
||||||
SDPRINTF(("(up %p) type %d LWP %d ev %d intr %d\n", self,
|
SDPRINTF(("(up %p) type %d LWP %d ev %d intr %d\n", self,
|
||||||
type, sas[0]->sa_id, ev ? sas[1]->sa_id : 0,
|
type, sas[0]->sa_id, ev ? sas[1]->sa_id : 0,
|
||||||
intr ? sas[ev+intr]->sa_id : 0));
|
intr ? sas[ev+intr]->sa_id : 0));
|
||||||
switch (type) {
|
|
||||||
case SA_UPCALL_BLOCKED:
|
if (type == SA_UPCALL_BLOCKED)
|
||||||
t = pthread__sa_id(sas[1]);
|
|
||||||
pthread_spinlock(self, &t->pt_statelock);
|
|
||||||
t->pt_state = PT_STATE_BLOCKED_SYS;
|
|
||||||
pthread_spinunlock(self, &t->pt_statelock);
|
|
||||||
#ifdef PTHREAD__DEBUG
|
|
||||||
t->blocks++;
|
|
||||||
#endif
|
|
||||||
t->pt_blockedlwp = sas[1]->sa_id;
|
|
||||||
if (t->pt_cancel)
|
|
||||||
_lwp_wakeup(t->pt_blockedlwp);
|
|
||||||
t->pt_uc = sas[1]->sa_context;
|
|
||||||
first++; /* Don't handle this SA in the usual processing. */
|
first++; /* Don't handle this SA in the usual processing. */
|
||||||
PTHREADD_ADD(PTHREADD_UP_BLOCK);
|
|
||||||
break;
|
|
||||||
case SA_UPCALL_NEWPROC:
|
|
||||||
PTHREADD_ADD(PTHREADD_UP_NEW);
|
|
||||||
break;
|
|
||||||
case SA_UPCALL_PREEMPTED:
|
|
||||||
PTHREADD_ADD(PTHREADD_UP_PREEMPT);
|
|
||||||
break;
|
|
||||||
case SA_UPCALL_UNBLOCKED:
|
|
||||||
PTHREADD_ADD(PTHREADD_UP_UNBLOCK);
|
|
||||||
break;
|
|
||||||
case SA_UPCALL_SIGNAL:
|
|
||||||
PTHREADD_ADD(PTHREADD_UP_SIGNAL);
|
|
||||||
break;
|
|
||||||
case SA_UPCALL_SIGEV:
|
|
||||||
PTHREADD_ADD(PTHREADD_UP_SIGEV);
|
|
||||||
si = arg;
|
|
||||||
if (si->si_sigval.sival_int == PT_ALARMTIMER_MAGIC)
|
|
||||||
runalarms = 1;
|
|
||||||
/*
|
|
||||||
* PT_RRTIMER_MAGIC doesn't need explicit handling;
|
|
||||||
* the per-thread work below will put the interrupted
|
|
||||||
* thread on the back of the run queue, and
|
|
||||||
* pthread_next() will get one from the front.
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
case SA_UPCALL_USER:
|
|
||||||
/* We don't send ourselves one of these. */
|
|
||||||
default:
|
|
||||||
/*CONSTCOND*/
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do per-thread work, including saving the context.
|
* Do per-thread work, including saving the context.
|
||||||
|
@ -162,40 +119,35 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
|
||||||
&intqueue, self) > 0)
|
&intqueue, self) > 0)
|
||||||
pthread__resolve_locks(self, &intqueue);
|
pthread__resolve_locks(self, &intqueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We can take spinlocks now */
|
||||||
pthread__sched_idle2(self);
|
pthread__sched_idle2(self);
|
||||||
if (intqueue)
|
if (intqueue)
|
||||||
pthread__sched_bulk(self, intqueue);
|
pthread__sched_bulk(self, intqueue);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
/*
|
case SA_UPCALL_BLOCKED:
|
||||||
* Run the alarm queue (handled after lock resolution since
|
t = pthread__sa_id(sas[1]);
|
||||||
* alarm handling requires locks).
|
pthread_spinlock(self, &t->pt_statelock);
|
||||||
*/
|
t->pt_state = PT_STATE_BLOCKED_SYS;
|
||||||
if (runalarms)
|
t->pt_blockedlwp = sas[1]->sa_id;
|
||||||
pthread__alarm_process(self, arg);
|
if (t->pt_cancel)
|
||||||
|
_lwp_wakeup(t->pt_blockedlwp);
|
||||||
/*
|
pthread_spinunlock(self, &t->pt_statelock);
|
||||||
* Note that we handle signals after handling
|
#ifdef PTHREAD__DEBUG
|
||||||
* spinlock preemption. This is because spinlocks are only
|
t->blocks++;
|
||||||
* used internally to the thread library and we don't want to
|
#endif
|
||||||
* expose the middle of them to a signal. While this means
|
t->pt_uc = sas[1]->sa_context;
|
||||||
* that synchronous instruction traps that occur inside
|
PTHREADD_ADD(PTHREADD_UP_BLOCK);
|
||||||
* critical sections in this library (SIGFPE, SIGILL, SIGBUS,
|
break;
|
||||||
* SIGSEGV) won't be handled at the precise location where
|
case SA_UPCALL_NEWPROC:
|
||||||
* they occured, that's okay, because (1) we don't use any FP
|
PTHREADD_ADD(PTHREADD_UP_NEW);
|
||||||
* and (2) SIGILL/SIGBUS/SIGSEGV should really just core dump.
|
break;
|
||||||
*
|
case SA_UPCALL_PREEMPTED:
|
||||||
* This also means that a thread that was interrupted to take
|
PTHREADD_ADD(PTHREADD_UP_PREEMPT);
|
||||||
* a signal will be on a run queue, and not in upcall limbo.
|
break;
|
||||||
*/
|
case SA_UPCALL_UNBLOCKED:
|
||||||
if (type == SA_UPCALL_SIGNAL) {
|
PTHREADD_ADD(PTHREADD_UP_UNBLOCK);
|
||||||
si = arg;
|
|
||||||
if (ev)
|
|
||||||
pthread__signal(self, pthread__sa_id(sas[1]),
|
|
||||||
si->si_signo, si->si_code);
|
|
||||||
else
|
|
||||||
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
|
* A signal may have been presented to this thread while
|
||||||
* it was in the kernel.
|
* it was in the kernel.
|
||||||
|
@ -203,6 +155,49 @@ pthread__upcall(int type, struct sa_t *sas[], int ev, int intr, void *arg)
|
||||||
t = pthread__sa_id(sas[1]);
|
t = pthread__sa_id(sas[1]);
|
||||||
if (t->pt_flags & PT_FLAG_SIGDEFERRED)
|
if (t->pt_flags & PT_FLAG_SIGDEFERRED)
|
||||||
pthread__signal_deferred(self, t);
|
pthread__signal_deferred(self, t);
|
||||||
|
break;
|
||||||
|
case SA_UPCALL_SIGNAL:
|
||||||
|
PTHREADD_ADD(PTHREADD_UP_SIGNAL);
|
||||||
|
/*
|
||||||
|
* Note that we handle signals after handling
|
||||||
|
* spinlock preemption. This is because spinlocks are only
|
||||||
|
* used internally to the thread library and we don't want to
|
||||||
|
* expose the middle of them to a signal. While this means
|
||||||
|
* that synchronous instruction traps that occur inside
|
||||||
|
* critical sections in this library (SIGFPE, SIGILL, SIGBUS,
|
||||||
|
* SIGSEGV) won't be handled at the precise location where
|
||||||
|
* they occured, that's okay, because (1) we don't use any FP
|
||||||
|
* and (2) SIGILL/SIGBUS/SIGSEGV should really just core dump.
|
||||||
|
*
|
||||||
|
* This also means that a thread that was interrupted to take
|
||||||
|
* a signal will be on a run queue, and not in upcall limbo.
|
||||||
|
*/
|
||||||
|
si = arg;
|
||||||
|
if (ev)
|
||||||
|
pthread__signal(self, pthread__sa_id(sas[1]),
|
||||||
|
si->si_signo, si->si_code);
|
||||||
|
else
|
||||||
|
pthread__signal(self, NULL, si->si_signo, si->si_code);
|
||||||
|
break;
|
||||||
|
case SA_UPCALL_SIGEV:
|
||||||
|
PTHREADD_ADD(PTHREADD_UP_SIGEV);
|
||||||
|
si = arg;
|
||||||
|
SDPRINTF(("(up %p) sigev val %x\n", self,
|
||||||
|
si->si_sigval.sival_int));
|
||||||
|
if (si->si_sigval.sival_int == PT_ALARMTIMER_MAGIC)
|
||||||
|
pthread__alarm_process(self, arg);
|
||||||
|
/*
|
||||||
|
* PT_RRTIMER_MAGIC doesn't need explicit handling;
|
||||||
|
* the per-thread work below will put the interrupted
|
||||||
|
* thread on the back of the run queue, and
|
||||||
|
* pthread_next() will get one from the front.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
case SA_UPCALL_USER:
|
||||||
|
/* We don't send ourselves one of these. */
|
||||||
|
default:
|
||||||
|
/*CONSTCOND*/
|
||||||
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue