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