From 35c8da34a801e52f303615fe9f73373f8366a123 Mon Sep 17 00:00:00 2001 From: Masayuki Ishikawa Date: Thu, 8 Oct 2020 14:39:22 +0900 Subject: [PATCH] sched: task: Fix nxtask_exit() for SMP Summary: - During Wi-Fi audio streaming test, I found a deadlock in nxtask_exit() - Actually, nxtask_exit() was called and tried to enter critical section - In enter_critical_section(), there is a deadlock avoidance logic - However, if switched to a new rtcb with irqcount=0, the logic did not work - Because the 2nd critical section was treated as if it were the 1st one - Actually, it tried to run the deadlock avoidance logic - But nxtask_exit() was called with critical section (i.e. IRQ already disabled) - So the logic did not work as expected because up_irq_restore() did not enable the IRQ. - This commit fixes this issue by incrementing irqcount before calling nxtask_terminate() - Also it adjusts g_cpu_irqlock and g_cpu_lockset Impact: - Affects SMP only Testing: - Tested with spresense:wifi_smp (smp, ostest, nxplayer, telnetd) - Tested with sabre-6quad:smp with QEMU (smp, ostest) - Tested with maix-bit:smp with QEMU (smp, ostest) - Tested with esp32-core:smp with QEMU (smp, ostest) Signed-off-by: Masayuki Ishikawa --- sched/task/task_exit.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/sched/task/task_exit.c b/sched/task/task_exit.c index 831cb3a1090..6607f49c40a 100644 --- a/sched/task/task_exit.c +++ b/sched/task/task_exit.c @@ -28,6 +28,10 @@ #include "sched/sched.h" +#ifdef CONFIG_SMP +# include "irq/irq.h" +#endif + #include "signal/signal.h" #include "task/task.h" @@ -140,7 +144,36 @@ int nxtask_exit(void) */ nxsched_add_blocked(dtcb, TSTATE_TASK_INACTIVE); + +#ifdef CONFIG_SMP + /* NOTE: + * During nxtask_terminate(), enter_critical_section() will be called + * to deallocate tcb. However, this would aquire g_cpu_irqlock if + * rtcb->irqcount = 0, event though we are in critical section. + * To prevent from aquiring, increment rtcb->irqcount here. + */ + + if (rtcb->irqcount == 0) + { + spin_setbit(&g_cpu_irqset, this_cpu(), &g_cpu_irqsetlock, + &g_cpu_irqlock); + } + + rtcb->irqcount++; +#endif + ret = nxtask_terminate(dtcb->pid, true); + +#ifdef CONFIG_SMP + rtcb->irqcount--; + + if (rtcb->irqcount == 0) + { + spin_clrbit(&g_cpu_irqset, this_cpu(), &g_cpu_irqsetlock, + &g_cpu_irqlock); + } +#endif + rtcb->task_state = TSTATE_TASK_RUNNING; /* Decrement the lockcount on rctb. */