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); }
