Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update comments and _PyThreadState_Suspend.
_PyThreadState_Suspend now switches to "detached" if there is no active
stop-the-world request.
  • Loading branch information
colesbury committed Dec 18, 2023
commit 470298fc67c4ab628b6786fafb761a689f64b5f9
27 changes: 13 additions & 14 deletions Include/internal/pycore_pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,23 @@ extern "C" {
// transitions between "attached" and "detached" on its own PyThreadState.
//
// The "suspended" state is used to implement stop-the-world pauses, such as
// for cyclic garbage collection. It is only used in `--disable-gil` builds. It
// is similar to the "detached" state, but only the thread performing a
// stop-the-world pause may transition a thread from the "suspended" state back
// to the "detached" state. A thread trying to "attach" from the "suspended"
// state will block until it is transitioned back to "detached" when the
// stop-the-world pause is complete.
// for cyclic garbage collection. It is only used in `--disable-gil` builds.
// The "suspended" state is similar to the "detached" state in that in both
// states the thread is not allowed to call most Python APIs. However, unlike
// the "detached" state, a thread may not transition itself out from the
// "suspended" state. Only the thread performing a stop-the-world pause may
// transition a thread from the "suspended" state back to the "detached" state.
//
// State transition diagram:
//
// (bound thread) (stop-the-world thread)
// [attached] <-> [detached] <-> [suspended]
// + ^
// +--------------------------------------------------------+
// | ^
// +---------------------------->---------------------------+
// (bound thread)
//
// See `_PyThreadState_Attach()`, `_PyThreadState_Detach()`, and
// `_PyThreadState_Suspend()`.
// The (bound thread) and (stop-the-world thread) labels indicate which thread
// is allowed to perform the transition.
#define _Py_THREAD_DETACHED 0
#define _Py_THREAD_ATTACHED 1
#define _Py_THREAD_SUSPENDED 2
Expand Down Expand Up @@ -153,10 +153,9 @@ extern void _PyThreadState_Detach(PyThreadState *tstate);
// Detaches the current thread to the "suspended" state if a stop-the-world
// pause is in progress.
//
// If there is no stop-the-world pause in progress, then this function is
// a no-op. Returns one if the thread was switched to the "suspended" state and
// zero otherwise.
extern int _PyThreadState_Suspend(PyThreadState *tstate);
// If there is no stop-the-world pause in progress, then the thread switches
// to the "detached" state.
extern void _PyThreadState_Suspend(PyThreadState *tstate);

// Perform a stop-the-world pause for all threads in the all interpreters.
//
Expand Down
9 changes: 4 additions & 5 deletions Python/ceval_gil.c
Original file line number Diff line number Diff line change
Expand Up @@ -952,11 +952,10 @@ _Py_HandlePending(PyThreadState *tstate)
/* Stop-the-world */
if (_Py_eval_breaker_bit_is_set(interp, _PY_EVAL_PLEASE_STOP_BIT)) {
_Py_set_eval_breaker_bit(interp, _PY_EVAL_PLEASE_STOP_BIT, 0);
if (_PyThreadState_Suspend(tstate)) {
/* The attach blocks until the stop-the-world event is complete. */
_PyThreadState_Attach(tstate);
}
// else: stale stop-the-world event, ignore it!
_PyThreadState_Suspend(tstate);

/* The attach blocks until the stop-the-world event is complete. */
_PyThreadState_Attach(tstate);
}

/* Pending signals */
Expand Down
9 changes: 5 additions & 4 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1876,7 +1876,7 @@ _PyThreadState_Detach(PyThreadState *tstate)
detach_thread(tstate, _Py_THREAD_DETACHED);
}

int
void
_PyThreadState_Suspend(PyThreadState *tstate)
{
_PyRuntimeState *runtime = &_PyRuntime;
Expand All @@ -1894,8 +1894,10 @@ _PyThreadState_Suspend(PyThreadState *tstate)
HEAD_UNLOCK(runtime);

if (stw == NULL) {
// Don't suspend if we are not in a stop-the-world event.
return 0;
// Switch directly to "detached" if there is no active stop-the-world
// request.
detach_thread(tstate, _Py_THREAD_DETACHED);
return;
}

// Switch to "suspended" state.
Expand All @@ -1905,7 +1907,6 @@ _PyThreadState_Suspend(PyThreadState *tstate)
HEAD_LOCK(runtime);
decrement_stoptheworld_countdown(stw);
HEAD_UNLOCK(runtime);
return 1;
}

// Decrease stop-the-world counter of remaining number of threads that need to
Expand Down