Conversation
{tg,t}kill, rt_tgsigqueueinfo, and thus pthread_kill validated the target
tid then queued the signal into the single process-wide pending set, so
whichever thread reached a delivery point first consumed it and standard
signals coalesced across threads. Go async preemption, pthread_cancel,
and glibc setxid / musl __synccall all interrupted the wrong thread;
interruptible blocking I/O made the gap load-bearing.
Model Linux's 2 pending sets. Extract signal_pending_t (pending bitmask,
coalesced standard siginfo, per-signal RT queues); signal_state now holds
one shared instance (signal->shared_pending, hit by kill) and each
thread_entry_t holds its own private tpending (task->pending, hit by
tgkill/tkill). signal_deliver drains the current thread's private set
before the shared set, matching dequeue_signal; signal_pending,
sigsuspend, rt_sigprocmask unblock, and rt_sigpending union the two.
Resolve the target under thread_lock and enqueue into its tpending under
sig_lock then thread_lock so a concurrent exit cannot misroute; kill and
rt_sigqueueinfo stay process-directed. Add tkill (syscall 130), which was
ENOSYS. Both directed senders validate tgid/tid and treat sig 0 as an
existence probe.
signalfd reads the caller's private set then the shared set with a
per-entry source tag so peek and take consume from the same set; a queued
directed signal wakes signalfd waiters (Linux wakes the shared sighand
queue) and a blocking read re-waits on a false wake. The pending hint
becomes shared.pending OR the union of every active thread's private set,
recomputed on thread exit so a departed thread's unconsumed directed
signal stops pinning the identity-syscall fast path off.
Close #152
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
{tg,t}kill, rt_tgsigqueueinfo, and thus pthread_kill validated the target tid then queued the signal into the single process-wide pending set, so whichever thread reached a delivery point first consumed it and standard signals coalesced across threads. Go async preemption, pthread_cancel, and glibc setxid / musl __synccall all interrupted the wrong thread; interruptible blocking I/O made the gap load-bearing.
Model Linux's 2 pending sets. Extract signal_pending_t (pending bitmask, coalesced standard siginfo, per-signal RT queues); signal_state now holds one shared instance (signal->shared_pending, hit by kill) and each thread_entry_t holds its own private tpending (task->pending, hit by tgkill/tkill). signal_deliver drains the current thread's private set before the shared set, matching dequeue_signal; signal_pending, sigsuspend, rt_sigprocmask unblock, and rt_sigpending union the two.
Resolve the target under thread_lock and enqueue into its tpending under sig_lock then thread_lock so a concurrent exit cannot misroute; kill and rt_sigqueueinfo stay process-directed. Add tkill (syscall 130), which was ENOSYS. Both directed senders validate tgid/tid and treat sig 0 as an existence probe.
signalfd reads the caller's private set then the shared set with a per-entry source tag so peek and take consume from the same set; a queued directed signal wakes signalfd waiters (Linux wakes the shared sighand queue) and a blocking read re-waits on a false wake. The pending hint becomes shared.pending OR the union of every active thread's private set, recomputed on thread exit so a departed thread's unconsumed directed signal stops pinning the identity-syscall fast path off.
Close #152
Summary by cubic
Route thread-directed signals to the exact target thread and match Linux delivery semantics. Adds
SYS_tkill, correctstgkill/rt_tgsigqueueinforouting, and hardens signalfd to handle per-thread vs shared pending sets.New Features
tpending). Delivery drains the thread’s private set before the shared set;signal_pending,rt_sigpending,rt_sigsuspend, andrt_sigprocmaskunion the two.SYS_tkill(130). Routetgkill/rt_tgsigqueueinfoto the target thread withtgidvalidation; treatsig==0as an existence probe. Keepkill/rt_sigqueueinfoprocess-directed and accept a thread TID as the PID; also honorsig==0.signalfd: read private then shared with a per-entry source tag so take consumes from the same set; re-wait on false wakes; wake signalfd on directed signals so target readers unblock while non-targets seeEAGAIN.Bug Fixes
thread_lockand enqueue into its private set undersig_lock→thread_lockto avoid misrouting during concurrent thread exit.test-tgkill-directedand a signalfd case ensuring a directed signal wakes the target’s signalfd.Written for commit 217bb85. Summary will update on new commits.