162 threadchannel worker parked on recv hangs process shutdown when the sender finishes without close#166
Merged
Conversation
…es without close()
A worker spawned with Async\spawn_thread() and parked on ThreadChannel::recv()
kept the whole process alive once the owning side finished without close(): the
non-awaited worker pinned the parent scheduler, so the parent never reached
request shutdown to release the channel, and recv() blocked forever with no
output and no diagnostic.
1. Transparent thread completion event (libuv_reactor.c/.h). The event is hidden
and its notify handle is unref'd by default, so a non-awaited worker no longer
keeps the parent loop alive. start() creates the OS thread on the first call
(ASYNC_THREAD_F_LAUNCHED) and stays transparent; a later start() from an
awaiter arms the wait (uv_ref + count). stop() disarms back to transparent.
CLOSED is set on completion in notify_cb after stop(), because the stop
prologue short-circuits on a closed event and would skip the disarm. An
awaited worker is kept alive by its suspended coroutine.
2. Endpoint-drop disconnect for PHP ThreadChannels (thread_channel.c/.h). A
channel left with a single wrapper (ref_count <= 1) has no other thread that
could be a peer, so parked recv()/send() wake with ThreadChannelException
("no producers/consumers remain"), checked both at park (last peer dropped
before we parked) and on dispose (peer drops while parked). Raw pool channels
keep auto_disconnect off and close() explicitly.
Tests: thread_channel/042; full thread/thread_channel/thread_pool suites green.
Claude-Session: https://claude.ai/code/session_01NMdPEuD85qzTjv2N4ihTQU
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…el registry Replaces the ref_count-based disconnect from the previous commit, which was wrong for fan-out (N>1 workers on one channel) and the thread pool. ref_count counts wrappers, not endpoints, so no per-channel condition is reliable. Instead: every live shared channel is tracked in a process-wide registry, and libuv_reactor_quiesce() closes them all before waiting for child threads. A worker parked on recv()/send() then wakes with ThreadChannelException and exits. Combined with the transparent thread event (parent reaches shutdown instead of pinning on a non-awaited worker), this fixes the hang for any number of workers. Tests: thread_channel/042 (recv), 043 (producer coroutine), 044 (fan-out). Claude-Session: https://claude.ai/code/session_01NMdPEuD85qzTjv2N4ihTQU
…ent worker) Worker output emitted during shutdown disconnect double-flushed on the CI multi-core runner (a thread-stdout artifact, not a logic double-disconnect; 40x local runs were clean). The tests now keep the worker silent on disconnect and assert only the owner output: a hang fails via timeout, a spurious value fails via extra output. Claude-Session: https://claude.ai/code/session_01NMdPEuD85qzTjv2N4ihTQU
…shutdown thread_channel/orphan_recv.feature: a coroutine spawns N workers parked on recv() of a fresh ThreadChannel and finishes without close()/await(). The shutdown registry close_all() must disconnect every worker. New step in _harness/Steps.php. 5 .phpt x random:1..30 green on ASAN+async-fuzz (150 interleavings, no hang/leak/UAF), including fan-out. Claude-Session: https://claude.ai/code/session_01NMdPEuD85qzTjv2N4ihTQU
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.
No description provided.