mirror of
https://github.com/apache/nuttx.git
synced 2026-06-05 15:58:59 +08:00
arch: remove up_cpu_pause up_cpu_resume up_cpu_paused up_cpu_pausereq
reason: To remove the "sync pause" and decouple the critical section from the dependency on enabling interrupts, after that we need to further implement "schedlock + spinlock". changelist 1 Modify the implementation of critical sections to no longer involve enabling interrupts or handling synchronous pause events. 2 GIC_SMP_CPUCALL attach to pause handler to remove arch interface up_cpu_paused_restore up_cpu_paused_save 3 Completely remove up_cpu_pause, up_cpu_resume, up_cpu_paused, and up_cpu_pausereq 4 change up_cpu_pause_async to up_send_cpu_sgi Signed-off-by: hujun5 <hujun5@xiaomi.com>
This commit is contained in:
+3
-136
@@ -75,96 +75,6 @@ volatile uint8_t g_cpu_nestcount[CONFIG_SMP_NCPUS];
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: irq_waitlock
|
||||
*
|
||||
* Description:
|
||||
* Spin to get g_cpu_irqlock, handling a known deadlock condition:
|
||||
*
|
||||
* A deadlock may occur if enter_critical_section is called from an
|
||||
* interrupt handler. Suppose:
|
||||
*
|
||||
* - CPUn is in a critical section and has the g_cpu_irqlock spinlock.
|
||||
* - CPUm takes an interrupt and attempts to enter the critical section.
|
||||
* - It spins waiting on g_cpu_irqlock with interrupts disabled.
|
||||
* - CPUn calls up_cpu_pause() to pause operation on CPUm. This will
|
||||
* issue an inter-CPU interrupt to CPUm
|
||||
* - But interrupts are disabled on CPUm so the up_cpu_pause() is never
|
||||
* handled, causing the deadlock.
|
||||
*
|
||||
* This same deadlock can occur in the normal tasking case:
|
||||
*
|
||||
* - A task on CPUn enters a critical section and has the g_cpu_irqlock
|
||||
* spinlock.
|
||||
* - Another task on CPUm attempts to enter the critical section but has
|
||||
* to wait, spinning to get g_cpu_irqlock with interrupts disabled.
|
||||
* - The task on CPUn causes a new task to become ready-to-run and the
|
||||
* scheduler selects CPUm. CPUm is requested to pause via a pause
|
||||
* interrupt.
|
||||
* - But the task on CPUm is also attempting to enter the critical
|
||||
* section. Since it is spinning with interrupts disabled, CPUm cannot
|
||||
* process the pending pause interrupt, causing the deadlock.
|
||||
*
|
||||
* This function detects this deadlock condition while spinning with
|
||||
* interrupts disabled.
|
||||
*
|
||||
* Input Parameters:
|
||||
* cpu - The index of CPU that is trying to enter the critical section.
|
||||
*
|
||||
* Returned Value:
|
||||
* True: The g_cpu_irqlock spinlock has been taken.
|
||||
* False: The g_cpu_irqlock spinlock has not been taken yet, but there is
|
||||
* a pending pause interrupt request.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static inline_function bool irq_waitlock(int cpu)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
|
||||
FAR struct tcb_s *tcb = current_task(cpu);
|
||||
|
||||
/* Notify that we are waiting for a spinlock */
|
||||
|
||||
sched_note_spinlock(tcb, &g_cpu_irqlock, NOTE_SPINLOCK_LOCK);
|
||||
#endif
|
||||
|
||||
/* Duplicate the spin_lock() logic from spinlock.c, but adding the check
|
||||
* for the deadlock condition.
|
||||
*/
|
||||
|
||||
while (!spin_trylock_wo_note(&g_cpu_irqlock))
|
||||
{
|
||||
/* Is a pause request pending? */
|
||||
|
||||
if (up_cpu_pausereq(cpu))
|
||||
{
|
||||
/* Yes.. some other CPU is requesting to pause this CPU!
|
||||
* Abort the wait and return false.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
|
||||
/* Notify that we have aborted the wait for the spinlock */
|
||||
|
||||
sched_note_spinlock(tcb, &g_cpu_irqlock, NOTE_SPINLOCK_ABORT);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* We have g_cpu_irqlock! */
|
||||
|
||||
#ifdef CONFIG_SCHED_INSTRUMENTATION_SPINLOCKS
|
||||
/* Notify that we have the spinlock */
|
||||
|
||||
sched_note_spinlock(tcb, &g_cpu_irqlock, NOTE_SPINLOCK_LOCKED);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@@ -198,7 +108,6 @@ irqstate_t enter_critical_section(void)
|
||||
* the local CPU.
|
||||
*/
|
||||
|
||||
try_again:
|
||||
ret = up_irq_save();
|
||||
|
||||
/* If called from an interrupt handler, then just take the spinlock.
|
||||
@@ -259,8 +168,6 @@ try_again:
|
||||
|
||||
else
|
||||
{
|
||||
int paused = false;
|
||||
|
||||
/* Make sure that the g_cpu_irqset was not already set
|
||||
* by previous logic on this CPU that was executed by the
|
||||
* interrupt handler. We know that the bit in g_cpu_irqset
|
||||
@@ -274,43 +181,14 @@ try_again:
|
||||
* no longer blocked by the critical section).
|
||||
*/
|
||||
|
||||
try_again_in_irq:
|
||||
if (!irq_waitlock(cpu))
|
||||
{
|
||||
/* We are in a deadlock condition due to a pending
|
||||
* pause request interrupt. Break the deadlock by
|
||||
* handling the pause request now.
|
||||
*/
|
||||
|
||||
if (!paused)
|
||||
{
|
||||
up_cpu_paused_save();
|
||||
}
|
||||
|
||||
DEBUGVERIFY(up_cpu_paused(cpu));
|
||||
paused = true;
|
||||
|
||||
DEBUGASSERT((g_cpu_irqset & (1 << cpu)) == 0);
|
||||
|
||||
/* NOTE: Here, this CPU does not hold g_cpu_irqlock,
|
||||
* so call irq_waitlock(cpu) to acquire g_cpu_irqlock.
|
||||
*/
|
||||
|
||||
goto try_again_in_irq;
|
||||
}
|
||||
|
||||
cpu_irqlock_set(cpu);
|
||||
spin_lock(&g_cpu_irqlock);
|
||||
cpu_irqlock_set(cpu);
|
||||
}
|
||||
|
||||
/* In any event, the nesting count is now one */
|
||||
|
||||
g_cpu_nestcount[cpu] = 1;
|
||||
|
||||
if (paused)
|
||||
{
|
||||
up_cpu_paused_restore();
|
||||
}
|
||||
|
||||
DEBUGASSERT(spin_is_locked(&g_cpu_irqlock) &&
|
||||
(g_cpu_irqset & (1 << cpu)) != 0);
|
||||
}
|
||||
@@ -354,18 +232,7 @@ try_again_in_irq:
|
||||
|
||||
DEBUGASSERT((g_cpu_irqset & (1 << cpu)) == 0);
|
||||
|
||||
if (!irq_waitlock(cpu))
|
||||
{
|
||||
/* We are in a deadlock condition due to a pending pause
|
||||
* request interrupt. Re-enable interrupts on this CPU
|
||||
* and try again. Briefly re-enabling interrupts should
|
||||
* be sufficient to permit processing the pending pause
|
||||
* request.
|
||||
*/
|
||||
|
||||
up_irq_restore(ret);
|
||||
goto try_again;
|
||||
}
|
||||
spin_lock(&g_cpu_irqlock);
|
||||
|
||||
/* Then set the lock count to 1.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user