A blocked raise(40) shows in word 1 of sigpending, and sigaction(SIG_IGN) on it clears that word, as kern_sigaction drops it from the queue for any signal number.
FreeBSD 11's kern_sigaction (sys/kern/kern_sig.c) calls
sigqueue_delete_proc, which drops the signal from the process queue and
from every thread's queue, whenever the new handler is SIG_IGN, or
SIG_DFL on a signal whose sigprop has SA_IGNORE (SIGURG, SIGCONT,
SIGCHLD, SIGIO, SIGWINCH, SIGINFO). It does so whether or not the
signal is blocked. sigaction and signal now take the signal off the
pending set in those cases, so a later unblock or wait never sees it.
siginterrupt is a libSceLibcInternal export (the public SDK's stub table has it there, not in the
kernel tables) and FreeBSD 11.4's lib/libc/gen/siginterrupt.c reads the signal's disposition,
sets or clears the signal's bit in _sigintr and SA_RESTART, and installs the disposition again.
libc cannot call libkernel, so, as the pthread hooks do, libc keeps a registered sigaction and
the address of the _sigintr set, and libkernel registers both from a static initializer when it
loads. A call before that throws; the set is written without libkernel's registration lock, as
FreeBSD's libc does. Builds on #8866, which adds the set.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
The public SDK's libkernel, libkernel_sys and libkernel_web stub tables declare _sigintr, the
sigset_t that FreeBSD's libc shares between signal and siginterrupt, and no built library
provided it (#8846). libkernel now exports the 16-byte object, zero at start, and signal records
a handler with SA_RESTART unless its signal is in the set, as lib/libc/gen/signal.c does.
siginterrupt, which fills the set, is a libSceLibcInternal export; libc does not link libkernel
and cannot reach the dispositions, so it stays out and a debt entry for signal says so.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
pthread_kill(thread, 0) returned 0 for every handle other than the caller's before it asked whether the thread was still alive. FreeBSD's _pthread_kill looks the thread up with _thr_find_thread before it checks for signal 0, so the call answers ESRCH for a thread that has ended or was never a thread. The liveness check now runs before the signal 0 shortcut; the calling thread still answers 0.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A signal that is ignored is forgotten when it is sent: the call succeeds
(sys/kern/kern_sig.c:2178-2187). That covers SIG_IGN and the signals whose
default action is SA_IGNORE, SIGURG, SIGCONT, SIGCHLD, SIGIO, SIGWINCH and
SIGINFO (kern_sig.c:205-240); SIGCONT stays pending while blocked. The guest
failed with EINVAL for every such signal that has no host equivalent.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
FreeBSD 11.4 raise is thr_kill(thr_self(), sig) (lib/libc/gen/raise.c:52),
and thr_kill with a thread id treats signal 0 as a pure existence check
that returns 0 (sys/kern/kern_thr.c:425). The guest returned EINVAL.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
FreeBSD 11.4 kern_sigaction fails with EINVAL when a handler other than
SIG_DFL and SIG_IGN comes with flags outside SA_ONSTACK, SA_RESTART,
SA_RESETHAND, SA_NOCLDSTOP, SA_NODEFER, SA_NOCLDWAIT and SA_SIGINFO
(sys/kern/kern_sig.c:691-695). The guest accepted any flag word.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
FreeBSD 11.4 kern_sigprocmask applies SIG_CANTMASK to the set for SIG_BLOCK
and SIG_SETMASK (sys/kern/kern_sig.c:1056, 1067), and sigsuspend sets its
mask through the same call (kern_sig.c:1534). The guest mask kept both bits,
so sigprocmask(SIG_BLOCK, {SIGKILL}) read back as blocked.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Before: raise, kill and pthread_kill delivered a signal at once or failed
with EINVAL, nothing stayed pending, and pause, sigwait, sigwaitinfo and
sigtimedwait called NotImplemented_nid_no_patch.
Now: a process-wide pending set holds signals 1 to 128. A signal raised
while it is blocked stays pending and is delivered when _sigprocmask
unblocks it, taken by sigwait, sigwaitinfo or sigtimedwait, or delivered by
pause, which runs its handler on the calling thread and returns -1 with
EINTR. pthread_kill to another thread leaves the signal pending for
whichever thread waits for it and answers ESRCH for a handle that is not a
live guest thread. sigtimedwait follows FreeBSD's sigtimedwait(2): EAGAIN
on timeout, EINVAL for a tv_nsec outside 0 to 1000000000 while nothing is
pending, and an indefinite wait with a null timeout.
Apple clang ships libc++, which differs from libstdc++ where the sources
relied on it:
- std::atomic<std::shared_ptr<T>> is not provided. AtomicSharedPtr is that
type where the library has it and a mutex-guarded pointer with the same
member functions elsewhere; the AGC driver uses it.
- std::atomic_ref<const T> is not provided; the page span reads go through
a non-const reference.
- std::filesystem::file_time_type::clock::to_sys is not provided;
std::chrono::file_clock::to_sys is.
- std::max and std::min do not deduce across the integer types of the
guest range arithmetic, which is spelled with an explicit type.
- <string> and <initializer_list> are included where the sources and tests
use them.
FreeBSD's kernel_sigaction rejects SIGKILL and SIGSTOP only for a handler other than SIG_DFL, so signal(9, SIG_DFL) and signal(17, SIG_DFL) succeed. Drop the SIG_ERR rejection, which has no kernel basis and which sigaction does not apply.
signal() returned SIG_ERR with EINVAL for any signal without a host
equivalent, such as SIGHUP, SIGPIPE and SIGUSR1, while sigaction()
accepted them. FreeBSD's signal() is sigaction() with SA_RESTART and fails
only for numbers outside 1..128 and for SIGKILL and SIGSTOP.
RetroArch (PPSA99169) stops at alarm on main: `FAIL: unresolved ELF import DQXJraCc1rA from libSceLibcInternal.prx`.
alarm(seconds) arms one process-wide real-time alarm and returns the seconds left on the previous one, rounded up like FreeBSD's alarm.c (any partial second counts); alarm(0) cancels it. When it expires, SIGALRM's disposition as recorded by sigaction or signal applies: ignored, nothing happens; default, the process terminates as on FreeBSD (exit status 128 + 14); a guest handler throws, because asynchronous delivery to a guest handler is not implemented.
The timer lives in libkernel next to the signal dispositions (GuestAlarm_nid_no_patch); libSceLibcInternal, which the titles import alarm from, forwards to it.
AI-assisted (Claude Code).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
sigprocmask keeps the first word of the title's set as it is, where
FreeBSD keeps signal n at bit n - 1 (_SIG_BIT), but Dispatch tested bit
n. A title that blocked SIGTERM with a FreeBSD-built set (bit 14) was
not protected, and a set with bit 15 blocked SIGTERM instead of SIGURG.
Dispatch now tests bit n - 1; the stored mask and the set returned by
sigprocmask are unchanged.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
EVO-PLAYER (PPSA99039) v0.11.0 stops at sigaction once its earlier
imports resolve: it installs a crash handler for SIGSEGV, SIGBUS and
SIGABRT and a quit handler for SIGTERM, SIGINT and SIGHUP at start-up.
sigaction records the handler, flags and mask of signals 1 to 128 and
reports them back, with FreeBSD's EINVAL cases. signal shares the table
and records SA_RESTART, as FreeBSD's libc does. Plain handlers on the
signals signal already delivers run as signal handlers do; SA_SIGINFO
handlers and other signals are recorded only, and raise of such a
signal throws.
Assisted by Claude Code.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01DwFnKjMxmwGDWiuYYf1v4D
Guest signal handlers are called from a host dispatcher, so no guest PC is
a signal trampoline: return 0 for every address, as KytyPS5 and prosper do.
Co-Authored-By: Claude <[email protected]>