Interrupts need to be disabled on entry to cpu_sleep() for ARM. Given

that and the need to be in a critical section when switching to idleclock
mode for event timers, use spinlock_enter()/exit() to achieve both needs.

The ARM WFI (wait for interrupt) instruction blocks until an interrupt is
asserted, and it will unblock even if interrupts are masked, and it will
unblock immediately if an interrupt is already pending.  It is necessary
to execute it with interrupts disabled, otherwise the interrupt that
should unblock it may occur and be serviced just prior to executing the
instruction.  At that point the system is inappropriately asleep until
the next timer tick or some other random interrupt happens.

In general, interrupts need to be disabled continuously from the time the
decision is made that there is no work to be done and sleeping is needed
until actually going to sleep, to avoid a race where handling a new
interrupt changes the basis for deciding there is no work to be done.

Submitted by:	hps@ (in slightly different form)
This commit is contained in:
Ian Lepore 2014-05-12 13:05:03 +00:00
parent a485f139c3
commit 02bb9ba1cc

View File

@ -426,9 +426,9 @@ cpu_idle(int busy)
CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
busy, curcpu);
spinlock_enter();
#ifndef NO_EVENTTIMERS
if (!busy) {
critical_enter();
cpu_idleclock();
}
#endif
@ -437,9 +437,9 @@ cpu_idle(int busy)
#ifndef NO_EVENTTIMERS
if (!busy) {
cpu_activeclock();
critical_exit();
}
#endif
spinlock_exit();
CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
busy, curcpu);
}