Return the current thread state. The global interpreter lock must be held. When the current thread state is NULL, this issues a fatal error (so that the caller needn’t check for NULL).
Since the thread calling PyThreadState_Get is the one associated with its returned PyThreadState object, why must the GIL must be held prior to calling it? My understanding is the only reason the GIL would need to be held is if another thread might altar the returned PyThreadState object. If this untrue, what else might require the GIL be held? If this is true, why might another thread altar the PyThreadState of another thread?
If you dig into the implementation of PyThreadState_Get in Python/pystate.c: you’ll find that it accesses the internal _PyRuntime global PyRuntimeState structure. While the load of the _PyRuntime->tstate_current field is done using an atomic, if the interpreter were shutting down via another thread calling Py_FinalizeEx… a call to PyThreadState_Get without the GIL could wind up accessing freed PyRuntimeState memory or wind up with a result that is no longer pointing to valid memory as PyThreadState’s themselves are being freed.
Holding the GIL while using internal data structures such as the runtime state or thread states prevents this.
The contents of a PyThreadState itself also need protection by the GIL. The structure forms a doubly linked list (see struct _ts)… so other threads could be modifying those as they come and go if you don’t hold the GIL.
Point taken about attempting to access a thread’s state during or after Py_FinalizeEx is called.
The contents of a PyThreadState itself also need protection by the GIL. The structure forms a doubly linked list (see struct _ts)… so other threads could be modifying those as they come and go if you don’t hold the GIL.
That makes sense. If the thread calling PyThreadState_Get were guaranteed to not modify any internal state, the only other safety concern would be if another thread were to modify the PyThreadState object of the thread calling PyThreadState_Get, right? Is there a common example in python code where this happens, or is this more a theoretical thread-safety issue?
It might be more theoretical. I expect code could get away with doing it even though it isn’t supported. But that’s true of all thread safety issues until it isn’t.