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

View File

@ -84,6 +84,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -113,24 +155,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
/* Release the g_cpu_paused spinlock to synchronize with the
* requesting CPU.
*/
@ -147,11 +171,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* This CPU has been resumed. Restore the exception context of the TCB at
* the (new) head of the assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -168,8 +212,6 @@ int up_cpu_paused(int cpu)
*/
arm_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}

View File

@ -84,6 +84,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -113,24 +155,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
/* Release the g_cpu_paused spinlock to synchronize with the
* requesting CPU.
*/
@ -147,11 +171,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* This CPU has been resumed. Restore the exception context of the TCB at
* the (new) head of the assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -168,8 +212,6 @@ int up_cpu_paused(int cpu)
*/
arm_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}

View File

@ -166,6 +166,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -202,24 +244,6 @@ int up_cpu_paused(int cpu)
return OK;
}
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
/* Wait for the spinlock to be released */
spin_unlock(&g_cpu_paused[cpu]);
@ -230,11 +254,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -251,8 +295,6 @@ int up_cpu_paused(int cpu)
*/
arm_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}

View File

@ -94,6 +94,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -123,24 +165,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
/* Wait for the spinlock to be released */
spin_unlock(&g_cpu_paused[cpu]);
@ -151,11 +175,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -173,10 +217,6 @@ int up_cpu_paused(int cpu)
arm_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}
@ -307,7 +347,7 @@ int up_cpu_pause(int cpu)
* called. g_cpu_paused will be unlocked in any case.
*/
return 0;
return OK;
}
/****************************************************************************
@ -357,5 +397,5 @@ int up_cpu_resume(int cpu)
spin_unlock(&g_cpu_resumed[cpu]);
return 0;
return OK;
}

View File

@ -134,6 +134,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -163,24 +205,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
/* Wait for the spinlock to be released */
spin_unlock(&g_cpu_paused[cpu]);
@ -191,11 +215,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -212,8 +256,6 @@ int up_cpu_paused(int cpu)
*/
arm_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}
@ -357,7 +399,7 @@ int up_cpu_pause(int cpu)
* called. g_cpu_paused will be unlocked in any case.
*/
return 0;
return OK;
}
/****************************************************************************
@ -406,7 +448,7 @@ int up_cpu_resume(int cpu)
spin_lock(&g_cpu_resumed[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return 0;
return OK;
}
/****************************************************************************

View File

@ -96,6 +96,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -125,24 +167,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm_savestate(tcb->xcp.regs);
/* Wait for the spinlock to be released */
spin_unlock(&g_cpu_paused[cpu]);
@ -153,11 +177,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -174,8 +218,6 @@ int up_cpu_paused(int cpu)
*/
arm_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}

View File

@ -83,6 +83,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm64_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -112,24 +154,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
arm64_savestate(tcb->xcp.regs);
/* Release the g_cpu_paused spinlock to synchronize with the
* requesting CPU.
*/
@ -150,7 +174,31 @@ int up_cpu_paused(int cpu)
* the (new) head of the assigned task list.
*/
tcb = this_task();
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -167,8 +215,6 @@ int up_cpu_paused(int cpu)
*/
arm64_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}

View File

@ -84,6 +84,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
riscv_savecontext(tcb);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -113,24 +155,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
riscv_savecontext(tcb);
/* Wait for the spinlock to be released */
spin_unlock(&g_cpu_paused[cpu]);
@ -141,11 +165,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -163,9 +207,6 @@ int up_cpu_paused(int cpu)
riscv_restorecontext(tcb);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}
@ -280,7 +321,7 @@ int up_cpu_pause(int cpu)
* called. g_cpu_paused will be unlocked in any case.
*/
return 0;
return OK;
}
/****************************************************************************
@ -330,5 +371,5 @@ int up_cpu_resume(int cpu)
spin_unlock(&g_cpu_resumed[cpu]);
return 0;
return OK;
}

View File

@ -127,6 +127,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
sim_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -156,24 +198,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = current_task(cpu);
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
sim_savestate(tcb->xcp.regs);
/* Wait for the spinlock to be released */
spin_unlock(&g_cpu_paused[cpu]);
@ -184,16 +208,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = current_task(cpu);
return OK;
}
/* 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.
*/
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -214,8 +253,6 @@ int up_cpu_paused(int cpu)
*/
sim_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}

