You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/10/06 01:27:02 UTC

(nuttx) branch master updated: sched: replace sync pause with async pause for nxtask_terminate

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new eae57cb0e6 sched: replace sync pause with async pause for nxtask_terminate
eae57cb0e6 is described below

commit eae57cb0e6c2677dcf42e95959a8dd9946889602
Author: hujun5 <hu...@xiaomi.com>
AuthorDate: Sun Sep 29 19:52:57 2024 +0800

    sched: replace sync pause with async pause for nxtask_terminate
    
    reason:
    In the kernel, we are planning to remove all occurrences of up_cpu_pause as one of the steps to
    simplify the implementation of critical sections. The goal is to enable spin_lock_irqsave to encapsulate critical sections,
    thereby facilitating the replacement of critical sections(big lock) with smaller spin_lock_irqsave(small lock)
    
    Signed-off-by: hujun5 <hu...@xiaomi.com>
---
 arch/arm/src/common/arm_exit.c         |  6 ---
 arch/arm64/src/common/arm64_exit.c     |  6 ---
 arch/avr/src/common/avr_exit.c         |  6 ---
 arch/hc/src/common/hc_exit.c           |  6 ---
 arch/mips/src/common/mips_exit.c       |  6 ---
 arch/misoc/src/lm32/lm32_exit.c        |  6 ---
 arch/misoc/src/minerva/minerva_exit.c  |  6 ---
 arch/or1k/src/common/or1k_exit.c       |  6 ---
 arch/renesas/src/common/renesas_exit.c |  6 ---
 arch/risc-v/src/common/riscv_exit.c    |  6 ---
 arch/sim/src/sim/sim_exit.c            |  6 ---
 arch/sparc/src/common/sparc_exit.c     |  6 ---
 arch/tricore/src/common/tricore_exit.c |  6 ---
 arch/x86/src/common/x86_exit.c         |  6 ---
 arch/x86_64/src/common/x86_64_exit.c   |  6 ---
 arch/xtensa/src/common/xtensa_exit.c   |  6 ---
 arch/z16/src/common/z16_exit.c         |  6 ---
 arch/z80/src/common/z80_exit.c         |  6 ---
 sched/pthread/pthread_exit.c           |  8 ++++
 sched/task/exit.c                      |  8 ++++
 sched/task/task_exit.c                 | 12 +-----
 sched/task/task_exithook.c             | 22 +---------
 sched/task/task_terminate.c            | 76 ++++++++++++++++++++++++++++++++--
 23 files changed, 91 insertions(+), 143 deletions(-)

