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

xiaoxiang781216 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 4b2aaf80e74 sched/signal: Run a synchronous signal handler out of the 
critical section.
4b2aaf80e74 is described below

commit 4b2aaf80e741f8ab4ec1bdb4bbf0fc65f0dc48c0
Author: Marco Casaroli <[email protected]>
AuthorDate: Tue Oct 13 16:30:51 2026 +0200

    sched/signal: Run a synchronous signal handler out of the critical section.
    
    nxsig_queue_action() runs the signal handler at once when the signal is
    for the calling thread.  It is called from nxsig_tcbdispatch(), which
    holds the critical section.  In a kernel build this happens at the end
    of each system call with a pending signal: the user handler then runs
    in user mode with interrupts disabled, and on SMP its thread holds the
    global critical section lock until the handler returns.  The other CPUs
    wait for the lock all that time, and the CPU of the handler takes no
    interrupt.
    
    Let nxsig_queue_action() only mark the delivery, and deliver in
    nxsig_tcbdispatch() after it leaves the critical section.  A signal that
    an interrupt queues meanwhile is delivered in the same loop.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 sched/signal/sig_dispatch.c | 36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/sched/signal/sig_dispatch.c b/sched/signal/sig_dispatch.c
index 000bd1e9913..ba5b731204d 100644
--- a/sched/signal/sig_dispatch.c
+++ b/sched/signal/sig_dispatch.c
@@ -103,6 +103,8 @@ static int sig_handler(FAR void *cookie)
  *
  * Returned Value:
  *   Returns 0 (OK) on success or a negated errno value on failure.
+ *   *deliver is set to true if the caller must deliver the signal to the
+ *   calling thread when it leaves the critical section.
  *
  * Assumptions:
  *   Called in critical section
@@ -111,7 +113,8 @@ static int sig_handler(FAR void *cookie)
 
 static int nxsig_queue_action(FAR struct tcb_s *stcb,
                               FAR sigactq_t *sigact,
-                              FAR siginfo_t *info)
+                              FAR siginfo_t *info,
+                              FAR bool *deliver)
 {
   FAR sigq_t    *sigq;
   int            ret = OK;
@@ -187,10 +190,11 @@ static int nxsig_queue_action(FAR struct tcb_s *stcb,
                   stcb->sigdeliver = nxsig_deliver;
                   if (stcb == this_task() && !up_interrupt_context())
                     {
-                      /* In this case just deliver the signal now. */
+                      /* Deliver the signal now, but out of the critical
+                       * section: the handler must not run with it held.
+                       */
 
-                      (stcb->sigdeliver)(stcb);
-                      stcb->sigdeliver = NULL;
+                      *deliver = true;
                     }
                   else
                     {
@@ -496,6 +500,7 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
   FAR sigpendq_t *sigpend = NULL;
 #ifdef CONFIG_ENABLE_ALL_SIGNALS
   FAR sigactq_t *sigact;
+  bool deliver = false;
 #endif
 
   sinfo("TCB=%p pid=%d signo=%d code=%d value=%d masked=%s\n",
@@ -636,7 +641,7 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
 
       /* Queue any sigaction's requested by this task. */
 
-      ret = nxsig_queue_action(stcb, sigact, info);
+      ret = nxsig_queue_action(stcb, sigact, info, &deliver);
 #endif
       /* Deliver of the signal must be performed in a critical section */
 
@@ -737,6 +742,27 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
 
   leave_critical_section(flags);
 
+#ifdef CONFIG_ENABLE_ALL_SIGNALS
+  /* Run the signal handlers of the calling thread, now that the critical
+   * section is free.  A signal that an interrupt queues meanwhile is
+   * delivered in the same loop.
+   */
+
+  while (deliver)
+    {
+      (stcb->sigdeliver)(stcb);
+
+      flags = enter_critical_section();
+      if (sq_empty(&stcb->sigpendactionq))
+        {
+          stcb->sigdeliver = NULL;
+          deliver = false;
+        }
+
+      leave_critical_section(flags);
+    }
+#endif
+
   /* Dispatch kernel action, if needed, in case a pending signal was added */
 
   if (sigpend != NULL)

Reply via email to