@@ -1565,7 +1565,7 @@ tstate_delete_common(PyThreadState *tstate)
1565
1565
if (tstate -> next ) {
1566
1566
tstate -> next -> prev = tstate -> prev ;
1567
1567
}
1568
- if (tstate -> state != _Py_THREAD_GC ) {
1568
+ if (tstate -> state != _Py_THREAD_SUSPENDED ) {
1569
1569
// Any ongoing stop-the-world request should not wait for us because
1570
1570
// our thread is getting deleted.
1571
1571
if (interp -> stoptheworld .requested ) {
@@ -1805,9 +1805,9 @@ static void
1805
1805
tstate_wait_attach (PyThreadState * tstate )
1806
1806
{
1807
1807
do {
1808
- int expected = _Py_THREAD_GC ;
1808
+ int expected = _Py_THREAD_SUSPENDED ;
1809
1809
1810
- // Wait until we're switched out of GC to DETACHED.
1810
+ // Wait until we're switched out of SUSPENDED to DETACHED.
1811
1811
_PyParkingLot_Park (& tstate -> state , & expected , sizeof (tstate -> state ),
1812
1812
/*timeout=*/ -1 , NULL , /*detach=*/ 0 );
1813
1813
@@ -1871,19 +1871,8 @@ _PyThreadState_Detach(PyThreadState *tstate)
1871
1871
detach_thread (tstate , _Py_THREAD_DETACHED );
1872
1872
}
1873
1873
1874
- // Decrease stop-the-world counter of remaining number of threads that need to
1875
- // pause. If we are the final thread to pause, notify the requesting thread.
1876
- static void
1877
- decrement_stoptheworld_countdown (struct _stoptheworld_state * stw )
1878
- {
1879
- assert (stw -> thread_countdown > 0 );
1880
- if (-- stw -> thread_countdown == 0 ) {
1881
- _PyEvent_Notify (& stw -> stop_event );
1882
- }
1883
- }
1884
-
1885
- void
1886
- _PyThreadState_Park (PyThreadState * tstate )
1874
+ int
1875
+ _PyThreadState_Suspend (PyThreadState * tstate )
1887
1876
{
1888
1877
_PyRuntimeState * runtime = & _PyRuntime ;
1889
1878
@@ -1900,25 +1889,30 @@ _PyThreadState_Park(PyThreadState *tstate)
1900
1889
HEAD_UNLOCK (runtime );
1901
1890
1902
1891
if (stw == NULL ) {
1903
- // We might be processing a stale EVAL_PLEASE_STOP, in which
1904
- // case there is nothing to do. This can happen if a thread
1905
- // asks us to stop for a previous GC at the same time we detach.
1906
- return ;
1892
+ // Don't suspend if we are not in a stop-the-world event.
1893
+ return 0 ;
1907
1894
}
1908
1895
1909
- // Switch to GC state.
1910
- detach_thread (tstate , _Py_THREAD_GC );
1896
+ // Switch to "suspended" state.
1897
+ detach_thread (tstate , _Py_THREAD_SUSPENDED );
1911
1898
1912
1899
// Decrease the count of remaining threads needing to park.
1913
1900
HEAD_LOCK (runtime );
1914
1901
decrement_stoptheworld_countdown (stw );
1915
1902
HEAD_UNLOCK (runtime );
1916
-
1917
- // Wait until we are switched back to DETACHED and then re-attach. After
1918
- // this we will be in the ATTACHED state, the same as before.
1919
- tstate_wait_attach (tstate );
1903
+ return 1 ;
1920
1904
}
1921
1905
1906
+ // Decrease stop-the-world counter of remaining number of threads that need to
1907
+ // pause. If we are the final thread to pause, notify the requesting thread.
1908
+ static void
1909
+ decrement_stoptheworld_countdown (struct _stoptheworld_state * stw )
1910
+ {
1911
+ assert (stw -> thread_countdown > 0 );
1912
+ if (-- stw -> thread_countdown == 0 ) {
1913
+ _PyEvent_Notify (& stw -> stop_event );
1914
+ }
1915
+ }
1922
1916
1923
1917
#ifdef Py_GIL_DISABLED
1924
1918
// Interpreter for _Py_FOR_EACH_THREAD(). For global stop-the-world events,
@@ -1936,10 +1930,10 @@ interp_for_stop_the_world(struct _stoptheworld_state *stw)
1936
1930
// Loops over threads for a stop-the-world event.
1937
1931
// For global: all threads in all interpreters
1938
1932
// For per-interpreter: all threads in the interpreter
1939
- #define _Py_FOR_EACH_THREAD (stw ) \
1940
- for (PyInterpreterState * i = interp_for_stop_the_world((stw)); \
1933
+ #define _Py_FOR_EACH_THREAD (stw , i , t ) \
1934
+ for (i = interp_for_stop_the_world((stw)); \
1941
1935
i != NULL; i = ((stw->is_global) ? i->next : NULL)) \
1942
- for (PyThreadState * t = i->threads.head; t; t = t->next)
1936
+ for (t = i->threads.head; t; t = t->next)
1943
1937
1944
1938
1945
1939
// Try to transition threads atomically from the "detached" state to the
@@ -1948,12 +1942,14 @@ static bool
1948
1942
park_detached_threads (struct _stoptheworld_state * stw )
1949
1943
{
1950
1944
int num_parked = 0 ;
1951
- _Py_FOR_EACH_THREAD (stw ) {
1945
+ PyInterpreterState * i ;
1946
+ PyThreadState * t ;
1947
+ _Py_FOR_EACH_THREAD (stw , i , t ) {
1952
1948
int state = _Py_atomic_load_int_relaxed (& t -> state );
1953
1949
if (state == _Py_THREAD_DETACHED ) {
1954
- // Atomically transition to _Py_THREAD_GC if in detached state.
1950
+ // Atomically transition to "suspended" if in " detached" state.
1955
1951
if (_Py_atomic_compare_exchange_int (& t -> state ,
1956
- & state , _Py_THREAD_GC )) {
1952
+ & state , _Py_THREAD_SUSPENDED )) {
1957
1953
num_parked ++ ;
1958
1954
}
1959
1955
}
@@ -1983,9 +1979,12 @@ stop_the_world(struct _stoptheworld_state *stw)
1983
1979
HEAD_LOCK (runtime );
1984
1980
stw -> requested = 1 ;
1985
1981
stw -> thread_countdown = 0 ;
1982
+ stw -> stop_event = (PyEvent ){0 }; // zero-initialize (unset)
1986
1983
stw -> requester = _PyThreadState_GET (); // may be NULL
1987
1984
1988
- _Py_FOR_EACH_THREAD (stw ) {
1985
+ PyInterpreterState * i ;
1986
+ PyThreadState * t ;
1987
+ _Py_FOR_EACH_THREAD (stw , i , t ) {
1989
1988
if (t != stw -> requester ) {
1990
1989
// Count all the other threads (we don't wait on ourself).
1991
1990
stw -> thread_countdown ++ ;
@@ -2007,10 +2006,9 @@ stop_the_world(struct _stoptheworld_state *stw)
2007
2006
break ;
2008
2007
}
2009
2008
2010
- int64_t wait_ns = 1000 * 1000 ; // 1ms
2009
+ _PyTime_t wait_ns = 1000 * 1000 ; // 1ms (arbitrary, may need tuning)
2011
2010
if (PyEvent_WaitTimed (& stw -> stop_event , wait_ns )) {
2012
2011
assert (stw -> thread_countdown == 0 );
2013
- stw -> stop_event = (PyEvent ){0 };
2014
2012
break ;
2015
2013
}
2016
2014
@@ -2030,12 +2028,12 @@ start_the_world(struct _stoptheworld_state *stw)
2030
2028
stw -> world_stopped = 0 ;
2031
2029
stw -> requester = NULL ;
2032
2030
// Switch threads back to the detached state.
2033
- _Py_FOR_EACH_THREAD ( stw ) {
2034
- int state = _Py_atomic_load_int_relaxed ( & t -> state ) ;
2035
- if ( state == _Py_THREAD_GC &&
2036
- _Py_atomic_compare_exchange_int ( & t -> state ,
2037
- & state ,
2038
- _Py_THREAD_DETACHED )) {
2031
+ PyInterpreterState * i ;
2032
+ PyThreadState * t ;
2033
+ _Py_FOR_EACH_THREAD ( stw , i , t ) {
2034
+ if ( t != stw -> requester ) {
2035
+ assert ( t -> state == _Py_THREAD_SUSPENDED );
2036
+ _Py_atomic_store_int ( & t -> state , _Py_THREAD_DETACHED );
2039
2037
_PyParkingLot_UnparkAll (& t -> state );
2040
2038
}
2041
2039
}
0 commit comments