Skip to content

gh-121621: Move asyncio running loop to thread state - #121695

Merged
Fidget-Spinner merged 21 commits into
python:mainfrom
Fidget-Spinner:asyncio_rest_threadsafe
Jul 16, 2024
Merged

gh-121621: Move asyncio running loop to thread state#121695
Fidget-Spinner merged 21 commits into
python:mainfrom
Fidget-Spinner:asyncio_rest_threadsafe

Conversation

@Fidget-Spinner

@Fidget-SpinnerFidget-Spinner commented Jul 13, 2024

Copy link
Copy Markdown
Member

Comment threadInclude/internal/pycore_freelist.h Outdated
@ericsnowcurrently

Copy link
Copy Markdown
Member

CC @markshannon

@colesburycolesbury left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be worthwhile to split this up into two PRs:

  • The running loop change, which should be small and relatively straightforward
  • The freelist change, which I think needs more work to avoid duplicating struct definitions

Comment threadInclude/cpython/pystate.h Outdated
Comment threadModules/_asynciomodule.c Outdated
Comment threadModules/_asynciomodule.c Outdated

// Visit freelist.
PyObject *next = (PyObject*) state->fi_freelist;
#ifdef WITH_FREELISTS

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem right. We don't visit freelists anywhere else. The objects in the freelist should never be tracked by the GC.

Comment threadInclude/internal/pycore_freelist.h Outdated
extern void _PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization);

// Keep in sync with _asynciomodule.c !
typedef struct futureiterobject_dummy {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to avoid this sort of duplication if at all possible.

@Fidget-SpinnerFidget-Spinner changed the title gh-121621: Move asyncio freelist to thread stategh-121621: Move asyncio running loop to thread stateJul 15, 2024

@colesburycolesbury left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions:

I think the get_running_loop and set_running_loop are more confusing than helpful at this point. For example, there's a bunch of dead code now to access the module state. I think the code will be easier to read if they are inlined into their callsites.

I think the code will be more robust if the loop field on PyThreadState uses NULL instead of Py_None (i.e., handle the conversion to Py_None in the call sites as necessary). PyThreadState_Clear() still sets the field to NULL, which breaks the non-NULL invariant -- PyThreadState_Clear can still execute Python code via finalizers.

Comment threadInclude/cpython/pystate.h Outdated
@Fidget-Spinner

Copy link
Copy Markdown
MemberAuthor

A few suggestions:

I think the get_running_loop and set_running_loop are more confusing than helpful at this point. For example, there's a bunch of dead code now to access the module state. I think the code will be easier to read if they are inlined into their callsites.

I think the code will be more robust if the loop field on PyThreadState uses NULL instead of Py_None (i.e., handle the conversion to Py_None in the call sites as necessary). PyThreadState_Clear() still sets the field to NULL, which breaks the non-NULL invariant -- PyThreadState_Clear can still execute Python code via finalizers.

I agree with the first suggestion.

The second suggestion has one problem --- we'd still need to special case Py_None because the asyncio spec says if the event loop is None, it will raise a RuntimeError. So we'd need an extra branch checking for NULL and converting to Py_None, AND a branch checking if it's non-null but Py_None. That's not clean IMO.

I'd prefer we just set it to Py_None in PyThreadState_Clear to keep the invariant that there are only two states: Py_None and not-none.

Comment threadModules/_asynciomodule.c Outdated
Comment threadInclude/cpython/pystate.h Outdated

@colesburycolesbury left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM. I left a few minor style comments.

...we'd still need to special case Py_None because the asyncio spec says if the event loop is None, it will raise a RuntimeError.

This is a common pattern in CPython. We normalize Py_None to NULL in the setter. For example, _asyncio__set_running_loop would look like:

PyThreadState*ts=_PyThreadState_GET();
if (loop==Py_None) {
loop=NULL;
}
Py_XSETREF(ts->asyncio_running_loop, Py_XNewRef(loop));

For example, see:

if (value==Py_None)
value=NULL;

This is a much more common pattern than setting the field to Py_None in the clear function.

Comment threadModules/_asynciomodule.c Outdated
Comment threadModules/_asynciomodule.c Outdated
Comment threadModules/_asynciomodule.c Outdated
@Fidget-Spinner
Fidget-Spinner merged commit 69c68de into python:mainJul 16, 2024
@Fidget-SpinnerFidget-Spinner added the needs backport to 3.13 bugs and security fixes label Jul 16, 2024
@miss-islington-app

Copy link
Copy Markdown

Thanks @Fidget-Spinner for the PR 🌮🎉.. I'm working now to backport this PR to: 3.13.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jul 16, 2024
…121695)
(cherry picked from commit 69c68de)
Co-authored-by: Ken Jin <kenjin@python.org>
@bedevere-app

Copy link
Copy Markdown

GH-121864 is a backport of this pull request to the 3.13 branch.

@bedevere-appbedevere-appBot removed the needs backport to 3.13 bugs and security fixes label Jul 16, 2024
@Fidget-Spinner
Fidget-Spinner deleted the asyncio_rest_threadsafe branch July 16, 2024 17:10
Fidget-Spinner added a commit that referenced this pull request Jul 16, 2024
… (GH-121864)
gh-121621: Move asyncio running loop to thread state (GH-121695)
(cherry picked from commit 69c68de)
Co-authored-by: Ken Jin <kenjin@python.org>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@Fidget-Spinner@ericsnowcurrently@colesbury@kumaraditya303