diff --git a/arch/arm/src/common/arm_exit.c b/arch/arm/src/common/arm_exit.c
index b8189f3d8e..9a41c2231f 100644
--- a/arch/arm/src/common/arm_exit.c
+++ b/arch/arm/src/common/arm_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/arm64/src/common/arm64_exit.c b/arch/arm64/src/common/arm64_exit.c
index d8e6bc4596..a444c80983 100644
--- a/arch/arm64/src/common/arm64_exit.c
+++ b/arch/arm64/src/common/arm64_exit.c
@@ -60,12 +60,6 @@ void up_exit(int status)
   struct tcb_s *tcb = this_task();
   UNUSED(status);
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/avr/src/common/avr_exit.c b/arch/avr/src/common/avr_exit.c
index 8b7e34af07..0e88b87094 100644
--- a/arch/avr/src/common/avr_exit.c
+++ b/arch/avr/src/common/avr_exit.c
@@ -55,12 +55,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/hc/src/common/hc_exit.c b/arch/hc/src/common/hc_exit.c
index a2c2b6a3b2..b7397d41c0 100644
--- a/arch/hc/src/common/hc_exit.c
+++ b/arch/hc/src/common/hc_exit.c
@@ -54,12 +54,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/mips/src/common/mips_exit.c b/arch/mips/src/common/mips_exit.c
index f4520d5c81..0c12040cc8 100644
--- a/arch/mips/src/common/mips_exit.c
+++ b/arch/mips/src/common/mips_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/misoc/src/lm32/lm32_exit.c b/arch/misoc/src/lm32/lm32_exit.c
index 2fb3aed55b..7e3a8723af 100644
--- a/arch/misoc/src/lm32/lm32_exit.c
+++ b/arch/misoc/src/lm32/lm32_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/misoc/src/minerva/minerva_exit.c b/arch/misoc/src/minerva/minerva_exit.c
index 0723be57be..ef1d92ecf0 100644
--- a/arch/misoc/src/minerva/minerva_exit.c
+++ b/arch/misoc/src/minerva/minerva_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.  The
-   * IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/or1k/src/common/or1k_exit.c b/arch/or1k/src/common/or1k_exit.c
index 854976a333..25d338c042 100644
--- a/arch/or1k/src/common/or1k_exit.c
+++ b/arch/or1k/src/common/or1k_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/renesas/src/common/renesas_exit.c b/arch/renesas/src/common/renesas_exit.c
index 8b8a81fe55..474bf019ea 100644
--- a/arch/renesas/src/common/renesas_exit.c
+++ b/arch/renesas/src/common/renesas_exit.c
@@ -54,12 +54,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/risc-v/src/common/riscv_exit.c b/arch/risc-v/src/common/riscv_exit.c
index 201cf52163..39d17a77c4 100644
--- a/arch/risc-v/src/common/riscv_exit.c
+++ b/arch/risc-v/src/common/riscv_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/sim/src/sim/sim_exit.c b/arch/sim/src/sim/sim_exit.c
index eb000b06fa..9d1d8c2567 100644
--- a/arch/sim/src/sim/sim_exit.c
+++ b/arch/sim/src/sim/sim_exit.c
@@ -52,12 +52,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb;
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/sparc/src/common/sparc_exit.c b/arch/sparc/src/common/sparc_exit.c
index aee2dcb0fc..80458173f4 100644
--- a/arch/sparc/src/common/sparc_exit.c
+++ b/arch/sparc/src/common/sparc_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  (void)enter_critical_section();
-
   /* Update scheduler parameters */
 
   nxsched_suspend_scheduler(tcb);
