arch & sched: task: Fix up_exit() and nxtask_exit() for SMP

Summary:
- During repeating ostest with sabre-6quad:smp (QEMU),
  I noticed that pthread_rwlock_test sometimes stops
- Finally, I found that nxtask_exit() released a critical
  section too early before context switching which resulted in
  selecting inappropriate TCB
- This commit fixes this issue by moving nxsched_resume_scheduler()
  from nxtask_exit() to up_exit() and also removing
  spin_setbit() and spin_clrbit() from nxtask_exit()
  because the caller holds a critical section
- To be consistent with non-SMP cases, the above changes
  were done for all CPU architectures

Impact:
- This commit affects all CPU architectures regardless of SMP

Testing:
- Tested with ostest with the following configs
- sabre-6quad:smp (QEMU, dev board), sabre-6quad:nsh (QEMU)
- spresense:wifi_smp
- sim:smp, sim:ostest
- maix-bit:smp (QEMU)
- esp32-devkitc:smp (QEMU)
- lc823450-xgevk:rndis

Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
This commit is contained in:
Masayuki Ishikawa 2020-12-22 08:49:19 +09:00 committed by Xiang Xiao
parent d5a1c8cae8
commit ec73a4e69c
16 changed files with 78 additions and 23 deletions

View file

@ -150,6 +150,12 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases
* NOTE: the API also adjusts the global IRQ control for SMP
*/
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -165,6 +165,10 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases */
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -149,6 +149,10 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases */
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -167,6 +167,12 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases
* NOTE: the API also adjusts the global IRQ control for SMP
*/
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -160,6 +160,10 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for RR & SPORADIC cases */
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -158,6 +158,10 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases */
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running task
* is closed down gracefully (data caches dump, MMU flushed) and set up the

View file

@ -165,6 +165,10 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases */
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -149,6 +149,10 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for RR & SPORADIC cases */
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -167,6 +167,12 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases
* NOTE: the API also adjusts the global IRQ control for SMP
*/
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -86,6 +86,12 @@ void up_exit(int status)
tcb = this_task();
sinfo("New Active Task TCB=%p\n", tcb);
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases
* NOTE: the API also adjusts the global IRQ control for SMP
*/
nxsched_resume_scheduler(tcb);
/* The way that we handle signals in the simulation is kind of
* a kludge. This would be unsafe in a truly multi-threaded, interrupt
* driven environment.

View file

@ -149,6 +149,12 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases
* NOTE: the API also adjusts the global IRQ control for SMP
*/
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -153,6 +153,12 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases
* NOTE: the API also adjusts the global IRQ control for SMP
*/
nxsched_resume_scheduler(tcb);
/* Context switch, rearrange MMU */
up_restore_auxstate(tcb);

View file

@ -172,6 +172,12 @@ void up_exit(int status)
tcb = this_task();
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases
* NOTE: the API also adjusts the global IRQ control for SMP
*/
nxsched_resume_scheduler(tcb);
#if XCHAL_CP_NUM > 0
/* Set up the co-processor state for the newly started thread. */

View file

@ -150,6 +150,10 @@ void up_exit(int status)
tcb = this_task();
sinfo("New Active Task TCB=%p\n", tcb);
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases */
nxsched_resume_scheduler(tcb);
/* Then switch contexts */
RESTORE_USERCONTEXT(tcb);

View file

@ -152,6 +152,10 @@ void up_exit(int status)
tcb = this_task();
sinfo("New Active Task TCB=%p\n", tcb);
/* Adjusts time slice for SCHED_RR & SCHED_SPORADIC cases */
nxsched_resume_scheduler(tcb);
#ifdef CONFIG_ARCH_ADDRENV
/* Make sure that the address environment for the previously running
* task is closed down gracefully (data caches dump, MMU flushed) and

View file

@ -119,12 +119,12 @@ int nxtask_exit(void)
rtcb = this_task();
#endif
/* Because clearing the global IRQ control in nxsched_remove_readytorun()
* was moved to nxsched_resume_scheduler(). So call the API here.
/* NOTE: nxsched_resume_scheduler() was moved to up_exit()
* because the global IRQ control for SMP should be deferred until
* context switching, otherwise, the context switching would be done
* without a critical section
*/
nxsched_resume_scheduler(rtcb);
/* We are now in a bad state -- the head of the ready to run task list
* does not correspond to the thread that is running. Disabling pre-
* emption on this TCB and marking the new ready-to-run task as not
@ -162,19 +162,6 @@ int nxtask_exit(void)
* To prevent from aquiring, increment rtcb->irqcount here.
*/
if (rtcb->irqcount == 0)
{
/* NOTE: Need to aquire g_cpu_irqlock here again before
* calling spin_setbit() becauses it was released in
* the above nxsched_resume_scheduler()
*/
DEBUGVERIFY(irq_waitlock(this_cpu()));
spin_setbit(&g_cpu_irqset, this_cpu(), &g_cpu_irqsetlock,
&g_cpu_irqlock);
}
rtcb->irqcount++;
#endif
@ -182,12 +169,6 @@ int nxtask_exit(void)
#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;