diff --git a/arch/arm/src/armv7-a/arm_cpupause.c b/arch/arm/src/armv7-a/arm_cpupause.c index ed098c4ba77..4c7b6a71ddb 100644 --- a/arch/arm/src/armv7-a/arm_cpupause.c +++ b/arch/arm/src/armv7-a/arm_cpupause.c @@ -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; } diff --git a/arch/arm/src/armv7-r/arm_cpupause.c b/arch/arm/src/armv7-r/arm_cpupause.c index 921b1f0f399..3e8102d6f51 100644 --- a/arch/arm/src/armv7-r/arm_cpupause.c +++ b/arch/arm/src/armv7-r/arm_cpupause.c @@ -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; } diff --git a/arch/arm/src/cxd56xx/cxd56_cpupause.c b/arch/arm/src/cxd56xx/cxd56_cpupause.c index 476c684331a..2e1a6a95428 100644 --- a/arch/arm/src/cxd56xx/cxd56_cpupause.c +++ b/arch/arm/src/cxd56xx/cxd56_cpupause.c @@ -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; } diff --git a/arch/arm/src/lc823450/lc823450_cpupause.c b/arch/arm/src/lc823450/lc823450_cpupause.c index d00c939ef2c..fc5a246157b 100644 --- a/arch/arm/src/lc823450/lc823450_cpupause.c +++ b/arch/arm/src/lc823450/lc823450_cpupause.c @@ -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; } diff --git a/arch/arm/src/rp2040/rp2040_cpupause.c b/arch/arm/src/rp2040/rp2040_cpupause.c index 2d74d775119..44e100ef419 100644 --- a/arch/arm/src/rp2040/rp2040_cpupause.c +++ b/arch/arm/src/rp2040/rp2040_cpupause.c @@ -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; } /**************************************************************************** diff --git a/arch/arm/src/sam34/sam4cm_cpupause.c b/arch/arm/src/sam34/sam4cm_cpupause.c index f81902bd9b8..dc80b3cc9d1 100644 --- a/arch/arm/src/sam34/sam4cm_cpupause.c +++ b/arch/arm/src/sam34/sam4cm_cpupause.c @@ -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; } diff --git a/arch/arm64/src/common/arm64_cpupause.c b/arch/arm64/src/common/arm64_cpupause.c index 0d7acefee80..943b56c4218 100644 --- a/arch/arm64/src/common/arm64_cpupause.c +++ b/arch/arm64/src/common/arm64_cpupause.c @@ -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; } diff --git a/arch/risc-v/src/common/riscv_cpupause.c b/arch/risc-v/src/common/riscv_cpupause.c index 8f5c2924330..730fc55170f 100644 --- a/arch/risc-v/src/common/riscv_cpupause.c +++ b/arch/risc-v/src/common/riscv_cpupause.c @@ -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; } diff --git a/arch/sim/src/sim/sim_smpsignal.c b/arch/sim/src/sim/sim_smpsignal.c index 0f9ba526da3..aef103b1942 100644 --- a/arch/sim/src/sim/sim_smpsignal.c +++ b/arch/sim/src/sim/sim_smpsignal.c @@ -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; } diff --git a/arch/sparc/src/s698pm/s698pm_cpupause.c b/arch/sparc/src/s698pm/s698pm_cpupause.c index 16449cabf8a..3e7101a66df 100644 --- a/arch/sparc/src/s698pm/s698pm_cpupause.c +++ b/arch/sparc/src/s698pm/s698pm_cpupause.c @@ -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; } diff --git a/arch/xtensa/src/common/xtensa_cpupause.c b/arch/xtensa/src/common/xtensa_cpupause.c index 9a8697f3cf5..12cfcfa5498 100644 --- a/arch/xtensa/src/common/xtensa_cpupause.c +++ b/arch/xtensa/src/common/xtensa_cpupause.c @@ -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; } diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index 785b113b94f..2abbdf0b757 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -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 * diff --git a/sched/irq/irq_csection.c b/sched/irq/irq_csection.c index 799182960d7..0c804c7460e 100644 --- a/sched/irq/irq_csection.c +++ b/sched/irq/irq_csection.c @@ -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