You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2026/10/19 11:53:27 UTC
(nuttx) 01/02: sched/signal: Discard a signal that is ignored.
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 <ma...@gmail.com>
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 <ma...@gmail.com>
---
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);
}