NetBSD-Users archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: copyparty ignores signals (inc. SIGINT)
> Date: Sat, 13 Dec 2025 00:56:39 +0000 (UTC)
> From: RVP <rvp%SDF.ORG@localhost>
>
> Hmm. In FreeBSD, OpenBSD & Linux, pthread_sigmask(3) seems to apply
> per-thread, but on NetBSD, the whole process gets blocked--not just
> the thread which called pthread_sigmask():
This is not accurate: NetBSD pthread_sigmask correctly blocks signals
only in the thread, not in the whole process. (NetBSD doesn't even
store a process-wide signal mask at all, only per-thread signal
masks.) But your test program isn't testing that.
When one thread has a signal unblocked, and another thread has that
signal blocked but is waiting for it in sigwait(), it is arbitrary
which of those threads the signal is delivered to, just like if two
threads both have the signal unblocked. Quoth POSIX.1-2024:
> Signals generated for the process shall be delivered to exactly one
> of those threads within the process which is in a call to a
> sigwait() function selecting that signal or has not blocked delivery
> of the signal.
https://pubs.opengroup.org/onlinepubs/9799919799/functions/V2_chap02.html#tag_16_04_01
It's not clear from the short ktrace fragment what's going on, and
https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py
looks way too sketchy for me to bother running it myself, but maybe
someone who is willing to run it can produce a larger ktrace fragment
that covers both the sigaction/pthread_sigmask/sigwait _and_ the
signal delivery to see what's going on.
Note: When you examine `ps -o sigmask', it's different on NetBSD and
others just because we don't use the same per-thread state to record
the signals that sigwait() is waiting for. POSIX requires a signal to
be blocked in a thread in order for that thread to wait for it with
sigwait(), so it's not surprising that you see the signal blocked in
ps(1) output:
> The signals defined by set shall have been blocked at the time of
> the call to sigwait(); otherwise, the behavior is undefined.
https://pubs.opengroup.org/onlinepubs/9799919799/functions/sigwait.html
Internally, NetBSD stores a linked list of threads in sigwait() per
process (p_sigwaiters), and a set of signals to wait for per thread
(l_sigwaited), separately from the per-thread signal mask (l_sigmask)
where the signal remains internally recorded as blocked during
sigwait(). The signal delivery logic (arbitrarily) checks for threads
waiting in sigwait() before trying other threads:
- sigwait() sets up the current thread on p_sigwaiters:
https://nxr.netbsd.org/xref/src/sys/kern/sys_sig.c?r=1.61#811
- Signal delivery checks p_sigwaiters first before trying
non-sigwait() delivery:
https://nxr.netbsd.org/xref/src/sys/kern/kern_sig.c?r=1.411#1378
https://nxr.netbsd.org/xref/src/sys/kern/kern_sig.c?r=1.411#1218
In contrast, in FreeBSD, sigwait() unblocks the signal internally, and
signal delivery (arbitrarily) checks for the _first_ thread with the
signal unblocked before determining whether it's waiting in sigwait()
or not, so it's not surprising that on FreeBSD, ps(1) reports the
signals unblocked while in sigwait():
- sigwait() internally unblocks the signal and waits for a wakeup:
https://cgit.freebsd.org/src/tree/sys/kern/kern_sig.c?id=4f184fd35d81bbd85284d47d2a65aeece67e87d4#n1380
- Signal delivery checks for the first thread with signal unblocked,
queues it, and wakes up that thread -- it's up to the thread to
react by running the signal handler or by waking up in sigwait():
https://cgit.freebsd.org/src/tree/sys/kern/kern_sig.c?id=4f184fd35d81bbd85284d47d2a65aeece67e87d4#n2310
https://cgit.freebsd.org/src/tree/sys/kern/kern_sig.c?id=4f184fd35d81bbd85284d47d2a65aeece67e87d4#n2167
Home |
Main Index |
Thread Index |
Old Index