Skip to content

Rename PyGILState_Check() #131264

Open
Open
@ericsnowcurrently

Description

@ericsnowcurrently

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions