GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-113964: Don't prevent new threads until all non-daemon threads exit by colesbury · Pull Request #116677 · python/cpython

Conversation

@colesbury

@colesbury colesbury commented Mar 12, 2024 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Starting in Python 3.12, we started preventing fork() and starting new threads during interpreter finalization (shutdown). This has led to a number of regressions and flaky tests. We should not prevent starting new threads (or fork()) until all non-daemon threads exit and finalization starts in earnest.

This changes the checks to use
_PyInterpreterState_GetFinalizing(interp), which is set immediately before terminating non-daemon threads.

  • Issue: 3.12 regression: "can't create new thread at interpreter shutdown" from non-daemon threads or atexit handlers #113964

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

furkanonder reacted with hooray emoji furkanonder reacted with rocket emoji
All reactions
  • 🎉 1 reaction
  • 🚀 1 reaction
@colesbury
pythongh-113964: Don't prevent new threads until all non-daemon threa…
2ccb6e1
…ds exit

Starting in Python 3.12, we started preventing fork() and starting new
threads during interpreter finalization (shutdown). This has led to a
number of regressions and flaky tests. We should not prevent starting
new threads (or fork()) until all non-daemon threads exit and
finalization starts in earnest.

This changes the checks to use
`_PyInterpreterState_GetFinalizing(interp)`, which is set immediately
before terminating non-daemon threads.
@colesbury
colesbury requested review from ericsnowcurrently, gpshead, gvanrossum and vstinner March 12, 2024 20:32
@bedevere-app bedevere-app Bot added the awaiting core review label Mar 12, 2024
@bedevere-app bedevere-app Bot mentioned this pull request Mar 12, 2024
3.12 regression: "can't create new thread at interpreter shutdown" from non-daemon threads or atexit handlers #113964
Open
@colesbury colesbury mentioned this pull request Mar 12, 2024
test_concurrent_futures.test_shutdown: AssertionError: b'' != b'apple' #112542
Closed
@colesbury

colesbury commented Mar 12, 2024

Copy link
Copy Markdown
Contributor Author

This also fixes the flaky test test_concurrent_futures.test_shutdown (#112542).

See also the discussion #114570

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@colesbury colesbury mentioned this pull request Mar 12, 2024
Checking for sys.is_finalizing before thread.start() still yields "can't create new thread at interpreter shutdown" #114570
Closed
@colesbury
Update tests
6b7d01e
@gvanrossum

gvanrossum commented Mar 12, 2024

Copy link
Copy Markdown
Member

Thanks for looking at this! I'll leave it up to @gpshead to review.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Mar 13, 2024

Copy link
Copy Markdown
Member

History of _thread changes.

(1) June 2023, issue gh-104690: _thread.start_new_thread() disallows the creation of new thread during Python finalization since the commit ce558e6 to fix issue gh-104690 which caused a crash.

(2) Sept 2023, issue gh-108987: thread_run() of Modules/_threadmodule.c now starts with:

    // gh-108987: If _thread.start_new_thread() is called before or while
    // Python is being finalized, thread_run() can called *after*.
    // _PyRuntimeState_SetFinalizing() is called. At this point, all Python
    // threads must exit, except of the thread calling Py_Finalize() whch holds
    // the GIL and must not exit.
    //
    // At this stage, tstate can be a dangling pointer (point to freed memory),
    // it's ok to call _PyThreadState_MustExit() with a dangling pointer.
    if (_PyThreadState_MustExit(tstate)) {
        // Don't call PyThreadState_Clear() nor _PyThreadState_DeleteCurrent().
        // These functions are called on tstate indirectly by Py_Finalize()
        // which calls _PyInterpreterState_Clear().
        //
        // Py_DECREF() cannot be called because the GIL is not held: leak
        // references on purpose. Python is being finalized anyway.
        thread_bootstate_free(boot, 0);
        goto exit;
    }

(3) Feb 2024, gh-114570: I added PythonFinalizationError exception in commit 3e7b7df.

With all these changes, I'm no longer sure what should be the correct behavior. I only hope that our test suite is now testing cases which caused crashes previously.

I prefer to let someone else decide on this issue :-)

The Python finalization is fragile. I took notes on old issues and the history of changes at: https://pythondev.readthedocs.io/finalization.html

gpshead reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@colesbury
Strip output
27e4bc5
@colesbury colesbury mentioned this pull request Mar 13, 2024
Disable GIL by default in free-threaded build #116749
Closed
@ericsnowcurrently ericsnowcurrently mentioned this pull request Mar 18, 2024
Can not communicate with subprocess during interpreter shutdown on windows #115219
Closed
@gpshead gpshead self-assigned this Mar 19, 2024
gpshead
gpshead approved these changes Mar 19, 2024
View reviewed changes

@gpshead gpshead left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general I think this change is correct. I believe we'll want to backport this to 3.12 (I haven't looked at how difficult that'll be though) as the issue came up there as being a behavior regression from <=3.11 that reasonable code relies on.

One thing I think we're missing with the unit test transformations to be "AtFinalization" via the main interpreter exiting and triggering is: Alternate explicit tests for atexit.register()'d handlers at finalization time. Which implies we need to explicitly define what that behavior should be. But that may be a separate PR, i've noted that on the issue.

For this, see also #115219 which I may mark a dupe.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting core review labels Mar 19, 2024
@gpshead gpshead added the needs backport to 3.12 only security fixes label Mar 19, 2024
@gpshead gpshead mentioned this pull request Mar 19, 2024
gh-113964: Restore the ability to start threads from atexit handler functions. #116982
Open
@gpshead

gpshead commented Mar 19, 2024

Copy link
Copy Markdown
Member

