Skip to content

Rename PyGILState_Check() #131264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
ericsnowcurrently opened this issue Mar 14, 2025 · 8 comments
Open

Rename PyGILState_Check() #131264

ericsnowcurrently opened this issue Mar 14, 2025 · 8 comments
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-C-API type-feature A feature request or enhancement

Comments

@ericsnowcurrently
Copy link
Member

ericsnowcurrently commented Mar 14, 2025

Feature or enhancement

Proposal:

Nearly all of the C-API expects that the current thread holds the GIL when called. Mostly, users of the C-API had to know before calling the C-API. Beck in the day it wasn't obvious how. This was the motivation behind adding PyGILState_Check().

The key point in this issue is that the name PyGILState_Check() unnecessarily associates the capability with the PyGILState_* API. Users would benefit from a different function name. I'd think something like Py_HoldsGIL() would be better.


Why was the function added as PyGILState_Check()? Perhaps @kristjanvalur remembers. It was added in 2013, 10 years after the PEP 311 implementation, so it's not because it was part of the PEP. I'd guess it's mostly because it was implemented using PyGILState_GetThisThreadState().

It's also notable that a lot of things have changed in the runtime since 2013. At the time PyGILState_Check() was added:

  • you could use PyThreadState_Get() (or PyThreadState_GET()) to get the tstate active in the current thread, but only if it held the GIL
  • you could get the last active tstate in the current thread using PyGILState_GetThisThreadState()
  • internally there was a static PyThreadState_IsCurrent() that sort of merged the two

Here some of the developments since then:

  • every tstate now knows whether or not it holds the GIL
  • the runtime now keeps track of the last tstate to hold the GIL
  • the current tstate has moved from a global variable to a thread-local variable
  • each interpreter now has its own GIL

Here's the history in some detail:

(expand)
  • 1997 - thread state (& interp state) introduced (commit a027efa)
    • current tstate stored in static global variable
    • PyThreadState_Get() exposes it
    • PyThreadState_Swap() modifies it
    • GIL must be held to call it, so that global effectively indicates which tstate (i.e. thread) holds the GIL
  • 1998 - added PyThreadState_GET() macro (commit 275ea67)
    • current tstate global variable moved to "internal" C-API (commit 18bc7c2)
  • 2003 - PEP 311 adds the PyGILState_* API (commit 8d98d2c),
    • last tstate used in current OS thread stored in thread-specific storage (autoTLSkey)
    • PyGILState_GetThisThreadState() exposes it
    • it is set to NULL when a tstate is destroyed and it was the last one used in the current thread
    • adds static PyThreadState_IsCurrent() that indicates if that thread-local tstate holds the GIL
    • PyGILState_Check() does not exist yet
  • 2009 - new GIL impl (commit 074e5ed)
    • adds new "last_holder" and "held" state
  • 2013 - PyGILState_Check() added (Add api PyGILState_Check #61724, commit 684cd0e)
    • effectively exposes PyThreadState_IsCurrent(PyGILState_GetThisThreadState())
  • 2017 - _PyRuntimeState added (commit 2ebc5ce)
    • moved "current" tstate from global var in pystate.c (_PyThreadState_Current) to _PyRuntime.gilstate.tstate_current
    • moved GILState-related global vars to _PyRuntime.gilstate
    • moved GIL from global vars to _PyRuntime.ceval.gil
  • 2018 - added _PyThreadState_GET(), without NULL check (commit 50b4857)
  • 2023 - moved "current" tstate from _PyRuntime.gilstate.tstate_current to _PyRuntime.tstate_current (commit 6036c3e)
  • 2023 - moved "current" tstate to a thread-local variable in pystate.c (commit f8abfa3)
  • 2023 - added internal current_thread_holds_gil (commit 92d8bff)
  • 2023 - moved GIL to the interpreter state (commit 5c9ee49)
  • 2024 - added PyThreadState._status.holds_gil (commit be1dfcc)

Has this already been discussed elsewhere?

No response given

Links to previous discussion of this feature:

No response

@ericsnowcurrently ericsnowcurrently added 3.14 bugs and security fixes topic-C-API type-feature A feature request or enhancement labels Mar 14, 2025
@picnixz picnixz added interpreter-core (Objects, Python, Grammar, and Parser dirs) and removed 3.14 bugs and security fixes labels Mar 14, 2025
@ericsnowcurrently
Copy link
Member Author

FTR, there's a recent proposal that discusses some of the related name issues: https://discuss.python.org/t/a-new-api-for-ensuring-releasing-thread-states/83959.

@ZeroIntensity
Copy link
Member

I'd think something like Py_HoldsGIL() would be better.

I'm pretty much against any new APIs with "GIL" in the name, because they're not very intuitive for free-threading. How about Py_HoldsTstate, named after the assertion API (_Py_AssertHoldsTstate)?

@ericsnowcurrently
Copy link
Member Author

FWIW, "HoldsTstate" doesn't mean much to me.

@ZeroIntensity
Copy link
Member

Yeah, there's not a good correlation between thread states and the GIL (yet, hopefully). If we want to stay away from thread states, how about something like Py_CanCallInterpreter?

@colesbury
Copy link
Contributor

PyThreadState_GetUnchecked() != NULL seems like a sufficient way to decide if it's safe to call into the interpreter.

@kristjanvalur
Copy link
Contributor

Perhaps @kristjanvalur remembers.

Not exactly, but everything GIL-related at the time was probably PyGILState_ prefixed. Also to avoid bike shedding, putting a new function in an existing naming scope was probably useful at the time :)

@ericsnowcurrently
Copy link
Member Author

Yeah, sounds about right. 😄

@ericsnowcurrently
Copy link
Member Author

PyThreadState_GetUnchecked() != NULL seems like a sufficient way to decide if it's safe to call into the interpreter.

You're probably right.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-C-API type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

5 participants