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 93c7e875a4f sched/task: Give the child of fork() the signal actions of 
the parent.
93c7e875a4f is described below

commit 93c7e875a4f1ae2e044e02e19b0a7a1528b22635
Author: Marco Casaroli <[email protected]>
AuthorDate: Wed Oct 21 04:06:03 2026 +0200

    sched/task: Give the child of fork() the signal actions of the parent.
    
    The child of fork() and vfork() started with no signal actions: the
    action list of its new task group was empty, and so was the set of the
    signals that have the default action, which only nxtask_start() fills.
    So no signal had its default action in the child.  A child that had not
    called exec ignored SIGTERM, SIGINT and even SIGKILL, and a handler of
    the parent did not run in the child.  A shell forks for a subshell, for
    a pipeline and for a command in the background, so these could not be
    stopped with kill.
    
    POSIX says that the child has the signal actions of the parent, the
    signal mask of the calling thread (nxtask_setup_scheduler() copies it
    already) and no pending signals.  Add nxsig_dupactions(), which copies
    the action list and the set of the signals with the default action to
    the new group, and call it in nxtask_setup_fork().
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 sched/signal/sig_action.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++
 sched/signal/signal.h     |  2 ++
 sched/task/task_fork.c    |  9 +++++++
 3 files changed, 75 insertions(+)

diff --git a/sched/signal/sig_action.c b/sched/signal/sig_action.c
index bf348d43100..a0f55f22330 100644
--- a/sched/signal/sig_action.c
+++ b/sched/signal/sig_action.c
@@ -442,6 +442,70 @@ int sigaction(int signo, FAR const struct sigaction *act,
   return OK;
 }
 
+/****************************************************************************
+ * Name: nxsig_dupactions
+ *
+ * Description:
+ *   Give a new task group (the child of fork() or vfork()) a copy of the
+ *   signal actions of the group of its parent: the signal handlers, and
+ *   the signals that have the default action.  The signals that the
+ *   parent ignores have no action, so the child ignores them too.
+ *
+ * Input Parameters:
+ *   group  - The new task group.  It has no signal actions yet.
+ *   parent - The task group of the parent.
+ *
+ ****************************************************************************/
+
+void nxsig_dupactions(FAR struct task_group_s *group,
+                      FAR struct task_group_s *parent)
+{
+  FAR sigactq_t *sigact;
+  FAR sigactq_t *copy;
+  irqstate_t flags;
+  int i;
+  int n;
+
+  /* Copy one action at a time: an allocation cannot be made while the
+   * list of the parent is locked, and another thread of the parent can
+   * change the list meanwhile.
+   */
+
+  for (i = 0; ; i++)
+    {
+      copy = nxsig_alloc_action();
+
+      flags = spin_lock_irqsave(&parent->tg_lock);
+      for (sigact = (FAR sigactq_t *)parent->tg_sigactionq.head, n = 0;
+           sigact != NULL && n < i;
+           sigact = sigact->flink, n++);
+
+      if (sigact != NULL)
+        {
+          copy->signo = sigact->signo;
+          copy->act   = sigact->act;
+        }
+
+      spin_unlock_irqrestore(&parent->tg_lock, flags);
+
+      if (sigact == NULL)
+        {
+          nxsig_release_action(copy);
+          break;
+        }
+
+      flags = spin_lock_irqsave(&group->tg_lock);
+      sq_addlast((FAR sq_entry_t *)copy, &group->tg_sigactionq);
+      spin_unlock_irqrestore(&group->tg_lock, flags);
+    }
+
+#ifdef CONFIG_SIG_DEFAULT
+  flags = spin_lock_irqsave(&parent->tg_lock);
+  group->tg_sigdefault = parent->tg_sigdefault;
+  spin_unlock_irqrestore(&parent->tg_lock, flags);
+#endif
+}
+
 /****************************************************************************
  * Name: nxsig_release_action
  *
diff --git a/sched/signal/signal.h b/sched/signal/signal.h
index 1de4b8b66a8..8c43270512f 100644
--- a/sched/signal/signal.h
+++ b/sched/signal/signal.h
@@ -170,6 +170,8 @@ void               nxsig_initialize(void);
 
 /* sig_action.c */
 
+void               nxsig_dupactions(FAR struct task_group_s *group,
+                                    FAR struct task_group_s *parent);
 void               nxsig_release_action(FAR sigactq_t *sigact);
 
 /* sig_default.c */
diff --git a/sched/task/task_fork.c b/sched/task/task_fork.c
index 022cc07c534..8bd6c59776e 100644
--- a/sched/task/task_fork.c
+++ b/sched/task/task_fork.c
@@ -41,6 +41,7 @@
 
 #include "sched/sched.h"
 #include "group/group.h"
+#include "signal/signal.h"
 #include "task/task.h"
 #include "tls/tls.h"
 
@@ -424,6 +425,14 @@ FAR struct tcb_s *nxtask_setup_fork(start_t retaddr, bool 
vfork)
         }
     }
 
+#ifdef CONFIG_ENABLE_ALL_SIGNALS
+  /* POSIX: the child has the signal actions of the parent, but no pending
+   * signals.  nxtask_setup_scheduler() copied the signal mask already.
+   */
+
+  nxsig_dupactions(child->group, ptcb->group);
+#endif
+
   /* Now we have enough in place that we can join the group */
 
   group_initialize(child);

Reply via email to