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

Attachments

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