8000 gh-59956: Clarify Runtime State Status Expectations by ericsnowcurrently · Pull Request #101308 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-59956: Clarify Runtime State Status Expectations #101308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b64ce9f
Factor out tstate_verify_not_active().
ericsnowcurrently Jan 19, 2023
1be0ec4
Drop the check_current param from _PyThreadState_Delete().
ericsnowcurrently Jan 19, 2023
3454bf1
Drop _PyThreadState_Delete().
ericsnowcurrently Jan 19, 2023
a929e32
Unset the "current" thread state before zapping the threads instead o…
ericsnowcurrently Jan 19, 2023
e6ddd92
Only clear the current thread if the interpreter matches.
ericsnowcurrently Jan 19, 2023
36c512f
Always "check_current" in zapthreads().
ericsnowcurrently Jan 19, 2023
d402a82
Do not pass the runtime to _PyThreadState_DeleteExcept().
ericsnowcurrently Jan 19, 2023
2ddfe71
Add some notes, TODO comments, and asserts.
ericsnowcurrently Jan 19, 2023
99de509
Mark the main interpreter as finalizing during runtime fini.
ericsnowcurrently Jan 19, 2023
b77ae5e
Add more notes and TODO comments.
ericsnowcurrently Jan 19, 2023
9ca673c
Make PyThreadState._status more granular.
ericsnowcurrently Jan 19, 2023
8a71957
Add more status fields.
ericsnowcurrently Jan 20, 2023
62d1a93
Add a TODO.
ericsnowcurrently Jan 20, 2023
90cea92
Track active status.
ericsnowcurrently Jan 19, 2023
9965813
Clarify a TODO comment.
ericsnowcurrently Jan 20, 2023
fd5048b
Associate "bound" and "active".
ericsnowcurrently Jan 20, 2023
2105cd6
_PyThreadState_Prealloc() -> _PyThreadState_New()
ericsnowcurrently Jan 23, 2023
8b110cf
Factor out tstate_tss_*().
ericsnowcurrently Jan 24, 2023
ca98d68
current_tss_*() -> gilstate_tss_*().
ericsnowcurrently Jan 24, 2023
4f39976
Add bind_gilstate_tstate() and unbind_gilstate_tstate().
ericsnowcurrently Jan 24, 2023
6e73669
Update some TODO comments.
ericsnowcurrently Jan 24, 2023
cc3540d
Clean up _PyThreadState_Swap() a little.
ericsnowcurrently Jan 24, 2023
10000
1ce3841
Fix the stable ABI.
ericsnowcurrently Jan 25, 2023
121d328
Fixes for multiprocessing.
ericsnowcurrently Jan 25, 2023
8666362
Move a comment.
ericsnowcurrently Jan 25, 2023
52ac2d9
Preserve errno more carefully.
ericsnowcurrently Jan 25, 2023
f7ac19a
Do not call bind_gilstate_tstate() in bind_tstate().
ericsnowcurrently Jan 25, 2023
a338248
Add an assert.
ericsnowcurrently Jan 25, 2023
5be78e9
Clean up bind_gilstate_tstate().
ericsnowcurrently Jan 25, 2023
f019bd6
Clear bound_gilstate for the old thread state.
ericsnowcurrently Jan 25, 2023
6869bfe
bound_gilstate and gilstate_tss_get() must match.
ericsnowcurrently Jan 25, 2023
f91d458
Add a blank line for clarity.
ericsnowcurrently Jan 25, 2023
9b45398
Do not call unbind_gilstate_tstate() in unbind_tstate().
ericsnowcurrently Jan 25, 2023
98a2dae
Fix comments.
ericsnowcurrently Jan 25, 2023
afde196
Fix padding.
ericsnowcurrently Jan 30, 2023
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
10000
27 changes: 26 additions & 1 deletion Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,30 @@ struct _ts {
PyThreadState *next;
PyInterpreterState *interp;

int _status;
struct {
/* Has been initialized to a safe state.

In order to be effective, this must be set to 0 during or right
after allocation. */
unsigned int initialized:1;

/* Has been bound to an OS thread. */
unsigned int bound:1;
/* Has been unbound from its OS thread. */
unsigned int unbound:1;
/* Has been bound aa current for the GILState API. */
unsigned int bound_gilstate:1;
/* Currently in use (maybe holds the GIL). */
unsigned int active:1;

/* various stages of finalization */
unsigned int finalizing:1;
unsigned int cleared:1;
unsigned int finalized:1;

/* padding to align to 4 bytes */
unsigned int :24;
} _status;

int py_recursion_remaining;
int py_recursion_limit;
Expand Down Expand Up @@ -245,6 +268,8 @@ struct _ts {
// Alias for backward compatibility with Python 3.8
#define _PyInterpreterState_Get PyInterpreterState_Get

/* An alias for the internal _PyThreadState_New(),
kept for stable ABI compatibility. */
PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *);

/* Similar to PyThreadState_Get(), but don't issue a fatal error
Expand Down
17 changes: 2 additions & 15 deletions Include/internal/pycore_pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,12 @@ static inline PyInterpreterState* _PyInterpreterState_GET(void) {

// PyThreadState functions

PyAPI_FUNC(PyThreadState *) _PyThreadState_New(PyInterpreterState *interp);
PyAPI_FUNC(void) _PyThreadState_Bind(PyThreadState *tstate);
// We keep this around exclusively for stable ABI compatibility.
PyAPI_FUNC(void) _PyThreadState_Init(
PyThreadState *tstate);
PyAPI_FUNC(void) _PyThreadState_DeleteExcept(
_PyRuntimeState *runtime,
PyThreadState *tstate);
PyAPI_FUNC(void) _PyThreadState_DeleteExcept(PyThreadState *tstate);


static inline void
Expand All @@ -139,18 +138,6 @@ _PyThreadState_UpdateTracingState(PyThreadState *tstate)
}


/* PyThreadState status */

#define PyThreadState_UNINITIALIZED 0
/* Has been initialized to a safe state.

In order to be effective, this must be set to 0 during or right
after allocation. */
#define PyThreadState_INITIALIZED 1
#define PyThreadState_BOUND 2
#define PyThreadState_UNBOUND 3


/* Other */

PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap(
Expand Down
2 changes: 1 addition & 1 deletion Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1161,7 +1161,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
return PyErr_NoMemory();
}
boot->interp = _PyInterpreterState_GET();
boot->tstate = _PyThreadState_Prealloc(boot->interp);
boot->tstate = _PyThreadState_New(boot->interp);
if (boot->tstate == NULL) {
PyMem_Free(boot);
if (!PyErr_Occurred()) {
Expand Down
2 changes: 1 addition & 1 deletion Python/ceval_gil.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ _PyEval_ReInitThreads(PyThreadState *tstate)
}

/* Destroy all threads except the current one */
_PyThreadState_DeleteExcept(runtime, tstate);
_PyThreadState_DeleteExcept(tstate);
return _PyStatus_OK();
}
#endif
Expand Down
43 changes: 40 additions & 3 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -696,10 +696,11 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
init_interp_settings(interp, &config);

PyThreadState *tstate = PyThreadState_New(interp);
PyThreadState *tstate = _PyThreadState_New(interp);
if (tstate == NULL) {
return _PyStatus_ERR("can't make first thread");
}
_PyThreadState_Bind(tstate);
(void) PyThreadState_Swap(tstate);

status = init_interp_create_gil(tstate);
Expand Down Expand Up @@ -1821,6 +1822,11 @@ Py_FinalizeEx(void)

/* Get current thread state and interpreter pointer */
PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
// XXX assert(_Py_IsMainInterpreter(tstate->interp));
// XXX assert(_Py_IsMainThread());

// Block some operations.
tstate->interp->finalizing = 1;

// Wrap up existing "threading"-module-created, non-daemon threads.
wait_for_thread_shutdown(tstate);
Expand Down Expand Up @@ -1867,7 +1873,23 @@ Py_FinalizeEx(void)
_PyRuntimeState_SetFinalizing() has been called, no other Python thread
can take the GIL at this point: if they try, they will exit
immediately. */
_PyThreadState_DeleteExcept(runtime, tstate);
_PyThreadState_DeleteExcept(tstate);

/* At this point no Python code should be running at all.
The only thread state left should be the main thread of the main
interpreter (AKA tstate), in which this code is running right now.
There may be other OS threads running but none of them will have
thread states associated with them, nor will be able to create
new thread states.

Thus tstate is the only possible thread state from here on out.
It may still be used during finalization to run Python code as
needed or provide runtime state (e.g. sys.modules) but that will
happen sparingly. Furthermore, the order of finalization aims
to not need a thread (or interpreter) state as soon as possible.
*/
// XXX Make sure we are preventing the creating of any new thread states
// (or interpreters).

/* Flush sys.stdout and sys.stderr */
if (flush_std_files() < 0) {
Expand Down Expand Up @@ -1958,6 +1980,20 @@ Py_FinalizeEx(void)
}
#endif /* Py_TRACE_REFS */

/* At this point there's almost no other Python code that will run,
nor interpreter state needed. The only possibility is the
finalizers of the objects stored on tstate (and tstate->interp),
which are triggered via finalize_interp_clear().

For now we operate as though none of those finalizers actually
need an operational thread state or interpreter. In reality,
those finalizers may rely on some part of tstate or
tstate->interp, and/or may raise exceptions
or otherwise fail.
*/
// XXX Do this sooner during finalization.
// XXX Ensure finalizer errors are handled properly.

finalize_interp_clear(tstate);
finalize_interp_delete(tstate->interp);

Expand Down Expand Up @@ -2039,12 +2075,13 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config)
return _PyStatus_OK();
}

PyThreadState *tstate = PyThreadState_New(interp);
PyThreadState *tstate = _PyThreadState_New(interp);
if (tstate == NULL) {
PyInterpreterState_Delete(interp);
*tstate_p = NULL;
return _PyStatus_OK();
}
_PyThreadState_Bind(tstate);

PyThreadState *save_tstate = PyThreadState_Swap(tstate);

Expand Down
Loading
0