diff --git a/arch/tricore/src/common/tricore_exit.c b/arch/tricore/src/common/tricore_exit.c
index a3bff634fb..432551b63b 100644
--- a/arch/tricore/src/common/tricore_exit.c
+++ b/arch/tricore/src/common/tricore_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/x86/src/common/x86_exit.c b/arch/x86/src/common/x86_exit.c
index 2bb9359941..3356a72dde 100644
--- a/arch/x86/src/common/x86_exit.c
+++ b/arch/x86/src/common/x86_exit.c
@@ -55,12 +55,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/x86_64/src/common/x86_64_exit.c b/arch/x86_64/src/common/x86_64_exit.c
index d264a06408..b222f7a5d3 100644
--- a/arch/x86_64/src/common/x86_64_exit.c
+++ b/arch/x86_64/src/common/x86_64_exit.c
@@ -54,12 +54,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb;
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/xtensa/src/common/xtensa_exit.c b/arch/xtensa/src/common/xtensa_exit.c
index 2b79b5047e..fc4f4bdd7d 100644
--- a/arch/xtensa/src/common/xtensa_exit.c
+++ b/arch/xtensa/src/common/xtensa_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/z16/src/common/z16_exit.c b/arch/z16/src/common/z16_exit.c
index ecd8353674..93cf3a1e46 100644
--- a/arch/z16/src/common/z16_exit.c
+++ b/arch/z16/src/common/z16_exit.c
@@ -54,12 +54,6 @@ void up_exit(int status)
 {
   FAR struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/arch/z80/src/common/z80_exit.c b/arch/z80/src/common/z80_exit.c
index 300ce5027f..80af3eee20 100644
--- a/arch/z80/src/common/z80_exit.c
+++ b/arch/z80/src/common/z80_exit.c
@@ -56,12 +56,6 @@ void up_exit(int status)
 {
   FAR struct tcb_s *tcb = this_task();
 
-  /* Make sure that we are in a critical section with local interrupts.
-   * The IRQ state will be restored when the next task is started.
-   */
-
-  enter_critical_section();
-
   /* Destroy the task at the head of the ready to run list. */
 
   nxtask_exit();
diff --git a/sched/pthread/pthread_exit.c b/sched/pthread/pthread_exit.c
index 039a1805b5..c20eeebd75 100644
--- a/sched/pthread/pthread_exit.c
+++ b/sched/pthread/pthread_exit.c
@@ -91,6 +91,12 @@ void nx_pthread_exit(FAR void *exit_value)
       _exit(EXIT_FAILURE);
     }
 
+  /* Make sure that we are in a critical section with local interrupts.
+   * The IRQ state will be restored when the next task is started.
+   */
+
+  enter_critical_section();
+
   /* Perform common task termination logic.  This will get called again later
    * through logic kicked off by up_exit().
    *
@@ -103,6 +109,8 @@ void nx_pthread_exit(FAR void *exit_value)
    * once, or does something very naughty.
    */
 
+  tcb->flags |= TCB_FLAG_EXIT_PROCESSING;
+
   nxtask_exithook(tcb, status);
 
   up_exit(EXIT_SUCCESS);
diff --git a/sched/task/exit.c b/sched/task/exit.c
index a4e8868799..4d5f19cab2 100644
--- a/sched/task/exit.c
+++ b/sched/task/exit.c
@@ -73,6 +73,12 @@ void _exit(int status)
 
 #endif
 
+  /* Make sure that we are in a critical section with local interrupts.
+   * The IRQ state will be restored when the next task is started.
+   */
+
+  enter_critical_section();
+
   /* Perform common task termination logic.  This will get called again later
    * through logic kicked off by up_exit().
    *
@@ -85,6 +91,8 @@ void _exit(int status)
    * once, or does something very naughty.
    */
 
+  tcb->flags |= TCB_FLAG_EXIT_PROCESSING;
+
   nxtask_exithook(tcb, status);
 
   up_exit(status);
diff --git a/sched/task/task_exit.c b/sched/task/task_exit.c
index 611b69f89f..a4efb2bc83 100644
--- a/sched/task/task_exit.c
+++ b/sched/task/task_exit.c
@@ -135,15 +135,6 @@ int nxtask_exit(void)
 
   rtcb->task_state = TSTATE_TASK_READYTORUN;
 
-  /* Move the TCB to the specified blocked task list and delete it.  Calling
-   * nxtask_terminate with non-blocking true will suppress atexit() and
-   * on-exit() calls and will cause buffered I/O to fail to be flushed.  The
-   * former is required _exit() behavior; the latter is optional _exit()
-   * behavior.
-   */
-
-  nxsched_add_blocked(dtcb, TSTATE_TASK_INACTIVE);
-
 #ifdef CONFIG_SMP
   /* NOTE:
    * During nxtask_terminate(), enter_critical_section() will be called
@@ -155,7 +146,8 @@ int nxtask_exit(void)
   rtcb->irqcount++;
 #endif
 
-  ret = nxtask_terminate(dtcb->pid);
+  dtcb->task_state = TSTATE_TASK_INACTIVE;
+  ret = nxsched_release_tcb(dtcb, dtcb->flags & TCB_FLAG_TTYPE_MASK);
 
 #ifdef CONFIG_SMP
   rtcb->irqcount--;
diff --git a/sched/task/task_exithook.c b/sched/task/task_exithook.c
index fbb3bd055c..6e0d51fa19 100644
--- a/sched/task/task_exithook.c
+++ b/sched/task/task_exithook.c
@@ -429,10 +429,7 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status)
    * called.  If that bit is set, then just exit doing nothing more..
    */
 
-  if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0)
-    {
-      return;
-    }
+  DEBUGASSERT((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0);
 
   nxsched_dumponexit();
 
@@ -442,12 +439,6 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status)
 
   nxtask_recover(tcb);
 
