Skip to content

gh-97696 Add documentation for get_coro() behavior with eager tasks #104189

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

Closed
wants to merge 62 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
5c30058
gh-97696 Add documentation for get_coro() behavior with eager tasks
jbower-fb May 5, 2023
248b78b
Update asyncio-task.rst
jbower-fb May 5, 2023
3205457
gh-104190: fix ubsan crash (#104191)
sunmy2019 May 5, 2023
4126669
gh-104051: fix crash in test_xxtestfuzz with -We (#104052)
iritkatriel May 5, 2023
992dead
GH-103092: port `_asyncio` freelist to module state (#104196)
kumaraditya303 May 5, 2023
be60d71
gh-64658: Expand Argument Clinic return converter docs (#104175)
erlend-aasland May 5, 2023
582fe9a
gh-68395: Avoid naming conflicts by mangling variable names in Argume…
erlend-aasland May 5, 2023
78dc058
gh-64631: Test exception messages in cloned Argument Clinic funcs (#1…
erlend-aasland May 5, 2023
d3192a2
gh-64595: Argument Clinic: Touch source file if any output file chang…
erlend-aasland May 5, 2023
5405b60
GH-96803: Add three C-API functions to make _PyInterpreterFrame less …
markshannon May 5, 2023
21fb990
gh-103533: Use PEP 669 APIs for cprofile (GH-103534)
gaogaotiantian May 5, 2023
ef989ab
gh-69152: Add _proxy_response_headers attribute to HTTPConnection (#2…
nametkin May 5, 2023
0b62e96
GH-100479: Add `pathlib.PurePath.with_segments()` (GH-103975)
barneygale May 5, 2023
0826f80
gh-99113: Share the GIL via PyInterpreterState.ceval.gil (gh-104203)
ericsnowcurrently May 5, 2023
efc84cd
gh-104108: Add the Py_mod_multiple_interpreters Module Def Slot (gh-1…
ericsnowcurrently May 5, 2023
7192a46
gh-99113: Add Py_MOD_PER_INTERPRETER_GIL_SUPPORTED (gh-104205)
ericsnowcurrently May 5, 2023
c205faa
gh-104146: Remove unused var 'parser_body_declarations' from clinic.p…
erlend-aasland May 5, 2023
b057233
gh-99113: Add PyInterpreterConfig.own_gil (gh-104204)
ericsnowcurrently May 5, 2023
0b9d0b2
gh-104144: Skip scheduling a done callback if a TaskGroup task comple…
itamaro May 5, 2023
8df75f2
gh-97696: Remove redundant #include (#104216)
jbower-fb May 5, 2023
88482c7
gh-101819: Prepare to modernize the _io extension (#104178)
vstinner May 5, 2023
810e47b
gh-102215: importlib documentation cleanups
yrro May 6, 2023
cf8ee0b
GH-97950: Use new-style index directive ('builtin') (#104164)
AA-Turner May 6, 2023
b2c254d
gh-104233: Fix "unused variable" warning in `ceval_gil.c` (#104234)
sobolevn May 6, 2023
6ab9a42
gh-65772: Clean-up turtle module (#104218)
terryjreedy May 6, 2023
b4f3496
Rewrite the turtledemo makeGraphFrame method (#104224)
terryjreedy May 6, 2023
cb70222
gh-104144: Optimize gather to finish eagerly when all futures complet…
itamaro May 6, 2023
1173ce2
gh-90953: Emit deprecation warnings for `ast` features deprecated in …
AlexWaygood May 6, 2023
a719df1
GH-103548: Improve performance of `pathlib.Path.[is_]absolute()` (GH-…
barneygale May 6, 2023
060a31e
gh-101819: Remove unused 'locale_module' from _io state (#104246)
erlend-aasland May 6, 2023
fc1e63f
gh-99113: Add a check for Py_MOD_PER_INTERPRETER_GIL_SUPPORTED (gh-10…
ericsnowcurrently May 6, 2023
74d38ea
gh-99113: Make Sure the GIL is Acquired at the Right Places (gh-104208)
ericsnowcurrently May 6, 2023
de9f9dd
gh-101640: Make argparse _print_message catch any write error (#101802)
arhadthedev May 6, 2023
fe13226
gh-104254: Document the optional keyword-only "context" argument to T…
itamaro May 7, 2023
33e8bdb
gh-103886: Improve `builtins.__doc__` (#104179)
tomasr8 May 7, 2023
44b081d
gh-97696: Use `PyObject_CallMethodNoArgs` and inline is_loop_running …
itamaro May 7, 2023
06707b9
gh-104018: remove unused format "z" handling in string formatfloat() …
belm0 May 7, 2023
7e11146
Re-enable commented-out test in test_generators.py (#104130)
ymki4360 May 7, 2023
c66f1b6
gh-101819: Port _io.PyIncrementalNewlineDecoder_Type to heap type (#1…
erlend-aasland May 7, 2023
e63898e
gh-101819: Adapt _io.PyWindowsConsoleIO_Type to heap type (#104197)
erlend-aasland May 7, 2023
18babf4
gh-100370: fix OverflowError in sqlite3.Connection.blobopen for 32-bi…
erlend-aasland May 7, 2023
b61f7d2
gh-101819: Port _io.PyBytesIOBuffer_Type to heap type (#104264)
erlend-aasland May 7, 2023
f06a11c
GH-100479: Fix pathlib test failure on WASI (#104215)
barneygale May 7, 2023
86ca8d2
gh-103193: cache calls to `inspect._shadowed_dict` in `inspect.getatt…
AlexWaygood May 7, 2023
c195a2c
gh-104240: make _PyCompile_CodeGen support different compilation mode…
iritkatriel May 7, 2023
3145c0f
GH-89812: Churn `pathlib.Path` methods (GH-104243)
barneygale May 7, 2023
44914e0
gh-103650: Fix perf maps address format (#103651)
art049 May 7, 2023
f6943eb
GH-102613: Improve performance of `pathlib.Path.rglob()` (GH-104244)
barneygale May 7, 2023
8e76e2d
gh-104265 Disallow instantiation of `_csv.Reader` and `_csv.Writer` (…
chgnrdv May 7, 2023
67b4b55
gh-64660: Don't hardcode Argument Clinic return converter result vari…
erlend-aasland May 7, 2023
52539f0
gh-104273: Remove redundant len() calls in argparse function (#104274)
buraksaler May 7, 2023
82a37a4
gh-99108: Replace SHA3 implementation HACL* version (#103597)
msprotz May 8, 2023
2745006
gh-97696: Improve and fix documentation for asyncio eager tasks (#104…
itamaro May 8, 2023
013469f
gh-102500: Remove mention of bytes shorthand (#104281)
hauntsaninja May 8, 2023
ffa4d19
Trim trailing whitespace and test on CI (#104275)
hugovk May 8, 2023
7714382
gh-103193: Improve `getattr_static` test coverage (#104286)
AlexWaygood May 8, 2023
a7e9a63
GH-104145: Use fully-qualified cross reference types for the bisect m…
AA-Turner May 8, 2023
82bc549
gh-99108: fix typo in Modules/Setup (#104293)
msprotz May 8, 2023
b28c5f2
gh-104223: Fix issues with inheriting from buffer classes (#104227)
JelleZijlstra May 8, 2023
a49c8a8
gh-89550: Buffer GzipFile.write to reduce execution time by ~15% (#10…
CCLDArjun May 8, 2023
b8116d8
GH-104284: Fix documentation gettext build (#104296)
AA-Turner May 8, 2023
9a51482
get_coro versionchanged info and cross-reference
jbower-fb May 8, 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
Prev Previous commit
Next Next commit
gh-99113: Make Sure the GIL is Acquired at the Right Places (gh-104208)
This is a pre-requisite for a per-interpreter GIL.  Without it this change isn't strictly necessary.  However, there is no real downside otherwise.
  • Loading branch information
ericsnowcurrently authored and jbower-fb committed May 8, 2023
commit 74d38eaae640eb1b3bc9cc2154bd7aed1c3fce6e
2 changes: 2 additions & 0 deletions Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ extern int _PyEval_ThreadsInitialized(void);
extern PyStatus _PyEval_InitGIL(PyThreadState *tstate, int own_gil);
extern void _PyEval_FiniGIL(PyInterpreterState *interp);

extern void _PyEval_AcquireLock(PyThreadState *tstate);
extern void _PyEval_ReleaseLock(PyThreadState *tstate);
extern PyThreadState * _PyThreadState_SwapNoGIL(PyThreadState *);

extern void _PyEval_DeactivateOpCache(void);

Expand Down
84 changes: 57 additions & 27 deletions Python/ceval_gil.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,42 +499,66 @@ PyEval_ThreadsInitialized(void)
return _PyEval_ThreadsInitialized();
}

static inline int
current_thread_holds_gil(struct _gil_runtime_state *gil, PyThreadState *tstate)
{
if (((PyThreadState*)_Py_atomic_load_relaxed(&gil->last_holder)) != tstate) {
return 0;
}
return _Py_atomic_load_relaxed(&gil->locked);
}

static void
init_shared_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil)
{
assert(gil_created(gil));
interp->ceval.gil = gil;
interp->ceval.own_gil = 0;
}

static void
init_own_gil(PyInterpreterState *interp, struct _gil_runtime_state *gil)
{
assert(!gil_created(gil));
create_gil(gil);
assert(gil_created(gil));
interp->ceval.gil = gil;
interp->ceval.own_gil = 1;
}

PyStatus
_PyEval_InitGIL(PyThreadState *tstate, int own_gil)
{
assert(tstate->interp->ceval.gil == NULL);
int locked;
if (!own_gil) {
PyInterpreterState *main_interp = _PyInterpreterState_Main();
assert(tstate->interp != main_interp);
struct _gil_runtime_state *gil = main_interp->ceval.gil;
assert(gil_created(gil));
tstate->interp->ceval.gil = gil;
tstate->interp->ceval.own_gil = 0;
return _PyStatus_OK();
init_shared_gil(tstate->interp, gil);
locked = current_thread_holds_gil(gil, tstate);
}

/* XXX per-interpreter GIL */
struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil;
if (!_Py_IsMainInterpreter(tstate->interp)) {
else if (!_Py_IsMainInterpreter(tstate->interp)) {
/* Currently, the GIL is shared by all interpreters,
and only the main interpreter is responsible to create
and destroy it. */
assert(gil_created(gil));
tstate->interp->ceval.gil = gil;
struct _gil_runtime_state *main_gil = _PyInterpreterState_Main()->ceval.gil;
init_shared_gil(tstate->interp, main_gil);
// XXX For now we lie.
tstate->interp->ceval.own_gil = 1;
return _PyStatus_OK();
locked = current_thread_holds_gil(main_gil, tstate);
}
else {
PyThread_init_thread();
// XXX per-interpreter GIL: switch to interp->_gil.
init_own_gil(tstate->interp, &tstate->interp->runtime->ceval.gil);
locked = 0;
}
if (!locked) {
take_gil(tstate);
}
assert(own_gil);

assert(!gil_created(gil));

PyThread_init_thread();
create_gil(gil);
assert(gil_created(gil));
tstate->interp->ceval.gil = gil;
tstate->interp->ceval.own_gil = 1;
take_gil(tstate);
return _PyStatus_OK();
}

Expand Down Expand Up @@ -611,9 +635,17 @@ PyEval_ReleaseLock(void)
drop_gil(ceval, tstate);
}

void
_PyEval_AcquireLock(PyThreadState *tstate)
{
_Py_EnsureTstateNotNULL(tstate);
take_gil(tstate);
}

void
_PyEval_ReleaseLock(PyThreadState *tstate)
{
_Py_EnsureTstateNotNULL(tstate);
struct _ceval_state *ceval = &tstate->interp->ceval;
drop_gil(ceval, tstate);
}
Expand All @@ -625,7 +657,7 @@ PyEval_AcquireThread(PyThreadState *tstate)

take_gil(tstate);

if (_PyThreadState_Swap(tstate->interp->runtime, tstate) != NULL) {
if (_PyThreadState_SwapNoGIL(tstate) != NULL) {
Py_FatalError("non-NULL old thread state");
}
}
Expand All @@ -635,8 +667,7 @@ PyEval_ReleaseThread(PyThreadState *tstate)
{
assert(is_tstate_valid(tstate));

_PyRuntimeState *runtime = tstate->interp->runtime;
PyThreadState *new_tstate = _PyThreadState_Swap(runtime, NULL);
PyThreadState *new_tstate = _PyThreadState_SwapNoGIL(NULL);
if (new_tstate != tstate) {
Py_FatalError("wrong thread state");
}
Expand Down Expand Up @@ -684,8 +715,7 @@ _PyEval_SignalAsyncExc(PyInterpreterState *interp)
PyThreadState *
PyEval_SaveThread(void)
{
_PyRuntimeState *runtime = &_PyRuntime;
PyThreadState *tstate = _PyThreadState_Swap(runtime, NULL);
PyThreadState *tstate = _PyThreadState_SwapNoGIL(NULL);
_Py_EnsureTstateNotNULL(tstate);

struct _ceval_state *ceval = &tstate->interp->ceval;
Expand All @@ -701,7 +731,7 @@ PyEval_RestoreThread(PyThreadState *tstate)

take_gil(tstate);

_PyThreadState_Swap(tstate->interp->runtime, tstate);
_PyThreadState_SwapNoGIL(tstate);
}


Expand Down Expand Up @@ -1005,7 +1035,7 @@ _Py_HandlePending(PyThreadState *tstate)
/* GIL drop request */
if (_Py_atomic_load_relaxed_int32(&interp_ceval_state->gil_drop_request)) {
/* Give another thread a chance */
if (_PyThreadState_Swap(runtime, NULL) != tstate) {
if (_PyThreadState_SwapNoGIL(NULL) != tstate) {
Py_FatalError("tstate mix-up");
}
drop_gil(interp_ceval_state, tstate);
Expand All @@ -1014,7 +1044,7 @@ _Py_HandlePending(PyThreadState *tstate)

take_gil(tstate);

if (_PyThreadState_Swap(runtime, tstate) != NULL) {
if (_PyThreadState_SwapNoGIL(tstate) != NULL) {
Py_FatalError("orphan tstate");
}
}
Expand Down
25 changes: 22 additions & 3 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ init_interp_create_gil(PyThreadState *tstate, int own_gil)

/* finalize_interp_delete() comment explains why _PyEval_FiniGIL() is
only called here. */
// XXX This is broken with a per-interpreter GIL.
_PyEval_FiniGIL(tstate->interp);

/* Auto-thread-state API */
Expand Down Expand Up @@ -645,7 +646,8 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
return _PyStatus_ERR("can't make first thread");
}
_PyThreadState_Bind(tstate);
(void) PyThreadState_Swap(tstate);
// XXX For now we do this before the GIL is created.
(void) _PyThreadState_SwapNoGIL(tstate);

status = init_interp_create_gil(tstate, config.own_gil);
if (_PyStatus_EXCEPTION(status)) {
Expand Down Expand Up @@ -2025,11 +2027,20 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
}
_PyThreadState_Bind(tstate);

PyThreadState *save_tstate = PyThreadState_Swap(tstate);
// XXX For now we do this before the GIL is created.
PyThreadState *save_tstate = _PyThreadState_SwapNoGIL(tstate);
int has_gil = 0;

/* From this point until the init_interp_create_gil() call,
we must not do anything that requires that the GIL be held
(or otherwise exist). That applies whether or not the new
interpreter has its own GIL (e.g. the main interpreter). */

/* Copy the current interpreter config into the new interpreter */
const PyConfig *src_config;
if (save_tstate != NULL) {
// XXX Might new_interpreter() have been called without the GIL held?
_PyEval_ReleaseLock(save_tstate);
src_config = _PyInterpreterState_GetConfig(save_tstate->interp);
}
else
Expand All @@ -2039,11 +2050,13 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
src_config = _PyInterpreterState_GetConfig(main_interp);
}

/* This does not require that the GIL be held. */
status = _PyConfig_Copy(&interp->config, src_config);
if (_PyStatus_EXCEPTION(status)) {
goto error;
}

/* This does not require that the GIL be held. */
status = init_interp_settings(interp, config);
if (_PyStatus_EXCEPTION(status)) {
goto error;
Expand All @@ -2053,6 +2066,7 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)
if (_PyStatus_EXCEPTION(status)) {
goto error;
}
has_gil = 1;

status = pycore_interp_init(tstate);
if (_PyStatus_EXCEPTION(status)) {
Expand All @@ -2072,7 +2086,12 @@ new_interpreter(PyThreadState **tstate_p, const PyInterpreterConfig *config)

/* Oops, it didn't work. Undo it all. */
PyErr_PrintEx(0);
PyThreadState_Swap(save_tstate);
if (has_gil) {
PyThreadState_Swap(save_tstate);
}
else {
_PyThreadState_SwapNoGIL(save_tstate);
}
PyThreadState_Clear(tstate);
PyThreadState_Delete(tstate);
PyInterpreterState_Delete(interp);
Expand Down
42 changes: 32 additions & 10 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1863,17 +1863,11 @@ PyThreadState_Get(void)
}


PyThreadState *
_PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts)
static void
_swap_thread_states(_PyRuntimeState *runtime,
PyThreadState *oldts, PyThreadState *newts)
{
#if defined(Py_DEBUG)
/* This can be called from PyEval_RestoreThread(). Similar
to it, we need to ensure errno doesn't change.
*/
int err = errno;
#endif
PyThreadState *oldts = current_fast_get(runtime);

// XXX Do this only if oldts != NULL?
current_fast_clear(runtime);

if (oldts != NULL) {
Expand All @@ -1887,13 +1881,41 @@ _PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts)
current_fast_set(runtime, newts);
tstate_activate(newts);
}
}

PyThreadState *
_PyThreadState_SwapNoGIL(PyThreadState *newts)
{
#if defined(Py_DEBUG)
/* This can be called from PyEval_RestoreThread(). Similar
to it, we need to ensure errno doesn't change.
*/
int err = errno;
#endif

PyThreadState *oldts = current_fast_get(&_PyRuntime);
_swap_thread_states(&_PyRuntime, oldts, newts);

#if defined(Py_DEBUG)
errno = err;
#endif
return oldts;
}

PyThreadState *
_PyThreadState_Swap(_PyRuntimeState *runtime, PyThreadState *newts)
{
PyThreadState *oldts = current_fast_get(runtime);
if (oldts != NULL) {
_PyEval_ReleaseLock(oldts);
}
_swap_thread_states(runtime, oldts, newts);
if (newts != NULL) {
_PyEval_AcquireLock(newts);
}
return oldts;
}

PyThreadState *
PyThreadState_Swap(PyThreadState *newts)
{
Expand Down