How to Get Thread State in No_GIL Version 3.13

I’m doing some hacking in the gcmodule.c with Py_GIL_DISABLED turned on in 3.13. I noticed that it needs extra operations to handle runtime thread states for NO_GIL.

I wrote my own function in Modules/gcmodule.c, say inspect_gc_list() which is called by PyThread_start_new_thread(inspect_gc_list, args) that acts similar to gc.get_objects(), underlying impl is gc_get_objects_impl(). It requires gcstate to get the GEN_HEAD, which is obtained from &tstate->interp->gc;.

For normal GIL-enabled build, one needs to hold GIL by calling PyGILState_Ensure() so that tstate != NULL. I face no problem with that.

However, I noticed in PEP 703 Thread State. For NO_GIL build, “Just as threads previously needed to acquire the GIL before accessing or modifying Python objects, they now must be in the ATTACHED state before accessing or modifying Python objects.”

My question is, how to set the thread state to ATTACHED state? I tried this in my inspect_gc_list():

PyGILState_STATE gstate = PyGILState_Ensure();
PyThreadState *tstate = _PyThreadState_GET();
_PyThreadState_Attach(tstate);
...

But it shows error:

Fatal Python error: _PyThreadState_Attach: non-NULL old thread state
Python runtime state: initialized

I don’t quite get this non-NULL old thread state error message coming from current_fast_get(&_PyRuntime) != NULL). Can only the main interpreter thread call _PyThreadState_Attach(), I don’t think so? I might missed something.

Another side question is, this PEP says When compiling without the GIL, the garbage collector will only use a single generation. But I don’t see the gcmodule handles that? The NUM_GENERATIONS macro is still 3. Plus, I don’t see any usage of ob_gc_bits in PyObject except initializing. Is it still in development? Thank you.

Are you aware that The GIL has not been removed yet? Currently, this branch only has (some of) the preparatory patches need to remove it and not predictably break lots of stuff.

1 Like