SMP: irq_csection() has a bad assumption. It assumed that the state of certain variables. That was true on entry into the interrupt handler, but might change to the execution of logic within the interrupt handler.
This commit is contained in:
parent
8e029f019b
commit
8602e8a8a9
|
@ -129,7 +129,7 @@ irqstate_t enter_critical_section(void)
|
||||||
/* We are in an interrupt handler. How can this happen?
|
/* We are in an interrupt handler. How can this happen?
|
||||||
*
|
*
|
||||||
* 1. We were not in a critical section when the interrupt
|
* 1. We were not in a critical section when the interrupt
|
||||||
* occurred. In this case:
|
* occurred. In this case, the interrupt was entered with:
|
||||||
*
|
*
|
||||||
* g_cpu_irqlock = SP_UNLOCKED.
|
* g_cpu_irqlock = SP_UNLOCKED.
|
||||||
* g_cpu_nestcount = 0
|
* g_cpu_nestcount = 0
|
||||||
|
@ -152,6 +152,11 @@ irqstate_t enter_critical_section(void)
|
||||||
* g_cpu_irqlock = SP_LOCKED.
|
* g_cpu_irqlock = SP_LOCKED.
|
||||||
* g_cpu_nestcount > 0
|
* g_cpu_nestcount > 0
|
||||||
* The bit in g_cpu_irqset for this CPU hould be zero
|
* The bit in g_cpu_irqset for this CPU hould be zero
|
||||||
|
*
|
||||||
|
* NOTE: However, the interrupt entry conditions can change due
|
||||||
|
* to previous processing by the interrupt handler that may
|
||||||
|
* instantiate a new thread that has irqcount > 0 and may then
|
||||||
|
* set the bit in g_cpu_irqset and g_cpu_irqlock = SP_LOCKED
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Handle nested calls to enter_critical_section() from the same
|
/* Handle nested calls to enter_critical_section() from the same
|
||||||
|
@ -165,19 +170,29 @@ irqstate_t enter_critical_section(void)
|
||||||
g_cpu_nestcount[cpu] < UINT8_MAX);
|
g_cpu_nestcount[cpu] < UINT8_MAX);
|
||||||
g_cpu_nestcount[cpu]++;
|
g_cpu_nestcount[cpu]++;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
/* This is the first call to enter_critical_section from the
|
||||||
/* First call to enter_critical_section. Test assumptions, then
|
* interrupt handler.
|
||||||
* wait until we have the lock.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT((g_cpu_irqset & (1 << cpu)) == 0);
|
else
|
||||||
|
{
|
||||||
|
/* Make sure that the g_cpu_irqlock() was not already set
|
||||||
|
* by previous logic on this CPU that was executed by the
|
||||||
|
* interrupt handler.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Wait until we can get the spinlock (meaning that we are no
|
if ((g_cpu_irqset & (1 << cpu)) == 0)
|
||||||
* longer in the critical section).
|
{
|
||||||
|
/* Wait until we can get the spinlock (meaning that we are
|
||||||
|
* no longer in the critical section).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spin_lock(&g_cpu_irqlock);
|
spin_lock(&g_cpu_irqlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In any event, the nesting count is now one */
|
||||||
|
|
||||||
g_cpu_nestcount[cpu] = 1;
|
g_cpu_nestcount[cpu] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue