I’m looking for guidance on whether CPython should expose a public C API to allow extension modules to query whether the GIL is currently enabled, for example:
int PyInterpreterState_IsGilEnabled(PyInterpreterState *interp);
Context:
A Python-level diagnostic API, sys._is_gil_enabled(), has already been added.
Some C extensions may want to make similar diagnostic decisions without calling back into Python (e.g. via PySys_GetAttr + PyObject_CallNoArgs).
The use case is primarily reporting, diagnostics, and choosing reasonable defaults (e.g. threading vs multiprocessing backends), not controlling GIL behavior.
Can you go into a little bit more detail about why the Python API for this isn’t usable? What are you doing specifically in your extension such that that the Python overhead is important for peformance?
To clarify, the Python API is usable, and this isn’t about tight inner-loop performance. The motivation is more about layering, ergonomics, and correctness for C extensions.
Some examples of where a direct C API would be preferable:
C extensions that want to make early or one-time decisions (e.g. choosing a threading vs multiprocessing backend, or enabling certain code paths) during initialization, where calling back into Python is awkward or undesirable.
Diagnostic or reporting code in C extensions (similar in spirit to Py_IsInitialized or other runtime-introspection APIs) that would prefer not to depend on Python-level attribute lookups and calls.
Situations where extensions are already operating at the C runtime/interpreter layer and want to query interpreter state directly, rather than re-entering Python and managing references, error handling, etc.
So this isn’t primarily about saving a few cycles, but about providing a clear, supported way for C code to query interpreter state, analogous to other CPython-specific introspection APIs.
That said, if the consensus is that the existing Python-level API is sufficient and a public C API would add too much surface area, I’m fine with that conclusion as well.
I think it would make more sense to make _PyEval_IsGILEnabled public rather than add PyInterpreterState_IsGilEnabled. Passing an interp parameter is more friction for users.
Exposing an existing helper like _PyEval_IsGILEnabled does seem simpler and avoids the need for extensions to handle an interpreter pointer explicitly.
Would the intent be to make this a public, CPython-specific C API (i.e. without the leading underscore), or to expose it as-is in public headers? And assuming there’s agreement on that direction, would it be OK for me to work on the necessary changes (headers, docs, tests)?
This should be an unstable C API, since this is pretty specific to CPython and we might want to change/remove it.
That said, to add C APIs, you need to open an issue with the C API working group. Please do that and get their approval (via a vote) before opening any PRs.
I’ll open an issue with the C API working group to propose this as an unstable, CPython-specific API and will wait for their approval before proceeding further.
Just to confirm: should any next step here (such as initiating a CAPWG vote) be handled by a core dev, or should contributors wait unless explicitly asked?
It’s a bit of a gray area. Generally speaking, all new C APIs should go through the WG, but there are sometimes exceptions. PyUnstable_Object_Dump and PyUnstable_Object_EnableDeferredRefcount were both APIs that went through them, for example. Sometimes the WG is skipped if there’s a rush to get the function out (such as with PyUnstable_Object_IsUniqueReferencedTemporary).
I’m inclined to point to the WG here, because there’s plenty of time before the 3.15 beta freeze, and as far as I can tell, there’s some ambiguity about the actual use case (I’m pretty sure the examples provided above were generated by an LLM).
Yeah - at least from what I’ve found, knowing if the GIL has been enabled is much less useful than you’d initially think. It only really tells you the situation at a single moment in time so you almost can’t do anything with it because it might have changed by the time it matters. You basically have to have a really short block that you know can’t be interrupted.
I suspect the function probably should exist. But it also should have a big note in the documentation saying “this is useless - don’t use it”.