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

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

commit 302f2cf062909caa8284a261db7f781a5d20074a
Author: Marco Casaroli <[email protected]>
AuthorDate: Sun Oct 18 17:27:28 2026 +0200

    sched/signal: Discard a signal that is ignored.
    
    nxsig_tcbdispatch() woke a task that waited on a semaphore or a message
    queue with EINTR for any unmasked signal, also for one that is ignored,
    as SIGCHLD and SIGWINCH are by default.  So a read() from a pipe failed
    with EINTR when a child of the reader exited.  It also ended
    nanosleep(), pause() and sigsuspend() early.  POSIX discards an ignored
    signal: it does not interrupt a function.
    
    Discard an unmasked signal without an action that is sent to a user
    task or thread: the task is not woken, and the signal is not added to
    the pending signals, also not during a system call.  A masked signal is
    pended as before.  A task that waits for signals is woken by an ignored
    signal only when the signal is in its wait set, as for sigwaitinfo()
    and sigtimedwait().  A program that wants a signal to interrupt a
    blocking call must install a handler for it.  Kernel threads are not
    affected: the OS wakes them with signals that have no action.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 sched/signal/sig_dispatch.c | 37 ++++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/sched/signal/sig_dispatch.c b/sched/signal/sig_dispatch.c
index ba5b731204d..a2f8fee1d7a 100644
--- a/sched/signal/sig_dispatch.c
+++ b/sched/signal/sig_dispatch.c
@@ -502,6 +502,7 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
   FAR sigactq_t *sigact;
   bool deliver = false;
 #endif
+  bool ignored = false;
 
   sinfo("TCB=%p pid=%d signo=%d code=%d value=%d masked=%s\n",
         stcb, stcb->pid, info->si_signo, info->si_code,
@@ -543,6 +544,20 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
 
   masked = nxsig_ismember(&stcb->sigprocmask, info->si_signo);
 
+#ifdef CONFIG_ENABLE_ALL_SIGNALS
+  /* An unmasked signal without an action is ignored.  It is discarded: it
+   * is not added to the pending signals, and it does not interrupt a wait.
+   * Kernel threads keep the old behaviour: the OS wakes them with signals
+   * that have no action.
+   */
+
+  if (masked == 0 &&
+      (stcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
+    {
+      ignored = nxsig_find_action(stcb->group, info->si_signo) == NULL;
+    }
+#endif
+
 #ifdef CONFIG_LIB_SYSCALL
   /* Check if the signal is masked OR if the signal is received while we are
    * processing a system call -- in either case, it will be added to the
@@ -583,7 +598,7 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
        */
 
       if (stcb->task_state == TSTATE_WAIT_SIG &&
-          (masked == 0 ||
+          ((masked == 0 && !ignored) ||
            (nxsig_ismember(&stcb->sigwaitmask, info->si_signo) == 1)))
         {
           if (stcb->sigunbinfo != NULL)
@@ -613,7 +628,7 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
 #if defined(CONFIG_LIB_SYSCALL) && defined(CONFIG_ENABLE_ALL_SIGNALS)
           /* Must also add signal action if in system call */
 
-          if (masked == 0)
+          if (masked == 0 && !ignored)
             {
               sigpend = nxsig_add_pendingsignal(stcb, info, group_dispatch);
             }
@@ -621,10 +636,10 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
         }
 
       /* Its not one we are waiting for... Add it to the list of pending
-       * signals.
+       * signals, unless it is ignored.
        */
 
-      else
+      else if (!ignored)
         {
           sigpend = nxsig_add_pendingsignal(stcb, info, group_dispatch);
         }
@@ -647,10 +662,14 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
 
       /* Check if the task is waiting for an unmasked signal. If so, then
        * unblock it. This must be performed in a critical section because
-       * signals can be queued from the interrupt level.
+       * signals can be queued from the interrupt level.  An ignored signal
+       * does not end nanosleep(), pause() or sigsuspend(): it wakes only
+       * sigwaitinfo() and sigtimedwait() when they wait for it.
        */
 
-      if (stcb->task_state == TSTATE_WAIT_SIG)
+      if (stcb->task_state == TSTATE_WAIT_SIG &&
+          (!ignored ||
+           nxsig_ismember(&stcb->sigwaitmask, info->si_signo) == 1))
         {
           if (stcb->sigunbinfo != NULL)
             {
@@ -695,7 +714,7 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
        * be unblocked when a signal is received.
        */
 
-      if (stcb->task_state == TSTATE_WAIT_SEM)
+      if (stcb->task_state == TSTATE_WAIT_SEM && !ignored)
         {
           nxsem_wait_irq(stcb, EINTR);
         }
@@ -705,8 +724,8 @@ int nxsig_tcbdispatch(FAR struct tcb_s *stcb, siginfo_t 
*info,
        * must be unblocked when a signal is received.
        */
 
-      else if (stcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
-          stcb->task_state == TSTATE_WAIT_MQNOTFULL)
+      else if ((stcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
+                stcb->task_state == TSTATE_WAIT_MQNOTFULL) && !ignored)
         {
           nxmq_wait_irq(stcb, EINTR);
         }

Reply via email to