Skip to main content

Include/pystate.h

cpython 3.14 @ ab2d84fe1023/Include/pystate.h

Include/pystate.h is the public header for interpreter and thread state. It declares the opaque PyInterpreterState and PyThreadState types, the GIL release/reacquire macros, and the PyGILState convenience API for code that may or may not already hold the GIL.

Map

LinesSymbolRole
1-50Forward declarations, PyInterpreterState opaque handleInterpreter-level state
51-120PyThreadState opaque handle, accessorsPer-thread Python state
121-160Py_BEGIN_ALLOW_THREADS, Py_END_ALLOW_THREADSGIL release/reacquire macros
161-210PyGILState_STATE, PyGILState_Ensure, PyGILState_ReleaseC-thread GIL management

Reading

GIL release macros

The Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS pair is a macro pair that saves and restores the current thread state. They declare a local _save variable which means the two macros must appear in the same lexical scope.

// CPython: Include/pystate.h:150 Py_BEGIN_ALLOW_THREADS
#define Py_BEGIN_ALLOW_THREADS { \
PyThreadState *_save; \
_save = PyEval_SaveThread();

#define Py_END_ALLOW_THREADS \
PyEval_RestoreThread(_save); \
}

Any Python API call between these macros is undefined behaviour because the calling thread does not hold the GIL.

PyGILState_Ensure / PyGILState_Release

These are the safe entry points for C threads that were not started by Python (for example, callback threads from a C library). PyGILState_Ensure acquires the GIL, creating a new PyThreadState if necessary, and returns a token. PyGILState_Release uses the token to release the GIL and optionally destroy the thread state.

// CPython: Include/pystate.h:180 PyGILState_Ensure
PyAPI_FUNC(PyGILState_STATE) PyGILState_Ensure(void);
PyAPI_FUNC(void) PyGILState_Release(PyGILState_STATE);

Per-thread dictionary

PyThreadState_GetDict() returns a dict local to the current thread. It is used by threading.local() and by profiling hooks.

gopy notes

gopy uses goroutines rather than OS threads and has no GIL. The PyThreadState concept maps to goroutine-local state via context.Context. The Py_BEGIN_ALLOW_THREADS / Py_END_ALLOW_THREADS pattern has no equivalent; blocking operations simply run in a goroutine.