@@ -998,6 +998,7 @@ _PyInterpreterState_Clear(PyThreadState *tstate)
998
998
999
999
1000
1000
static inline void tstate_deactivate (PyThreadState * tstate );
1001
+ static void tstate_set_detached (PyThreadState * tstate );
1001
1002
static void zapthreads (PyInterpreterState * interp );
1002
1003
1003
1004
void
@@ -1011,9 +1012,7 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
1011
1012
PyThreadState * tcur = current_fast_get (runtime );
1012
1013
if (tcur != NULL && interp == tcur -> interp ) {
1013
1014
/* Unset current thread. After this, many C API calls become crashy. */
1014
- current_fast_clear (runtime );
1015
- tstate_deactivate (tcur );
1016
- _PyEval_ReleaseLock (interp , NULL );
1015
+ _PyThreadState_Detach (tcur );
1017
1016
}
1018
1017
1019
1018
zapthreads (interp );
@@ -1651,6 +1650,7 @@ static void
1651
1650
tstate_delete_common (PyThreadState * tstate )
1652
1651
{
1653
1652
assert (tstate -> _status .cleared && !tstate -> _status .finalized );
1653
+ assert (tstate -> state != _Py_THREAD_ATTACHED );
1654
1654
1655
1655
PyInterpreterState * interp = tstate -> interp ;
1656
1656
if (interp == NULL ) {
@@ -1711,6 +1711,7 @@ void
1711
1711
_PyThreadState_DeleteCurrent (PyThreadState * tstate )
1712
1712
{
1713
1713
_Py_EnsureTstateNotNULL (tstate );
1714
+ tstate_set_detached (tstate );
1714
1715
tstate_delete_common (tstate );
1715
1716
current_fast_clear (tstate -> interp -> runtime );
1716
1717
_PyEval_ReleaseLock (tstate -> interp , NULL );
@@ -1867,6 +1868,79 @@ tstate_deactivate(PyThreadState *tstate)
1867
1868
// It will still be used in PyGILState_Ensure().
1868
1869
}
1869
1870
1871
+ static int
1872
+ tstate_try_attach (PyThreadState * tstate )
1873
+ {
1874
+ #ifdef Py_NOGIL
1875
+ int expected = _Py_THREAD_DETACHED ;
1876
+ if (_Py_atomic_compare_exchange_int (
1877
+ & tstate -> state ,
1878
+ & expected ,
1879
+ _Py_THREAD_ATTACHED )) {
1880
+ return 1 ;
1881
+ }
1882
+ return 0 ;
1883
+ #else
1884
+ assert (tstate -> state == _Py_THREAD_DETACHED );
1885
+ tstate -> state = _Py_THREAD_ATTACHED ;
1886
+ return 1 ;
1887
+ #endif
1888
+ }
1889
+
1890
+ static void
1891
+ tstate_set_detached (PyThreadState * tstate )
1892
+ {
1893
+ assert (tstate -> state == _Py_THREAD_ATTACHED );
1894
+ #ifdef Py_NOGIL
1895
+ _Py_atomic_store_int (& tstate -> state , _Py_THREAD_DETACHED );
1896
+ #else
1897
+ tstate -> state = _Py_THREAD_DETACHED ;
1898
+ #endif
1899
+ }
1900
+
1901
+ void
1902
+ _PyThreadState_Attach (PyThreadState * tstate )
1903
+ {
1904
+ #if defined(Py_DEBUG )
1905
+ // This is called from PyEval_RestoreThread(). Similar
1906
+ // to it, we need to ensure errno doesn't change.
1907
+ int err = errno ;
1908
+ #endif
1909
+
1910
+ _Py_EnsureTstateNotNULL (tstate );
1911
+ if (current_fast_get (& _PyRuntime ) != NULL ) {
1912
+ Py_FatalError ("non-NULL old thread state" );
1913
+ }
1914
+
1915
+ _PyEval_AcquireLock (tstate );
1916
+
1917
+ // XXX assert(tstate_is_alive(tstate));
1918
+ current_fast_set (& _PyRuntime , tstate );
1919
+ tstate_activate (tstate );
1920
+
1921
+ if (!tstate_try_attach (tstate )) {
1922
+ // TODO: Once stop-the-world GC is implemented for --disable-gil builds
1923
+ // this will need to wait until the GC completes. For now, this case
1924
+ // should never happen.
1925
+ Py_FatalError ("thread attach failed" );
1926
+ }
1927
+
1928
+ #if defined(Py_DEBUG )
1929
+ errno = err ;
1930
+ #endif
1931
+ }
1932
+
1933
+ void
1934
+ _PyThreadState_Detach (PyThreadState * tstate )
1935
+ {
1936
+ // XXX assert(tstate_is_alive(tstate) && tstate_is_bound(tstate));
1937
+ assert (tstate -> state == _Py_THREAD_ATTACHED );
1938
+ assert (tstate == current_fast_get (& _PyRuntime ));
1939
+ tstate_set_detached (tstate );
1940
+ tstate_deactivate (tstate );
1941
+ current_fast_clear (& _PyRuntime );
1942
+ _PyEval_ReleaseLock (tstate -> interp , tstate );
1943
+ }
1870
1944
1871
1945
//----------
1872
1946
// other API
@@ -1939,56 +2013,15 @@ PyThreadState_Get(void)
1939
2013
return tstate ;
1940
2014
}
1941
2015
1942
-
1943
- static void
1944
- _swap_thread_states (_PyRuntimeState * runtime ,
1945
- PyThreadState * oldts , PyThreadState * newts )
1946
- {
1947
- // XXX Do this only if oldts != NULL?
1948
- current_fast_clear (runtime );
1949
-
1950
- if (oldts != NULL ) {
1951
- // XXX assert(tstate_is_alive(oldts) && tstate_is_bound(oldts));
1952
- tstate_deactivate (oldts );
1953
- }
1954
-
1955
- if (newts != NULL ) {
1956
- // XXX assert(tstate_is_alive(newts));
1957
- assert (tstate_is_bound (newts ));
1958
- current_fast_set (runtime , newts );
1959
- tstate_activate (newts );
1960
- }
1961
- }
1962
-
1963
- PyThreadState *
1964
- _PyThreadState_SwapNoGIL (PyThreadState * newts )
1965
- {
1966
- #if defined(Py_DEBUG )
1967
- /* This can be called from PyEval_RestoreThread(). Similar
1968
- to it, we need to ensure errno doesn't change.
1969
- */
1970
- int err = errno ;
1971
- #endif
1972
-
1973
- PyThreadState * oldts = current_fast_get (& _PyRuntime );
1974
- _swap_thread_states (& _PyRuntime , oldts , newts );
1975
-
1976
- #if defined(Py_DEBUG )
1977
- errno = err ;
1978
- #endif
1979
- return oldts ;
1980
- }
1981
-
1982
2016
PyThreadState *
1983
2017
_PyThreadState_Swap (_PyRuntimeState * runtime , PyThreadState * newts )
1984
2018
{
1985
2019
PyThreadState * oldts = current_fast_get (runtime );
1986
2020
if (oldts != NULL ) {
1987
- _PyEval_ReleaseLock ( oldts -> interp , oldts );
2021
+ _PyThreadState_Detach ( oldts );
1988
2022
}
1989
- _swap_thread_states (runtime , oldts , newts );
1990
2023
if (newts != NULL ) {
1991
- _PyEval_AcquireLock (newts );
2024
+ _PyThreadState_Attach (newts );
1992
2025
}
1993
2026
return oldts ;
1994
2027
}
0 commit comments