1313#include "pycore_pylifecycle.h"
1414#include "pycore_pymem.h" // _PyMem_SetDefaultAllocator()
1515#include "pycore_pystate.h" // _PyThreadState_GET()
16+ #include "pycore_qsbr.h"
1617#include "pycore_runtime_init.h" // _PyRuntimeState_INIT
1718#include "pycore_sysmodule.h"
1819#include "pycore_refcnt.h"
@@ -164,12 +165,13 @@ _PyThreadState_Attach(PyThreadState *tstate)
164165 & tstate -> status ,
165166 _Py_THREAD_DETACHED ,
166167 _Py_THREAD_ATTACHED )) {
168+ // online for QSBR too
169+ _Py_qsbr_online (((PyThreadStateImpl * )tstate )-> qsbr );
167170
168171 // resume previous critical section
169172 if (tstate -> critical_section != 0 ) {
170173 _Py_critical_section_resume (tstate );
171174 }
172-
173175 return 1 ;
174176 }
175177 return 0 ;
@@ -178,6 +180,8 @@ _PyThreadState_Attach(PyThreadState *tstate)
178180static void
179181_PyThreadState_Detach (PyThreadState * tstate )
180182{
183+ _Py_qsbr_offline (((PyThreadStateImpl * )tstate )-> qsbr );
184+
181185 if (tstate -> critical_section != 0 ) {
182186 _Py_critical_section_end_all (tstate );
183187 }
@@ -737,7 +741,8 @@ free_threadstate(PyThreadState *tstate)
737741static void
738742init_threadstate (PyThreadState * tstate ,
739743 PyInterpreterState * interp , uint64_t id ,
740- PyThreadState * next )
744+ PyThreadState * next ,
745+ struct qsbr * empty_qsbr )
741746{
742747 if (tstate -> _initialized ) {
743748 Py_FatalError ("thread state already initialized" );
@@ -763,6 +768,18 @@ init_threadstate(PyThreadState *tstate,
763768 tstate -> native_thread_id = PyThread_get_thread_native_id ();
764769#endif
765770
771+ // First try to recycle an existing qsbr structure
772+ PyThreadStateImpl * tstate_impl = (PyThreadStateImpl * )tstate ;
773+ struct qsbr * recycled = _Py_qsbr_recycle (& _PyRuntime .qsbr_shared , tstate );
774+ if (recycled ) {
775+ tstate_impl -> qsbr = recycled ;
776+ }
777+ else {
778+ // If no recycled struct, use the newly allocated empty qsbr struct
779+ tstate_impl -> qsbr = empty_qsbr ;
780+ _Py_qsbr_register (& _PyRuntime .qsbr_shared , tstate , empty_qsbr );
781+ }
782+
766783 tstate -> py_recursion_limit = interp -> ceval .recursion_limit ,
767784 tstate -> py_recursion_remaining = interp -> ceval .recursion_limit ,
768785 tstate -> c_recursion_remaining = C_RECURSION_LIMIT ;
@@ -791,6 +808,12 @@ new_threadstate(PyInterpreterState *interp)
791808 if (new_tstate == NULL ) {
792809 return NULL ;
793810 }
811+ struct qsbr * qsbr = PyMem_RawCalloc (1 , sizeof (struct qsbr_pad ));
812+ if (qsbr == NULL ) {
813+ PyMem_RawFree (new_tstate );
814+ return NULL ;
815+ }
816+
794817 /* We serialize concurrent creation to protect global state. */
795818 HEAD_LOCK (runtime );
796819
@@ -818,13 +841,17 @@ new_threadstate(PyInterpreterState *interp)
818841 }
819842 interp -> threads .head = tstate ;
820843
821- init_threadstate (tstate , interp , id , old_head );
844+ init_threadstate (tstate , interp , id , old_head , qsbr );
822845
823846 HEAD_UNLOCK (runtime );
824847 if (!used_newtstate ) {
825848 // Must be called with lock unlocked to avoid re-entrancy deadlock.
826849 PyMem_RawFree (new_tstate );
827850 }
851+ if (qsbr -> tstate == NULL ) {
852+ // If the qsbr structure wasn't used, free it here after the unlock.
853+ PyMem_RawFree (qsbr );
854+ }
828855 return tstate ;
829856}
830857
@@ -1062,6 +1089,13 @@ tstate_delete_common(PyThreadState *tstate,
10621089 PyThread_tss_set (& gilstate -> autoTSSkey , NULL );
10631090 }
10641091
1092+ PyThreadStateImpl * tstate_impl = (PyThreadStateImpl * )tstate ;
1093+ if (is_current ) {
1094+ _Py_qsbr_offline (tstate_impl -> qsbr );
1095+ }
1096+ _Py_qsbr_unregister (tstate_impl -> qsbr );
1097+ tstate_impl -> qsbr = NULL ;
1098+
10651099 _PyRuntimeState * runtime = interp -> runtime ;
10661100 HEAD_LOCK (runtime );
10671101 if (tstate -> prev ) {
0 commit comments