Commit Graph
7 Commits
Author SHA1 Message Date
Yunus Shaikh f5757aab98 fix(libkernel): restore a handler's signal bit when the handler replaces the mask
A handler that read the mask and put it back with SIG_SETMASK stored its
own signal, which sigprocmask reports from the hold, in the process mask
and cleared the hold, so the signal stayed blocked after the handler
returned. pselect, setcontext and a siglongjmp inside the handler replace
the mask the same way. When the handler's own thread releases a hold, the
signal now gets back its bit from before the handler when the handler
returns, as FreeBSD's sigreturn puts back the mask from before it. A mask
another thread sets meanwhile is kept.
2026-10-25 09:49:35 -07:00
Yunus Shaikh 8be8dc83af Merge main into fix/libkernel-signal-handler-mask
Main's #10706 moves the declarations of exported functions and their types
into the libraries' public headers, and gives WaitForPendingInSet a
KernelTimespec timeout. The merge keeps this branch's DeliverUnblockedPending
and ChangeBlockedMask with main's KernelTimespec. It takes main's side of
the declarations in GuestSignalSets.cpp, whose setjmp and longjmp this
branch had added and libc's Api.hpp now declares. GuestSignalHandlerMask.cpp
includes the libkernel and libc public headers in place of its own
declarations and GuestSignalSet and GuestSigaction types, as the
public_headers audit requires.
2026-10-25 07:05:46 -07:00
Yunus Shaikh 56b2a6393f fix(libkernel): keep another thread's block of a signal a running handler also blocks
A handler's blocks are now holds kept apart from the mask sigprocmask sets, and released when the handler returns, so a sigprocmask(SIG_BLOCK) from another thread meanwhile survives even for a signal in the handler's sa_mask. sigprocmask reports the holds; SIG_UNBLOCK of a held signal releases its hold and SIG_SETMASK, which longjmp uses, releases them all, while sigsuspend's own restore keeps them.
2026-10-21 16:39:02 -07:00
Yunus Shaikh 780aa44726 fix(libkernel): block every word of a signal handler's mask while it runs
main now keeps all four words of the guest signal mask. A handler's sa_mask above signal 32 is added too, and SIGKILL and SIGSTOP stay unblocked, as sigprocmask leaves them.
2026-10-21 15:52:34 -07:00
Yunus Shaikh 9f584de29b test(libkernel): leave a signal handler with longjmp and raise it again
A handler that leaves with longjmp never returns to unblock its signal,
so longjmp has to bring back the mask setjmp saved before the signal.
2026-10-13 18:56:46 -07:00
Yunus Shaikh ef45904842 fix(libkernel): unblock only the signals a handler added when it returns
The blocked mask is still process-wide, so restoring the whole mask saved
before the handler undid any change another thread made while it ran.
2026-10-13 18:26:47 -07:00
Yunus Shaikh 3d1b4d460b fix(libkernel): block a signal while its handler runs and honour SA_RESETHAND
A guest signal handler ran with the mask it was raised under, so a
handler that raised its own signal again re-entered itself at once,
sigprocmask inside the handler did not report the signal or the
handler's sa_mask as blocked, and SA_RESETHAND left the handler
installed for the next delivery.

FreeBSD 11.4 forms the handler's frame and then, in postsig_done()
(sys/kern/kern_sig.c), blocks the handler's sa_mask and, unless
SA_NODEFER is set, the signal itself, and resets the disposition to
SIG_DFL when SA_RESETHAND is set; sigreturn restores the previous mask,
so a signal raised meanwhile stays pending until the handler returns.
sigaction keeps reporting SA_RESETHAND afterwards, since sigdflt() does
not clear ps_sigreset.

The handler now runs with its signal (unless SA_NODEFER) and its mask
added to the guest mask, which is restored when it returns, and pending
signals that the restored mask unblocks are delivered when raise
returns. SA_RESETHAND resets the handler to the default before it runs.
2026-10-13 09:47:28 -07:00