SMP: fix crash when switch to new task which is still running

cpu0 thread0:                        cpu1:
sched_yield()
nxsched_set_priority()
nxsched_running_setpriority()
nxsched_reprioritize_rtr()
nxsched_add_readytorun()
up_cpu_pause()
                                     IRQ enter
                                     arm64_pause_handler()
                                     enter_critical_section() begin
                                     up_cpu_paused() pick thread0
                                     arm64_restorestate() set thread0 tcb->xcp.regs to CURRENT_REGS
up_switch_context()
  thread0 -> thread1
arm64_syscall()
    case SYS_switch_context
     change thread0 tcb->xcp.regs
    restore_critical_section()
                                     enter_critical_section() done
                                     leave_critical_section()
                                     IRQ leave with restore CURRENT_REGS
                                     ERROR !!!

Reason:
As descript above, cpu0 swith task: thread0 -> thread1, and the
syscall() execute slowly, this time cpu1 pick thread0 to run at
up_cpu_paused(). Then cpu0 syscall execute, cpu1 IRQ leave error.

Resolve:
Move arm64_restorestate() after enter_critical_section() done

This is a continued fix with:
https://github.com/apache/nuttx/pull/6833

Signed-off-by: ligd <liguiding1@xiaomi.com>
This commit is contained in:
ligd
2024-02-22 10:44:56 +08:00
committed by Masayuki Ishikawa
parent 27ef7576ff
commit 2241969e5a
13 changed files with 789 additions and 278 deletions
+12
View File
@@ -252,6 +252,8 @@ 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
@@ -273,7 +275,13 @@ try_again_in_irq:
* handling the pause request now.
*/
if (!paused)
{
up_cpu_paused_save();
}
DEBUGVERIFY(up_cpu_paused(cpu));
paused = true;
/* NOTE: As the result of up_cpu_paused(cpu), this CPU
* might set g_cpu_irqset in nxsched_resume_scheduler()
@@ -305,6 +313,10 @@ try_again_in_irq:
spin_setbit(&g_cpu_irqset, cpu, &g_cpu_irqsetlock,
&g_cpu_irqlock);
if (paused)
{
up_cpu_paused_restore();
}
}
}
else