Skip to content

Signal implement SYS_rt_sigtimedwait syscall 137#201

Merged
jserv merged 1 commit into
sysprog21:mainfrom
open-sources-port:SYS_rt_sigtimedwait
Jul 16, 2026
Merged

Signal implement SYS_rt_sigtimedwait syscall 137#201
jserv merged 1 commit into
sysprog21:mainfrom
open-sources-port:SYS_rt_sigtimedwait

Conversation

@doanbaotrung

@doanbaotrung doanbaotrung commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Add rt_sigtimedwait so that sigwait(3), sigwaitinfo(3), and sigtimedwait(3) work inside the guest. All three are thin wrappers over this syscall in musl and glibc; returning -ENOSYS breaks any application that uses a dedicated signal-management thread.

abi.h:
Define SYS_rt_sigtimedwait = 137, which sits between
rt_sigpending (136) and rt_sigqueueinfo (138) in the aarch64
Linux syscall table.

signal.c:
sigtimedwait_try_dequeue() - acquires sig_lock and dequeues one
signal matching the caller's mask. Thread-directed (private)
set is drained before the shared set, mirroring Linux
dequeue_signal() priority. Reuses signal_rt_dequeue_locked()
and signal_standard_peek_locked() from signal_deliver().
signal_rt_sigtimedwait() - reads and validates the guest mask
and optional timeout, then polls in 1 ms sleep chunks (same
pattern as interruptible_sleep_ns in time.c) until:
- a matching signal is consumed -> return signum
- timeout expires -> return -EAGAIN
- exit_group requested -> return -EINTR
- unblocked non-waited signal -> return -EINTR
SIGKILL/SIGSTOP are silently removed from the wait mask,
matching Linux do_sigtimedwait behavior.
NULL timeout_gva blocks indefinitely; {0,0} polls once.
info_gva = 0 skips the siginfo_t write (sigwait(3) path).

signal.h: declare signal_rt_sigtimedwait.
dispatch.tbl: register sc_rt_sigtimedwait with guest-ptr flag.
syscall.c: SC_FORWARD x0..x3 -> set, info, timeout, sigsetsize.

Fix #196


Summary by cubic

Implements SYS_rt_sigtimedwait (137) so sigwait(3), sigwaitinfo(3), and sigtimedwait(3) work inside the guest, matching Linux behavior and unblocking apps that use a signal-manager thread.

  • New Features
    • Wires up SYS_rt_sigtimedwait: defines 137, registers sc_rt_sigtimedwait, forwards args in syscall.c, and updates coverage mapping (sigwait, sigwaitinfo, sigtimedwait).
    • Consumes one pending signal (thread-directed before process-directed); optionally writes siginfo_t; removes SIGKILL/SIGSTOP from the wait mask; NULL timeout blocks, {0,0} polls once, finite waits in 1 ms chunks; returns signum on success, -EAGAIN on timeout, -EINTR on exit-group or an unblocked deliverable unrelated signal.
    • Adds tests/test-sigtimedwait.c and a Makefile target (links -lpthread) covering sigwait, sigwaitinfo with siginfo_t, zero-time poll, short timeout, and cross-thread delivery.

Written for commit 34616d5. Summary will update on new commits.

Review in cubic

@doanbaotrung
doanbaotrung force-pushed the SYS_rt_sigtimedwait branch from 5b89e41 to 0e0f9a3 Compare July 13, 2026 14:23

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/syscall/signal.c">

<violation number="1" location="src/syscall/signal.c:1419">
P2: The saturation check uses `>` instead of `>=`, so a guest-supplied timespec with tv_sec == INT64_MAX/1000000000 and a large tv_nsec can make `tv_sec * 1000000000LL + tv_nsec` exceed INT64_MAX, causing signed overflow (UB) rather than saturating to INT64_MAX.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/syscall/signal.c
if (lts.tv_sec > (INT64_MAX / 1000000000LL))
remaining_ns = INT64_MAX;
else
remaining_ns = lts.tv_sec * 1000000000LL + lts.tv_nsec;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The saturation check uses > instead of >=, so a guest-supplied timespec with tv_sec == INT64_MAX/1000000000 and a large tv_nsec can make tv_sec * 1000000000LL + tv_nsec exceed INT64_MAX, causing signed overflow (UB) rather than saturating to INT64_MAX.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/syscall/signal.c, line 1419:

<comment>The saturation check uses `>` instead of `>=`, so a guest-supplied timespec with tv_sec == INT64_MAX/1000000000 and a large tv_nsec can make `tv_sec * 1000000000LL + tv_nsec` exceed INT64_MAX, causing signed overflow (UB) rather than saturating to INT64_MAX.</comment>

<file context>
@@ -1332,7 +1332,162 @@ int64_t signal_rt_sigpending(guest_t *g, uint64_t set_gva, uint64_t sigsetsize)
+        if (lts.tv_sec > (INT64_MAX / 1000000000LL))
+            remaining_ns = INT64_MAX;
+        else
+            remaining_ns = lts.tv_sec * 1000000000LL + lts.tv_nsec;
+    }
+
</file context>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix

I changed the saturation check condition to precisely verify the overflow threshold on both the tv_sec and tv_nsec components:

        /* Saturate to INT64_MAX to avoid overflow. */
        if (lts.tv_sec > (INT64_MAX / 1000000000LL) ||
            (lts.tv_sec == (INT64_MAX / 1000000000LL) &&
             lts.tv_nsec > (INT64_MAX % 1000000000LL))) {
            remaining_ns = INT64_MAX;
        } else {
            remaining_ns = lts.tv_sec * 1000000000LL + lts.tv_nsec;
        }

@doanbaotrung
doanbaotrung force-pushed the SYS_rt_sigtimedwait branch 4 times, most recently from 6b3cf43 to 0e6c431 Compare July 13, 2026 15:33
Comment thread src/syscall/signal.c Outdated
uint64_t *blocked = thread_blocked_ptr();
uint64_t deliverable;
pthread_mutex_lock(&sig_lock);
deliverable = self_pending_locked() & ~*blocked & ~mask;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signal_rt_sigtimedwait's EINTR check doesn't filter by signal disposition, so signals that should silently discard (SIG_IGN, or default-ignore/continue/stop like SIGCHLD/SIGURG/SIGWINCH/SIGCONT) spuriously wake the wait when they're not in mask

signal_pending_interruption() (signal.c:611) already implements the correct disposition filter. Suggest reusing that filtering logic here

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review.

Fixed. The old check used a raw bitmask self_pending_locked() & ~blocked & ~mask which would spuriously wake the wait for signals like SIGCHLD, SIGURG, SIGWINCH, and SIGCONT — all of which are silently discarded by signal_deliver with no guest-visible effect.

Replaced it with a disposition-aware filter loop that mirrors signal_pending_interruption() exactly: a candidate signal only causes -EINTR if it has a real user-visible effect — an explicit non-SIG_IGN handler, or a SIG_DFL disposition of TERM/CORE. Signals with SIG_IGN or default IGN/CONT/STOP dispositions now correctly fall through and do not interrupt the wait.

@jserv jserv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refined based on the review from @cubic-dev-ai . If you disagree with any of its feedback, discuss it with the reviewer to reach a consensus and consolidate the shared knowledge base.

Add rt_sigtimedwait so that sigwait(3), sigwaitinfo(3), and
sigtimedwait(3) work inside the guest.  All three are thin wrappers
over this syscall in musl and glibc; returning -ENOSYS breaks any
application that uses a dedicated signal-management thread.

abi.h:
  Define SYS_rt_sigtimedwait = 137, which sits between
  rt_sigpending (136) and rt_sigqueueinfo (138) in the aarch64
  Linux syscall table.

signal.c:
  sigtimedwait_try_dequeue() - acquires sig_lock and dequeues one
    signal matching the caller's mask.  Thread-directed (private)
    set is drained before the shared set, mirroring Linux
    dequeue_signal() priority.  Reuses signal_rt_dequeue_locked()
    and signal_standard_peek_locked() from signal_deliver().
  signal_rt_sigtimedwait() - reads and validates the guest mask
    and optional timeout, then polls in 1 ms sleep chunks (same
    pattern as interruptible_sleep_ns in time.c) until:
      - a matching signal is consumed -> return signum
      - timeout expires             -> return -EAGAIN
      - exit_group requested        -> return -EINTR
      - unblocked non-waited signal -> return -EINTR
    SIGKILL/SIGSTOP are silently removed from the wait mask,
    matching Linux do_sigtimedwait behavior.
    NULL timeout_gva blocks indefinitely; {0,0} polls once.
    info_gva = 0 skips the siginfo_t write (sigwait(3) path).

signal.h:     declare signal_rt_sigtimedwait.
dispatch.tbl: register sc_rt_sigtimedwait with guest-ptr flag.
syscall.c:    SC_FORWARD x0..x3 -> set, info, timeout, sigsetsize.

Fix sysprog21#196
@doanbaotrung
doanbaotrung force-pushed the SYS_rt_sigtimedwait branch from c749b7a to 34616d5 Compare July 16, 2026 14:47
@doanbaotrung
doanbaotrung requested a review from jserv July 16, 2026 14:55
@jserv
jserv merged commit 9bc7ee9 into sysprog21:main Jul 16, 2026
9 checks passed
@jserv

jserv commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Thank @doanbaotrung for contributing!

@doanbaotrung
doanbaotrung deleted the SYS_rt_sigtimedwait branch July 16, 2026 18:22
henrybear327 pushed a commit to henrybear327/elfuse that referenced this pull request Jul 17, 2026
…edwait

Signal implement SYS_rt_sigtimedwait syscall 137
henrybear327 pushed a commit to henrybear327/elfuse that referenced this pull request Jul 17, 2026
…edwait

Signal implement SYS_rt_sigtimedwait syscall 137
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SYS_rt_sigtimedwait to support synchronous signal handling sigwaitinfo/sigtimedwait

3 participants