-  /* NOTE: signal handling needs to be done in a criticl section */
-
-#ifdef CONFIG_SMP
-  irqstate_t flags = enter_critical_section();
-#endif
-
   /* Disable the scheduling function to prevent other tasks from
    * being deleted after they are awakened
    */
@@ -484,15 +475,4 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status)
       umm_memdump(&dump);
     }
 #endif
-
-  /* This function can be re-entered in certain cases.  Set a flag
-   * bit in the TCB to not that we have already completed this exit
-   * processing.
-   */
-
-  tcb->flags |= TCB_FLAG_EXIT_PROCESSING;
-
-#ifdef CONFIG_SMP
-  leave_critical_section(flags);
-#endif
 }
diff --git a/sched/task/task_terminate.c b/sched/task/task_terminate.c
index bfd08b6dd0..71242d47ae 100644
--- a/sched/task/task_terminate.c
+++ b/sched/task/task_terminate.c
@@ -39,6 +39,40 @@
 #include "signal/signal.h"
 #include "task/task.h"
 
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int terminat_handler(FAR void *cookie)
+{
+  pid_t pid = (pid_t)(uintptr_t)cookie;
+  FAR struct tcb_s *tcb;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+  tcb = nxsched_get_tcb(pid);
+
+  if (!tcb)
+    {
+      /* There is no TCB with this pid or, if there is, it is not a task. */
+
+      leave_critical_section(flags);
+      return -ESRCH;
+    }
+
+  nxsched_remove_readytorun(tcb, false);
+
+  leave_critical_section(flags);
+  return OK;
+}
+#endif
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -88,19 +122,52 @@ int nxtask_terminate(pid_t pid)
   /* Find for the TCB associated with matching PID */
 
   dtcb = nxsched_get_tcb(pid);
-  if (!dtcb)
+  if (!dtcb || dtcb->flags & TCB_FLAG_EXIT_PROCESSING)
     {
       leave_critical_section(flags);
       return -ESRCH;
     }
 
+  dtcb->flags |= TCB_FLAG_EXIT_PROCESSING;
+
   /* Remove dtcb from tasklist, let remove_readtorun() do the job */
 
   task_state = dtcb->task_state;
-  nxsched_remove_readytorun(dtcb, false);
-  dtcb->task_state = task_state;
+#ifdef CONFIG_SMP
+  if (task_state == TSTATE_TASK_RUNNING &&
+      dtcb->cpu != this_cpu())
+    {
+      cpu_set_t affinity;
+      uint16_t tcb_flags;
+      int ret;
 
-  leave_critical_section(flags);
+      tcb_flags = dtcb->flags;
+      dtcb->flags |= TCB_FLAG_CPU_LOCKED;
+      affinity = dtcb->affinity;
+      CPU_SET(dtcb->cpu, &dtcb->affinity);
+
+      ret = nxsched_smp_call_single(dtcb->cpu, terminat_handler,
+                                    (FAR void *)(uintptr_t)pid,
+                                    true);
+
+      if (ret < 0)
+        {
+          /* Already terminate */
+
+          leave_critical_section(flags);
+          return ret;
+        }
+
+      dtcb->flags = tcb_flags;
+      dtcb->affinity = affinity;
+    }
+  else
+#endif
+    {
+      nxsched_remove_readytorun(dtcb, false);
+    }
+
+  dtcb->task_state = task_state;
 
   /* Perform common task termination logic.  We need to do
    * this as early as possible so that higher level clean-up logic
@@ -111,6 +178,7 @@ int nxtask_terminate(pid_t pid)
 
   nxtask_exithook(dtcb, EXIT_SUCCESS);
 
+  leave_critical_section(flags);
   /* Since all tasks pass through this function as the final step in their
    * exit sequence, this is an appropriate place to inform any
    * instrumentation layer that the task no longer exists.