sched_cpulocked: Avoid use of spinlock. That has been reported to cause a deadlock.

This commit is contained in:
Gregory Nutt
2016-12-28 12:10:17 -06:00
parent 72490f84e6
commit 88da65ad8a
+13 -26
View File
@@ -75,13 +75,7 @@
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static bool sched_cpulocked(int cpu) static bool sched_cpulocked(int cpu)
{ {
bool ret; cpu_set_t irqset;
/* First, get the g_cpu_irqsetlock spinlock so that g_cpu_irqset and
* g_cpu_irqlock will be stable throughout this function.
*/
spin_lock(&g_cpu_irqsetlock);
/* g_cpu_irqset is not valid in early phases of initialization */ /* g_cpu_irqset is not valid in early phases of initialization */
@@ -91,25 +85,26 @@ static bool sched_cpulocked(int cpu)
* the correct return value should always be false. * the correct return value should always be false.
*/ */
ret = false; return false;
} }
/* Test if g_cpu_irqlock is locked. We don't really need to use check /* Test if g_cpu_irqlock is locked. We don't really need to use check
* g_cpu_irqlock to do this, we can use the g_cpu_set. * g_cpu_irqlock to do this, we can use the g_cpu_set.
*
* Sample the g_cpu_irqset once. That is an atomic operation. All
* subsequent operations will operate on the sampled cpu set.
*/ */
else if (g_cpu_irqset != 0) irqset = (cpu_set_t)g_cpu_irqset;
if (irqset != 0)
{ {
/* Some CPU holds the lock. So g_cpu_irqlock should be locked */ /* Some CPU holds the lock. So g_cpu_irqlock should be locked.
* Return false if the 'cpu' is the holder of the lock; return
DEBUGASSERT(spin_islocked(&g_cpu_irqlock));
/* Return false if the 'cpu' is the holder of the lock; return
* true if g_cpu_irqlock is locked, but this CPU is not the * true if g_cpu_irqlock is locked, but this CPU is not the
* holder of the lock. * holder of the lock.
*/ */
ret = ((g_cpu_irqset & (1 << cpu)) == 0); return ((irqset & (1 << cpu)) == 0);
} }
/* No CPU holds the lock */ /* No CPU holds the lock */
@@ -117,22 +112,14 @@ static bool sched_cpulocked(int cpu)
else else
{ {
/* In this case g_cpu_irqlock should be unlocked. However, if /* In this case g_cpu_irqlock should be unlocked. However, if
* the lock was established in the interrupt handler AND there is * the lock was established in the interrupt handler AND there are
* no bits set in g_cpu_irqset, that probabaly means only that * no bits set in g_cpu_irqset, that probabaly means only that
* critical section was established from an interrupt handler. * critical section was established from an interrupt handler.
* Return false in either case.
*/ */
DEBUGASSERT(!spin_islocked(&g_cpu_irqlock) || up_interrupt_context()); return false;
/* Return false in either case. */
ret = false;
} }
/* Release the g_cpu_irqsetlock */
spin_unlock(&g_cpu_irqsetlock);
return ret;
} }
#endif #endif