View File

@ -84,6 +84,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
sparc_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -113,24 +155,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
sparc_savestate(tcb->xcp.regs);
/* Wait for the spinlock to be released */
spin_unlock(&g_cpu_paused[cpu]);
@ -141,11 +165,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -163,9 +207,6 @@ int up_cpu_paused(int cpu)
sparc_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}
@ -283,7 +324,7 @@ int up_cpu_pause(int cpu)
* called. g_cpu_paused will be unlocked in any case.
*/
return 0;
return OK;
}
/****************************************************************************
@ -333,5 +374,5 @@ int up_cpu_resume(int cpu)
spin_unlock(&g_cpu_resumed[cpu]);
return 0;
return OK;
}

View File

@ -69,6 +69,48 @@ bool up_cpu_pausereq(int cpu)
return spin_is_locked(&g_cpu_paused[cpu]);
}
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_save(void)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
xtensa_savestate(tcb->xcp.regs);
return OK;
}
/****************************************************************************
* Name: up_cpu_paused
*
@ -98,24 +140,6 @@ bool up_cpu_pausereq(int cpu)
int up_cpu_paused(int cpu)
{
struct tcb_s *tcb = this_task();
/* Update scheduler parameters */
nxsched_suspend_scheduler(tcb);
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we are paused */
sched_note_cpu_paused(tcb);
#endif
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
xtensa_savestate(tcb->xcp.regs);
/* Wait for the spinlock to be released */
spin_unlock(&g_cpu_paused[cpu]);
@ -126,11 +150,31 @@ int up_cpu_paused(int cpu)
spin_lock(&g_cpu_wait[cpu]);
/* Restore the exception context of the tcb at the (new) head of the
* assigned task list.
*/
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
tcb = this_task();
return OK;
}
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
int up_cpu_paused_restore(void)
{
struct tcb_s *tcb = this_task();
#ifdef CONFIG_SCHED_INSTRUMENTATION
/* Notify that we have resumed */
@ -148,9 +192,6 @@ int up_cpu_paused(int cpu)
xtensa_restorestate(tcb->xcp.regs);
spin_unlock(&g_cpu_wait[cpu]);
spin_unlock(&g_cpu_resumed[cpu]);
return OK;
}

View File

@ -2256,6 +2256,29 @@ int up_cpu_pause(int cpu);
bool up_cpu_pausereq(int cpu);
#endif
/****************************************************************************
* Name: up_cpu_paused_save
*
* Description:
* Handle a pause request from another CPU. Normally, this logic is
* executed from interrupt handling logic within the architecture-specific
* However, it is sometimes necessary to perform the pending
* pause operation in other contexts where the interrupt cannot be taken
* in order to avoid deadlocks.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
#ifdef CONFIG_SMP
int up_cpu_paused_save(void);
#endif
/****************************************************************************
* Name: up_cpu_paused
*
@ -2287,6 +2310,26 @@ bool up_cpu_pausereq(int cpu);
int up_cpu_paused(int cpu);
#endif
/****************************************************************************
* Name: up_cpu_paused_restore
*
* Description:
* Restore the state of the CPU after it was paused via up_cpu_pause(),
* and resume normal tasking.
*
* Input Parameters:
* None
*
* Returned Value:
* On success, OK is returned. Otherwise, a negated errno value indicating
* the nature of the failure is returned.
*
****************************************************************************/
#ifdef CONFIG_SMP
int up_cpu_paused_restore(void);
#endif
/****************************************************************************
* Name: up_cpu_resume
*

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