Skip to content
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

Manually calling loop.stop causes deadlock #58

Closed
tjstum opened this issue Jul 3, 2019 · 2 comments
Closed

Manually calling loop.stop causes deadlock #58

tjstum opened this issue Jul 3, 2019 · 2 comments

Comments

@tjstum
Copy link
Member

tjstum commented Jul 3, 2019

Apologies if this is just my fault. Feel free to Won't Fix it if so 😄 I'm toying around with trio-asyncio and had a hard time figuring out what went wrong here.

If you have a toy program like such

import trio
import trio_asyncio

async def setAfterWait(event):
    await trio.sleep(5)
    print('setting')
    event.set()

async def asyncio_loop(event):
    async with trio_asyncio.open_loop() as loop:
        print('in')
        await event.wait()
        loop.stop()
        print('stopped')
    print('dedented')

async def main():
    event = trio.Event()
    async with trio.open_nursery() as nursery:
        nursery.start_soon(setAfterWait, event)
        nursery.start_soon(serve, event)

And you run this, you get print out like:

in
<5 second pause>
setting
stopped

And then the program hangs forever (you can KI it, which is always nice!). However, if you remove the explicit call to loop.stop(), it works as you expect.

in
<5 seconds>
setting
stopped
dedented

I ran into this while trying to debug a more complicated program where a loop.stop() had been added in a misguided attempt to debug a different shutdown issue (forgetting to cancel a nursery that had a bunch of "background" tasks).

@oremanj helped me get a task tree dump, and it looks like trio-asyncio gets stuck here:

[    4] |   |-- task __main__.asyncio_loop:
[    5] |   |   asyncio_loop at __mp_main__:14
[    6] |   |   _AsyncGeneratorContextManager.__aexit__ at async_generator._util:42
[    7] |   |   step at async_generator._impl:366
[    8] |   |   nursery nursery in open_loop at trio_asyncio.async_:108
[     ] |   |   +-- nested child:
[    9] |   |       open_loop at trio_asyncio.async_:123
[   10] |   |       Event.wait at trio._sync:73
[   11] |   |       ParkingLot.park at trio._core._parking_lot:137
[   12] |   |       wait_task_rescheduled at trio._core._traps:166

I'm guessing that what happens is that the __aexit__ is submitting a callback (TrioEventLoop._queue_handle) after the loop has been stopped, so it never actually fires. I definitely messed this up, but I figured I'd write this up in case anyone else runs into it. If there's a reasonable way to fix/document better, I'd be happy to pitch in.

Thanks!

@smurfix
Copy link
Collaborator

smurfix commented Jul 3, 2019

You're right – calling loop.stop yourself is a bad idea in conjunction with trio-asyncio.
I'd appreciate a PR with some text that warns against doing that kind of thing.

tjstum added a commit to tjstum/trio-asyncio that referenced this issue Jul 10, 2019
Calling loop.stop and then immediately proceeding to exit the
`open_loop`'s context (without hitting any checkpoints) causes the
program to hang forever

Fix by reusing the same `waiter` event across multiple calls to `stop`

Fixes python-trio#58
@smurfix
Copy link
Collaborator

smurfix commented Jul 24, 2019

Merged into "next" branch.

@smurfix smurfix closed this as completed Jul 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants