fix: join a thread whose shutdown was only requested - #2662
Open
nicolas-grekas wants to merge 1 commit into
Open
nicolas-grekas wants to merge 1 commit into
nicolas-grekas wants to merge 1 commit into
Conversation
A worker that fails to boot publishes state.ShuttingDown from the PHP thread itself, at a point where that thread still has its whole C exit path to walk. Init then tears the runtime down, and phpThread.shutdown() returned immediately for it because RequestSafeStateChange() refuses a thread that is already shutting down. drainPHPThreads() could therefore release the main thread into sapi_shutdown() and tsrm_shutdown() while a PHP thread was still alive and registered in TSRM, which is the exact invariant php_main() relies on. shutdown() now tells a shutdown that was only requested apart from a thread that has exited: reserved and done threads return right away as before, while a thread that is merely shutting down is joined with the same grace period and force-kill behaviour as a shutdown this caller owns.
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.
state.ShuttingDownmeans two things today and the code treats them as one. NormallyphpThread.shutdown()is what publishes it, and it owns the rest of the sequence: closedrainChan, wait forDone, force-kill past the grace period. But a worker that fails to boot publishes it from inside the PHP thread, at a point where that thread still has its whole C exit path ahead of it, down togo_frankenphp_on_thread_shutdown()which is what setsDone.That publication also unblocks
initWorkers(), soInit()fails and callsshutdown(), whereRequestSafeStateChange()refuses the thread that is already shutting down and returns right away.drainPHPThreads()then releasesphp_main()intosapi_shutdown()andtsrm_shutdown()with a live PHP thread still registered in TSRM, which is exactly what the comment above that teardown says cannot happen, and it nilsphpThreadswhile that thread still indexes it from its callbacks.shutdown()now tells a shutdown that was requested from a thread that has exited: the grace period and force-kill wait moved intophpThread.waitForExit(), the owning path waits forDoneas before, and the refused path waits forDoneorReservedon a single observation, so a thread that never booted returns at once and one that is merely shutting down is joined like any other. No path changes except a thread genuinely mid-shutdown at drain time, which today only the boot-failure path produces.TestInitJoinsAThreadStuckInStartupTeardownholds a failing worker inside its shutdown hook and assertsInit()cannot return while the thread is held. Without the fix it reports the thread still shutting down, and the race detector flagsdrainPHPThreads()nil'ingphpThreadsunder the live callback.Reported by @henderkes in #2617, where the background worker boot-failure path inherited it: #2617 (comment)