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)