I created #116982 for atexit - please take a look at that. Keeping these separate makes sense, and yours should go in first. But it'll be an easier merge if the tests I build on are not removed if feasible. (otherwise no worries, i'll untangle it when merging into mine)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@colesbury

colesbury commented Mar 19, 2024

Copy link
Copy Markdown
Contributor Author

@gpshead - I don't see a way to avoid removing/replacing the atexit tests. The existing atexit tests would not pass with this PR (because the exception is not raised), and the atexit tests from your PR would not pass reliably without the other changes from your PR.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@colesbury

colesbury commented Mar 19, 2024

Copy link
Copy Markdown
Contributor Author

I will go ahead and merge this with apologies for the inevitable merge conflicts.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@colesbury
colesbury merged commit 60e105c into python:main Mar 19, 2024
@miss-islington-app

miss-islington-app Bot commented Mar 19, 2024

Copy link
Copy Markdown

Thanks @colesbury for the PR 🌮🎉.. I'm working now to backport this PR to: 3.12.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label Mar 19, 2024
@miss-islington-app

miss-islington-app Bot commented Mar 19, 2024

Copy link
Copy Markdown

Sorry, @colesbury, I could not cleanly backport this to 3.12 due to a conflict.
Please backport using cherry_picker on command line.

cherry_picker 60e105c1c11ecca1680d03c38aa06bcc77a28714 3.12
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app miss-islington-app Bot assigned colesbury Mar 19, 2024
@miss-islington-app miss-islington-app Bot unassigned gpshead Mar 19, 2024
@bedevere-app

bedevere-app Bot commented Mar 19, 2024

Copy link
Copy Markdown

GH-117029 is a backport of this pull request to the 3.12 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.12 only security fixes label Mar 19, 2024
colesbury added a commit to colesbury/cpython that referenced this pull request Mar 19, 2024
@colesbury
[3.12] pythongh-113964: Don't prevent new threads until all non-daemo…
e5503bd
…n threads exit (pythonGH-116677)

Starting in Python 3.12, we prevented calling fork() and starting new threads
during interpreter finalization (shutdown). This has led to a number of
regressions and flaky tests. We should not prevent starting new threads
(or `fork()`) until all non-daemon threads exit and finalization starts in
earnest.

This changes the checks to use `_PyInterpreterState_GetFinalizing(interp)`,
which is set immediately before terminating non-daemon threads.
(cherry picked from commit 60e105c)

Co-authored-by: Sam Gross <[email protected]>
colesbury added a commit that referenced this pull request Mar 19, 2024
@colesbury
[3.12] gh-113964: Don't prevent new threads until all non-daemon thre…
9256433
…ads exit (GH-116677) (#117029)

Starting in Python 3.12, we prevented calling fork() and starting new threads
during interpreter finalization (shutdown). This has led to a number of
regressions and flaky tests. We should not prevent starting new threads
(or `fork()`) until all non-daemon threads exit and finalization starts in
earnest.

This changes the checks to use `_PyInterpreterState_GetFinalizing(interp)`,
which is set immediately before terminating non-daemon threads.

(cherry picked from commit 60e105c)
vstinner pushed a commit to vstinner/cpython that referenced this pull request Mar 20, 2024
@colesbury @vstinner
pythongh-113964: Don't prevent new threads until all non-daemon threa…
6f0a799
…ds exit (python#116677)

Starting in Python 3.12, we prevented calling fork() and starting new threads
during interpreter finalization (shutdown). This has led to a number of
regressions and flaky tests. We should not prevent starting new threads
(or `fork()`) until all non-daemon threads exit and finalization starts in
earnest.

This changes the checks to use `_PyInterpreterState_GetFinalizing(interp)`,
which is set immediately before terminating non-daemon threads.
adorilson pushed a commit to adorilson/cpython that referenced this pull request Mar 25, 2024
@colesbury @adorilson
pythongh-113964: Don't prevent new threads until all non-daemon threa…
adda0e9
…ds exit (python#116677)

Starting in Python 3.12, we prevented calling fork() and starting new threads
during interpreter finalization (shutdown). This has led to a number of
regressions and flaky tests. We should not prevent starting new threads
(or `fork()`) until all non-daemon threads exit and finalization starts in
earnest.

This changes the checks to use `_PyInterpreterState_GetFinalizing(interp)`,
which is set immediately before terminating non-daemon threads.
@colesbury
colesbury deleted the gh-113964-thread-shutdown branch April 8, 2024 16:16
diegorusso pushed a commit to diegorusso/cpython that referenced this pull request Apr 17, 2024
@colesbury @diegorusso
pythongh-113964: Don't prevent new threads until all non-daemon threa…
8a626c5
…ds exit (python#116677)

Starting in Python 3.12, we prevented calling fork() and starting new threads
during interpreter finalization (shutdown). This has led to a number of
regressions and flaky tests. We should not prevent starting new threads
(or `fork()`) until all non-daemon threads exit and finalization starts in
earnest.

This changes the checks to use `_PyInterpreterState_GetFinalizing(interp)`,
which is set immediately before terminating non-daemon threads.
@colesbury colesbury removed their assignment Jul 19, 2024
@zzstoatzz zzstoatzz mentioned this pull request Jan 16, 2025
Switch drain_all call to be called from new thread instead of event loop. PrefectHQ/prefect#16739
Merged
3 of 4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@gpshead gpshead gpshead approved these changes
@vstinner vstinner Awaiting requested review from vstinner
@ericsnowcurrently ericsnowcurrently Awaiting requested review from ericsnowcurrently
@gvanrossum gvanrossum Awaiting requested review from gvanrossum

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@colesbury @gvanrossum @vstinner @gpshead
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.