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

anchao 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 fa4e298e0fb sched/signal: fix missing EINTR when nxsig_clockwait is 
interrupted
fa4e298e0fb is described below

commit fa4e298e0fb2d1692c39207a3c851cc796fb6cad
Author: Junbo Zheng <[email protected]>
AuthorDate: Sun Oct 18 00:49:38 2026 +0800

    sched/signal: fix missing EINTR when nxsig_clockwait is interrupted
    
    nxsig_clockwait() always returned OK after being awakened, so
    nanosleep(), clock_nanosleep() and sleep() reported success when
    interrupted by a caught, unblocked signal instead of -1/EINTR, and
    the remaining time in *rmtp was invisible to retry loops.
    
    Install a sigunbinfo buffer in nxsig_clockwait() when the caller did
    not provide one (only nxsig_timedwait() does), then report -EINTR if
    the wake came from a real signal and -ECANCELED on cancellation.
    
    The new sigunbinfo accesses are guarded by
    CONFIG_DISABLE_ALL_SIGNALS, matching the guard around
    struct tcb_s::sigunbinfo in include/nuttx/sched.h: signal-disabled
    configurations keep the previous behavior unchanged.
    
    Testing: built and verified on the NuttX simulator (host:
    Ubuntu 22.04):
    
      cmake -B build -DBOARD_CONFIG=sim:nsh
      cmake --build build -j$(nproc)
      ./build/nuttx
    
    With a temporary test in examples/hello that installs a SIGUSR1
    handler, spawns a task sending SIGUSR1 after 0.5 s, then calls
    nanosleep(3s, &rem):
    
    Before:
      nanosleep ret=0 errno=0 (handler fired, rem=2.500000000)
    After:
      nanosleep ret=-1 errno=EINTR (handler fired, rem=2.500000000)
    
    Plain nanosleep(0.2s) still returns 0 and sigtimedwait(0.2s) still
    times out with EAGAIN, so the timedwait path is unaffected.
    
    Assisted-by: Claude Code (glm-5.3) <[email protected]>
    Signed-off-by: Junbo Zheng <[email protected]>
---
 sched/signal/sig_clockwait.c | 46 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/sched/signal/sig_clockwait.c b/sched/signal/sig_clockwait.c
index c5a1b418efa..ee6f6595e85 100644
--- a/sched/signal/sig_clockwait.c
+++ b/sched/signal/sig_clockwait.c
@@ -195,6 +195,10 @@ int nxsig_clockwait(int clockid, int flags,
   irqstate_t        iflags;
   clock_t expect = 0u;
   clock_t stop   = 0u;
+#ifndef CONFIG_DISABLE_ALL_SIGNALS
+  siginfo_t unbinfo;
+  bool own_unbinfo = false;
+#endif
 
   if (rqtp && (rqtp->tv_nsec < 0 || rqtp->tv_nsec >= 1000000000))
     {
@@ -238,6 +242,19 @@ int nxsig_clockwait(int clockid, int flags,
   iflags = enter_critical_section();
   rtcb = this_task();
 
+#ifndef CONFIG_DISABLE_ALL_SIGNALS
+  /* If the caller did not install its own sigunbinfo (only nxsig_timedwait()
+   * does), install ours so that we can tell how we were awakened: a real
+   * signal writes its siginfo here and requires -EINTR.
+   */
+
+  if (rtcb->sigunbinfo == NULL)
+    {
+      rtcb->sigunbinfo = &unbinfo;
+      own_unbinfo = true;
+    }
+#endif
+
   if (rqtp)
     {
       /* Start the watchdog timer */
@@ -286,6 +303,15 @@ int nxsig_clockwait(int clockid, int flags,
       stop = clock_systime_ticks();
     }
 
+  /* Retrieve the wake reason before dropping the critical section */
+
+#ifndef CONFIG_DISABLE_ALL_SIGNALS
+  if (own_unbinfo)
+    {
+      rtcb->sigunbinfo = NULL;
+    }
+#endif
+
   leave_critical_section(iflags);
 
   if (rqtp && rmtp && expect)
@@ -294,5 +320,25 @@ int nxsig_clockwait(int clockid, int flags,
                        clock_compare(stop, expect) ? expect - stop : 0);
     }
 
+#ifndef CONFIG_DISABLE_ALL_SIGNALS
+  if (own_unbinfo)
+    {
+      /* Awakened by a real signal?  Then the wait must fail with EINTR
+       * (POSIX: nanosleep/clock_nanosleep).  A pending cancellation is
+       * reported through the siginfo errno instead.
+       */
+
+      if (GOOD_SIGNO(unbinfo.si_signo))
+        {
+          return -EINTR;
+        }
+
+      if (unbinfo.si_signo == SIG_CANCEL_TIMEOUT)
+        {
+          return -unbinfo.si_errno;
+        }
+    }
+#endif
+
   return 0;
 }

Reply via email to