@@ -565,6 +565,124 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
565565#endif
566566
567567
568+ //---------------
569+ // global objects
570+ //---------------
571+
572+ /* The global objects thread state is meant to be used in a very limited
573+ way and should not be used to actually run any Python code. */
574+
575+ static PyThreadState *
576+ bind_global_objects_state (_PyRuntimeState * runtime )
577+ {
578+ PyThreadState * main_tstate = & runtime -> cached_objects .main_tstate ;
579+
580+ bind_tstate (main_tstate );
581+ /* Unlike _PyThreadState_Bind(), we do not modify gilstate TSS. */
582+
583+ return main_tstate ;
584+ }
585+
586+ static void
587+ unbind_global_objects_state (_PyRuntimeState * runtime )
588+ {
589+ PyThreadState * main_tstate = & runtime -> cached_objects .main_tstate ;
590+ assert (tstate_is_alive (main_tstate ));
591+ assert (!main_tstate -> _status .active );
592+ assert (gilstate_tss_get (runtime ) != main_tstate );
593+
594+ unbind_tstate (main_tstate );
595+
596+ /* This thread state may be bound/unbound repeatedly,
597+ so we must erase evidence that it was ever bound (or unbound). */
598+ main_tstate -> _status .bound = 0 ;
599+ main_tstate -> _status .unbound = 0 ;
600+
601+ /* We must fully unlink the thread state from any OS thread,
602+ to allow it to be bound more than once. */
603+ main_tstate -> thread_id = 0 ;
604+ #ifdef PY_HAVE_THREAD_NATIVE_ID
605+ main_tstate -> native_thread_id = 0 ;
606+ #endif
607+ }
608+
609+ static inline void
610+ acquire_global_objects_lock (_PyRuntimeState * runtime )
611+ {
612+ /* For now we can rely on the GIL, so we don't actually
613+ acquire a global lock here. */
614+ assert (current_fast_get (runtime ) != NULL );
615+ }
616+
617+ static inline void
618+ release_global_objects_lock (_PyRuntimeState * runtime )
619+ {
620+ /* For now we can rely on the GIL, so we don't actually
621+ release a global lock here. */
622+ assert (current_fast_get (runtime ) != NULL );
623+ }
624+
625+ PyObject *
626+ _Py_AddToGlobalDict (PyObject * dict , PyObject * key , PyObject * value )
627+ {
628+ assert (dict != NULL );
629+ assert (PyDict_CheckExact (dict ));
630+
631+ /* All global objects are stored in _PyRuntime
632+ and owned by the main interpreter. */
633+ _PyRuntimeState * runtime = & _PyRuntime ;
634+ PyThreadState * curts = current_fast_get (runtime );
635+ PyInterpreterState * interp = curts -> interp ;
636+ assert (interp != NULL ); // The GIL must be held.
637+
638+ /* Due to interpreter isolation we must hold a global lock,
639+ starting at this point and ending before we return.
640+ Note that the operations in this function are very fucused
641+ and we should not expect any reentrancy. */
642+ acquire_global_objects_lock (runtime );
643+
644+ /* Swap to the main interpreter, if necessary. */
645+ PyThreadState * oldts = NULL ;
646+ if (!_Py_IsMainInterpreter (interp )) {
647+ PyThreadState * main_tstate = bind_global_objects_state (runtime );
648+
649+ oldts = _PyThreadState_Swap (runtime , main_tstate );
650+ assert (oldts != NULL );
651+ assert (!_Py_IsMainInterpreter (oldts -> interp ));
652+
653+ /* The limitations of the global objects thread state apply
654+ from this point to the point we swap back to oldts. */
655+ }
656+
657+ /* This might trigger a resize, which is why we must "acquire"
658+ the global object state. Also note that PyDict_SetDefault()
659+ must be compatible with our reentrancy and global objects state
660+ constraints. */
661+ PyObject * actual = PyDict_SetDefault (dict , key , value );
662+ if (actual == NULL ) {
663+ /* Raising an exception from one interpreter in another
664+ is problematic, so we clear it and let the caller deal
665+ with the returned NULL. */
666+ assert (PyErr_ExceptionMatches (PyExc_MemoryError ));
667+ PyErr_Clear ();
668+ }
669+
670+ /* Swap back, it it wasn't in the main interpreter already. */
671+ if (oldts != NULL ) {
672+ // The returned tstate should be _PyRuntime.cached_objects.main_tstate.
673+ _PyThreadState_Swap (runtime , oldts );
674+
675+ unbind_global_objects_state (runtime );
676+ }
677+
678+ release_global_objects_lock (runtime );
679+
680+ // XXX Immortalize the key and value.
681+
682+ return actual ;
683+ }
684+
685+
568686/*************************************/
569687/* the per-interpreter runtime state */
570688/*************************************/
@@ -1217,8 +1335,7 @@ free_threadstate(PyThreadState *tstate)
12171335
12181336static void
12191337init_threadstate (PyThreadState * tstate ,
1220- PyInterpreterState * interp , uint64_t id ,
1221- PyThreadState * next )
1338+ PyInterpreterState * interp , uint64_t id )
12221339{
12231340 if (tstate -> _status .initialized ) {
12241341 Py_FatalError ("thread state already initialized" );
@@ -1227,18 +1344,13 @@ init_threadstate(PyThreadState *tstate,
12271344 assert (interp != NULL );
12281345 tstate -> interp = interp ;
12291346
1347+ // next/prev are set in add_threadstate().
1348+ assert (tstate -> next == NULL );
1349+ assert (tstate -> prev == NULL );
1350+
12301351 assert (id > 0 );
12311352 tstate -> id = id ;
12321353
1233- assert (interp -> threads .head == tstate );
1234- assert ((next != NULL && id != 1 ) || (next == NULL && id == 1 ));
1235- if (next != NULL ) {
1236- assert (next -> prev == NULL || next -> prev == tstate );
1237- next -> prev = tstate ;
1238- }
1239- tstate -> next = next ;
1240- assert (tstate -> prev == NULL );
1241-
12421354 // thread_id and native_thread_id are set in bind_tstate().
12431355
12441356 tstate -> py_recursion_limit = interp -> ceval .recursion_limit ,
@@ -1259,6 +1371,22 @@ init_threadstate(PyThreadState *tstate,
12591371 tstate -> _status .initialized = 1 ;
12601372}
12611373
1374+ static void
1375+ add_threadstate (PyInterpreterState * interp , PyThreadState * tstate ,
1376+ PyThreadState * next )
1377+ {
1378+ assert (interp -> threads .head != tstate );
1379+ assert ((next != NULL && tstate -> id != 1 ) ||
1380+ (next == NULL && tstate -> id == 1 ));
1381+ if (next != NULL ) {
1382+ assert (next -> prev == NULL || next -> prev == tstate );
1383+ next -> prev = tstate ;
1384+ }
1385+ tstate -> next = next ;
1386+ assert (tstate -> prev == NULL );
1387+ interp -> threads .head = tstate ;
1388+ }
1389+
12621390static PyThreadState *
12631391new_threadstate (PyInterpreterState * interp )
12641392{
@@ -1298,9 +1426,9 @@ new_threadstate(PyInterpreterState *interp)
12981426 & initial ._main_interpreter ._initial_thread ,
12991427 sizeof (* tstate ));
13001428 }
1301- interp -> threads .head = tstate ;
13021429
1303- init_threadstate (tstate , interp , id , old_head );
1430+ init_threadstate (tstate , interp , id );
1431+ add_threadstate (interp , tstate , old_head );
13041432
13051433 HEAD_UNLOCK (runtime );
13061434 if (!used_newtstate ) {
@@ -1347,6 +1475,33 @@ _PyThreadState_Init(PyThreadState *tstate)
13471475 Py_FatalError ("_PyThreadState_Init() is for internal use only" );
13481476}
13491477
1478+ void
1479+ _PyThreadState_InitDetached (PyThreadState * tstate , PyInterpreterState * interp )
1480+ {
1481+ _PyRuntimeState * runtime = interp -> runtime ;
1482+
1483+ HEAD_LOCK (runtime );
1484+ interp -> threads .next_unique_id += 1 ;
1485+ uint64_t id = interp -> threads .next_unique_id ;
1486+ HEAD_UNLOCK (runtime );
1487+
1488+ init_threadstate (tstate , interp , id );
1489+ // We do not call add_threadstate().
1490+ }
1491+
1492+
1493+ static void
1494+ clear_datastack (PyThreadState * tstate )
1495+ {
1496+ _PyStackChunk * chunk = tstate -> datastack_chunk ;
1497+ tstate -> datastack_chunk = NULL ;
1498+ while (chunk != NULL ) {
1499+ _PyStackChunk * prev = chunk -> previous ;
1500+ _PyObject_VirtualFree (chunk , chunk -> size );
1501+ chunk = prev ;
1502+ }
1503+ }
1504+
13501505void
13511506PyThreadState_Clear (PyThreadState * tstate )
13521507{
@@ -1421,7 +1576,6 @@ PyThreadState_Clear(PyThreadState *tstate)
14211576 // XXX Do it as early in the function as possible.
14221577}
14231578
1424-
14251579/* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */
14261580static void
14271581tstate_delete_common (PyThreadState * tstate )
@@ -1454,17 +1608,25 @@ tstate_delete_common(PyThreadState *tstate)
14541608 unbind_tstate (tstate );
14551609
14561610 // XXX Move to PyThreadState_Clear()?
1457- _PyStackChunk * chunk = tstate -> datastack_chunk ;
1458- tstate -> datastack_chunk = NULL ;
1459- while (chunk != NULL ) {
1460- _PyStackChunk * prev = chunk -> previous ;
1461- _PyObject_VirtualFree (chunk , chunk -> size );
1462- chunk = prev ;
1463- }
1611+ clear_datastack (tstate );
14641612
14651613 tstate -> _status .finalized = 1 ;
14661614}
14671615
1616+ void
1617+ _PyThreadState_ClearDetached (PyThreadState * tstate )
1618+ {
1619+ assert (!tstate -> _status .bound );
1620+ assert (!tstate -> _status .bound_gilstate );
1621+ assert (tstate -> datastack_chunk == NULL );
1622+ assert (tstate -> thread_id == 0 );
1623+ assert (tstate -> native_thread_id == 0 );
1624+ assert (tstate -> next == NULL );
1625+ assert (tstate -> prev == NULL );
1626+
1627+ PyThreadState_Clear (tstate );
1628+ clear_datastack (tstate );
1629+ }
14681630
14691631static void
14701632zapthreads (PyInterpreterState * interp )
0 commit comments