summaryrefslogtreecommitdiffstats
path: root/Python/pystate.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/pystate.c')
-rw-r--r--Python/pystate.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/Python/pystate.c b/Python/pystate.c
index 2f1521e..b1e085b 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -2057,19 +2057,36 @@ _PyThreadState_Attach(PyThreadState *tstate)
Py_FatalError("non-NULL old thread state");
}
- _PyEval_AcquireLock(tstate);
- // XXX assert(tstate_is_alive(tstate));
- current_fast_set(&_PyRuntime, tstate);
- tstate_activate(tstate);
+ while (1) {
+ int acquired_gil = _PyEval_AcquireLock(tstate);
- if (!tstate_try_attach(tstate)) {
- tstate_wait_attach(tstate);
- }
+ // XXX assert(tstate_is_alive(tstate));
+ current_fast_set(&_PyRuntime, tstate);
+ tstate_activate(tstate);
+
+ if (!tstate_try_attach(tstate)) {
+ tstate_wait_attach(tstate);
+ }
#ifdef Py_GIL_DISABLED
- _Py_qsbr_attach(((_PyThreadStateImpl *)tstate)->qsbr);
+ if (_PyEval_IsGILEnabled(tstate) != acquired_gil) {
+ // The GIL was enabled between our call to _PyEval_AcquireLock()
+ // and when we attached (the GIL can't go from enabled to disabled
+ // here because only a thread holding the GIL can disable
+ // it). Detach and try again.
+ assert(!acquired_gil);
+ tstate_set_detached(tstate, _Py_THREAD_DETACHED);
+ tstate_deactivate(tstate);
+ current_fast_clear(&_PyRuntime);
+ continue;
+ }
+ _Py_qsbr_attach(((_PyThreadStateImpl *)tstate)->qsbr);
+#else
+ (void)acquired_gil;
#endif
+ break;
+ }
// Resume previous critical section. This acquires the lock(s) from the
// top-most critical section.