Adjust the order of operations in spinlock_enter() and spinlock_exit() to

work properly with single-stepping in a kernel debugger.  Specifically,
these routines have always disabled interrupts before increasing the nesting
count and restored the prior state of interrupts after decreasing the nesting
count to avoid problems with a nested interrupt not disabling interrupts
when acquiring a spin lock.  However, trap interrupts for single-stepping
can still occur even when interrupts are disabled.  Now the saved state of
interrupts is not saved in the thread until after interrupts have been
disabled and the nesting count has been increased.  Similarly, the saved
state from the thread cannot be read once the nesting count has been
decreased to zero.  To fix this, use temporary variables to store interrupt
state and shuffle it between the thread's MD area and the appropriate
registers.

In cooperation with:	bde
MFC after:     1 month
This commit is contained in:
John Baldwin 2010-11-05 13:42:58 +00:00
parent 785901d6fa
commit 0108cce0a4
10 changed files with 93 additions and 41 deletions

View file

@ -1762,11 +1762,15 @@ void
spinlock_enter(void)
{
struct thread *td;
register_t flags;
td = curthread;
if (td->td_md.md_spinlock_count == 0)
td->td_md.md_saved_flags = intr_disable();
td->td_md.md_spinlock_count++;
if (td->td_md.md_spinlock_count == 0) {
flags = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_flags = flags;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -1774,12 +1778,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t flags;
td = curthread;
critical_exit();
flags = td->td_md.md_saved_flags;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
intr_restore(td->td_md.md_saved_flags);
intr_restore(flags);
}
/*

View file

@ -493,11 +493,15 @@ void
spinlock_enter(void)
{
struct thread *td;
register_t cspr;
td = curthread;
if (td->td_md.md_spinlock_count == 0)
td->td_md.md_saved_cspr = disable_interrupts(I32_bit | F32_bit);
td->td_md.md_spinlock_count++;
if (td->td_md.md_spinlock_count == 0) {
cspr = disable_interrupts(I32_bit | F32_bit);
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_cspr = cspr;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -505,12 +509,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t cspr;
td = curthread;
critical_exit();
cspr = td->td_md.md_saved_cspr;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
restore_interrupts(td->td_md.md_saved_cspr);
restore_interrupts(cspr);
}
/*

View file

@ -2997,11 +2997,15 @@ void
spinlock_enter(void)
{
struct thread *td;
register_t flags;
td = curthread;
if (td->td_md.md_spinlock_count == 0)
td->td_md.md_saved_flags = intr_disable();
td->td_md.md_spinlock_count++;
if (td->td_md.md_spinlock_count == 0) {
flags = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_flags = flags;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -3009,12 +3013,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t flags;
td = curthread;
critical_exit();
flags = td->td_md.md_saved_flags;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
intr_restore(td->td_md.md_saved_flags);
intr_restore(flags);
}
#if defined(I586_CPU) && !defined(NO_F00F_HACK)

View file

@ -513,11 +513,15 @@ void
spinlock_enter(void)
{
struct thread *td;
int intr;
td = curthread;
if (td->td_md.md_spinlock_count == 0)
td->td_md.md_saved_intr = intr_disable();
td->td_md.md_spinlock_count++;
if (td->td_md.md_spinlock_count == 0) {
intr = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_intr = intr;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -525,12 +529,14 @@ void
spinlock_exit(void)
{
struct thread *td;
int intr;
td = curthread;
critical_exit();
intr = td->td_md.md_saved_intr;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
intr_restore(td->td_md.md_saved_intr);
intr_restore(intr);
}
void

View file

@ -450,11 +450,15 @@ void
spinlock_enter(void)
{
struct thread *td;
register_t intr;
td = curthread;
if (td->td_md.md_spinlock_count == 0)
td->td_md.md_saved_intr = intr_disable();
td->td_md.md_spinlock_count++;
if (td->td_md.md_spinlock_count == 0) {
intr = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_intr = intr;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -462,12 +466,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t intr;
td = curthread;
critical_exit();
intr = td->td_md.md_saved_intr;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
intr_restore(td->td_md.md_saved_intr);
intr_restore(intr);
}
/*

View file

@ -2340,11 +2340,15 @@ void
spinlock_enter(void)
{
struct thread *td;
register_t flags;
td = curthread;
if (td->td_md.md_spinlock_count == 0)
td->td_md.md_saved_flags = intr_disable();
td->td_md.md_spinlock_count++;
if (td->td_md.md_spinlock_count == 0) {
flags = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_flags = flags;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -2352,12 +2356,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t flags;
td = curthread;
critical_exit();
flags = td->td_md.md_saved_flags;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
intr_restore(td->td_md.md_saved_flags);
intr_restore(flags);
}
#if defined(I586_CPU) && !defined(NO_F00F_HACK)

View file

@ -751,11 +751,15 @@ void
spinlock_enter(void)
{
struct thread *td;
register_t msr;
td = curthread;
if (td->td_md.md_spinlock_count == 0)
td->td_md.md_saved_msr = intr_disable();
td->td_md.md_spinlock_count++;
if (td->td_md.md_spinlock_count == 0) {
msr = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_msr = msr;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -763,12 +767,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t msr;
td = curthread;
critical_exit();
msr = td->td_md.md_saved_msr;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
intr_restore(td->td_md.md_saved_msr);
intr_restore(msr);
}
/*

View file

@ -516,11 +516,15 @@ void
spinlock_enter(void)
{
struct thread *td;
register_t msr;
td = curthread;
if (td->td_md.md_spinlock_count == 0)
td->td_md.md_saved_msr = intr_disable();
td->td_md.md_spinlock_count++;
if (td->td_md.md_spinlock_count == 0) {
msr = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_msr = msr;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -528,12 +532,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t msr;
td = curthread;
critical_exit();
msr = td->td_md.md_saved_msr;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
intr_restore(td->td_md.md_saved_msr);
intr_restore(msr);
}
/* Shutdown the CPU as much as possible. */

View file

@ -224,9 +224,10 @@ spinlock_enter(void)
if (td->td_md.md_spinlock_count == 0) {
pil = rdpr(pil);
wrpr(pil, 0, PIL_TICK);
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_pil = pil;
}
td->td_md.md_spinlock_count++;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -234,12 +235,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t pil;
td = curthread;
critical_exit();
pil = td->td_md.md_saved_pil;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0)
wrpr(pil, td->td_md.md_saved_pil, 0);
wrpr(pil, pil, 0);
}
static phandle_t

View file

@ -269,9 +269,10 @@ spinlock_enter(void)
td = curthread;
if (td->td_md.md_spinlock_count == 0) {
pil = intr_disable();
td->td_md.md_spinlock_count = 1;
td->td_md.md_saved_pil = pil;
}
td->td_md.md_spinlock_count++;
} else
td->td_md.md_spinlock_count++;
critical_enter();
}
@ -279,14 +280,14 @@ void
spinlock_exit(void)
{
struct thread *td;
register_t pil;
td = curthread;
critical_exit();
pil = td->td_md.md_saved_pil;
td->td_md.md_spinlock_count--;
if (td->td_md.md_spinlock_count == 0) {
intr_restore(td->td_md.md_saved_pil);
}
if (td->td_md.md_spinlock_count == 0)
intr_restore(pil);
}
unsigned