Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: Zac Medico <zmedico@g.o>, gentoo-portage-dev@l.g.o
Subject: [gentoo-portage-dev] Re: [PATCH v3] Use default asyncio event loop implementation in API consumer threads
Date: Sun, 06 Dec 2020 23:15:59
Message-Id: 9763437a-bbf4-c591-73e9-8172e067f077@gentoo.org
In Reply to: [gentoo-portage-dev] [PATCH v3] Use default asyncio event loop implementation in API consumer threads by Zac Medico
1 On 12/6/20 2:14 PM, Zac Medico wrote:
2 > Make the _safe_loop function return an AsyncioEventLoop instance,
3 > so that the default asyncio event loop implementation will be used
4 > in API consumer threads. This is possible because the underlying
5 > asyncio.get_event_loop() function returns a new event loop for
6 > each thread. The AsyncioEventLoop _run_until_complete method will
7 > now appropriately handle a ValueError from signal.set_wakeup_fd(-1)
8 > if it is not called in the main thread.
9 >
10 > Bug: https://bugs.gentoo.org/758755
11 > Signed-off-by: Zac Medico <zmedico@g.o>
12 > ---
13 > [PATCH v3] fixed AsyncioEventLoop _run_until_complete method to
14 > handle ValueError from signal.set_wakeup_fd(-1)
15 >
16 > lib/portage/util/_eventloop/asyncio_event_loop.py | 6 +++++-
17 > lib/portage/util/futures/_asyncio/__init__.py | 3 +--
18 > 2 files changed, 6 insertions(+), 3 deletions(-)
19 >
20 > diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py b/lib/portage/util/_eventloop/asyncio_event_loop.py
21 > index 836f1c30a..4d7047ae8 100644
22 > --- a/lib/portage/util/_eventloop/asyncio_event_loop.py
23 > +++ b/lib/portage/util/_eventloop/asyncio_event_loop.py
24 > @@ -121,4 +121,8 @@ class AsyncioEventLoop(_AbstractEventLoop):
25 > try:
26 > return self._loop.run_until_complete(future)
27 > finally:
28 > - self._wakeup_fd = signal.set_wakeup_fd(-1)
29 > + try:
30 > + self._wakeup_fd = signal.set_wakeup_fd(-1)
31 > + except ValueError:
32 > + # This is intended to fail when not called in the main thread.
33 > + pass
34 > diff --git a/lib/portage/util/futures/_asyncio/__init__.py b/lib/portage/util/futures/_asyncio/__init__.py
35 > index a902ad895..12013be00 100644
36 > --- a/lib/portage/util/futures/_asyncio/__init__.py
37 > +++ b/lib/portage/util/futures/_asyncio/__init__.py
38 > @@ -34,7 +34,6 @@ import portage
39 > portage.proxy.lazyimport.lazyimport(globals(),
40 > 'portage.util.futures.unix_events:_PortageEventLoopPolicy',
41 > 'portage.util.futures:compat_coroutine@_compat_coroutine',
42 > - 'portage.util._eventloop.EventLoop:EventLoop@_EventLoop',
43 > )
44 > from portage.util._eventloop.asyncio_event_loop import AsyncioEventLoop as _AsyncioEventLoop
45 > from portage.util._eventloop.global_event_loop import (
46 > @@ -256,4 +255,4 @@ def _safe_loop():
47 > """
48 > if portage._internal_caller:
49 > return _global_event_loop()
50 > - return _EventLoop(main=False)
51 > + return _AsyncioEventLoop()
52 >
53
54 This fails if an event loop has not been created for the current thread:
55
56 File "/usr/lib/python3.8/asyncio/events.py", line 639, in get_event_loop
57 raise RuntimeError('There is no current event loop in thread %r.'
58 RuntimeError: There is no current event loop in thread 'Thread-1'.
59
60 However, if we automatically instantiate a loop for the current thread
61 then we will be responsible for closing it as well, or else we'll
62 eventually see a ResourceWarning like this:
63
64 /usr/lib/python3.8/asyncio/base_events.py:654: ResourceWarning: unclosed
65 event loop <_UnixSelectorEventLoop running=False closed=False debug=False>
66 _warn(f"unclosed event loop {self!r}", ResourceWarning, source=self)
67 ResourceWarning: Enable tracemalloc to get the object allocation traceback
68
69 So, I think it's probably best if we force the API consumer to manage
70 the lifecycle of an asyncio loop for each thread that it uses to call
71 the portage API.
72 --
73 Thanks,
74 Zac

Attachments

File name MIME type
signature.asc application/pgp-signature