Skip to content

Signal implement SYS_rt_sigtimedwait syscall 137#201

Open
doanbaotrung wants to merge 1 commit into
sysprog21:mainfrom
open-sources-port:SYS_rt_sigtimedwait
Open

Signal implement SYS_rt_sigtimedwait syscall 137#201
doanbaotrung wants to merge 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 with a signal-manager thread.

  • New Features
    • Wires up SYS_rt_sigtimedwait: defines 137, registers sc_rt_sigtimedwait, forwards args, and updates coverage mapping (sigwait, sigwaitinfo, sigtimedwait).
    • Consumes one pending signal (thread-directed before process-directed); optionally writes siginfo_t; masks SIGKILL/SIGSTOP; 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 c749b7a. 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>

@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.

@doanbaotrung doanbaotrung force-pushed the SYS_rt_sigtimedwait branch from 0e6c431 to 5bd358c Compare July 14, 2026 13:55
@doanbaotrung doanbaotrung requested a review from Max042004 July 14, 2026 14:17
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 5bd358c to c749b7a Compare July 14, 2026 16:43
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