1 |
Use a child watcher wrapper to deliver the callbacks via the |
2 |
call_soon_threadsafe method, since documentation for the asycio |
3 |
AbstractChildWatcher class says that callbacks must be thread |
4 |
safe. |
5 |
|
6 |
Bug: https://bugs.gentoo.org/764905 |
7 |
Signed-off-by: Zac Medico <zmedico@g.o> |
8 |
--- |
9 |
.../util/_eventloop/asyncio_event_loop.py | 30 ++++++++++++++++++- |
10 |
1 file changed, 29 insertions(+), 1 deletion(-) |
11 |
|
12 |
diff --git a/lib/portage/util/_eventloop/asyncio_event_loop.py b/lib/portage/util/_eventloop/asyncio_event_loop.py |
13 |
index 4d7047ae8..b77728088 100644 |
14 |
--- a/lib/portage/util/_eventloop/asyncio_event_loop.py |
15 |
+++ b/lib/portage/util/_eventloop/asyncio_event_loop.py |
16 |
@@ -6,6 +6,7 @@ import signal |
17 |
|
18 |
import asyncio as _real_asyncio |
19 |
from asyncio.events import AbstractEventLoop as _AbstractEventLoop |
20 |
+from asyncio.unix_events import AbstractChildWatcher as _AbstractChildWatcher |
21 |
|
22 |
import portage |
23 |
|
24 |
@@ -47,6 +48,7 @@ class AsyncioEventLoop(_AbstractEventLoop): |
25 |
self.set_debug = loop.set_debug |
26 |
self.get_debug = loop.get_debug |
27 |
self._wakeup_fd = -1 |
28 |
+ self._child_watcher = None |
29 |
|
30 |
if portage._internal_caller: |
31 |
loop.set_exception_handler(self._internal_caller_exception_handler) |
32 |
@@ -87,7 +89,9 @@ class AsyncioEventLoop(_AbstractEventLoop): |
33 |
@rtype: asyncio.AbstractChildWatcher |
34 |
@return: the internal event loop's AbstractChildWatcher interface |
35 |
""" |
36 |
- return _real_asyncio.get_child_watcher() |
37 |
+ if self._child_watcher is None: |
38 |
+ self._child_watcher = _ChildWatcherThreadSafetyWrapper(self, _real_asyncio.get_child_watcher()) |
39 |
+ return self._child_watcher |
40 |
|
41 |
@property |
42 |
def _asyncio_wrapper(self): |
43 |
@@ -126,3 +130,27 @@ class AsyncioEventLoop(_AbstractEventLoop): |
44 |
except ValueError: |
45 |
# This is intended to fail when not called in the main thread. |
46 |
pass |
47 |
+ |
48 |
+ |
49 |
+class _ChildWatcherThreadSafetyWrapper(_AbstractChildWatcher): |
50 |
+ def __init__(self, loop, real_watcher): |
51 |
+ self._loop = loop |
52 |
+ self._real_watcher = real_watcher |
53 |
+ |
54 |
+ def close(self): |
55 |
+ pass |
56 |
+ |
57 |
+ def __enter__(self): |
58 |
+ return self |
59 |
+ |
60 |
+ def __exit__(self, a, b, c): |
61 |
+ pass |
62 |
+ |
63 |
+ def _child_exit(self, pid, status, callback, *args): |
64 |
+ self._loop.call_soon_threadsafe(callback, pid, status, *args) |
65 |
+ |
66 |
+ def add_child_handler(self, pid, callback, *args): |
67 |
+ self._real_watcher.add_child_handler(pid, self._child_exit, callback, *args) |
68 |
+ |
69 |
+ def remove_child_handler(self, pid): |
70 |
+ return self._real_watcher.remove_child_handler(pid) |
71 |
-- |
72 |
2.26.2 |