1 |
Make the wait() and _async_wait() methods raise InvalidStateError |
2 |
when the event loop is running and the returncode is not available, |
3 |
since these cases would trigger event loop recursion. There are no |
4 |
known remaining cases that cause event loop recursion via wait() |
5 |
and _async_wait(), and this patch protects against changes that would |
6 |
accidentally re-introduce event loop recursion. |
7 |
|
8 |
Since the wait() method now raises InvalidStateError in cases where |
9 |
it previously would have called the _wait() method, this patch makes |
10 |
it possible to remove the _wait() method implementations from all |
11 |
subclasses of AsynchronousTask. |
12 |
|
13 |
Bug: https://bugs.gentoo.org/653856 |
14 |
--- |
15 |
pym/_emerge/AbstractEbuildProcess.py | 3 +++ |
16 |
pym/_emerge/AsynchronousTask.py | 15 +++++++-------- |
17 |
2 files changed, 10 insertions(+), 8 deletions(-) |
18 |
|
19 |
diff --git a/pym/_emerge/AbstractEbuildProcess.py b/pym/_emerge/AbstractEbuildProcess.py |
20 |
index d481e6046..606c909e8 100644 |
21 |
--- a/pym/_emerge/AbstractEbuildProcess.py |
22 |
+++ b/pym/_emerge/AbstractEbuildProcess.py |
23 |
@@ -18,6 +18,7 @@ from portage.localization import _ |
24 |
from portage.package.ebuild._ipc.ExitCommand import ExitCommand |
25 |
from portage.package.ebuild._ipc.QueryCommand import QueryCommand |
26 |
from portage import shutil, os |
27 |
+from portage.util.futures import asyncio |
28 |
from portage.util._pty import _create_pty_or_pipe |
29 |
from portage.util import apply_secpass_permissions |
30 |
|
31 |
@@ -420,6 +421,8 @@ class AbstractEbuildProcess(SpawnProcess): |
32 |
if self._build_dir is None: |
33 |
SpawnProcess._async_wait(self) |
34 |
elif self._build_dir_unlock is None: |
35 |
+ if self.returncode is None: |
36 |
+ raise asyncio.InvalidStateError('Result is not ready.') |
37 |
self._async_unlock_builddir(returncode=self.returncode) |
38 |
|
39 |
def _async_unlock_builddir(self, returncode=None): |
40 |
diff --git a/pym/_emerge/AsynchronousTask.py b/pym/_emerge/AsynchronousTask.py |
41 |
index 7d2e6253b..5cc6d3b7d 100644 |
42 |
--- a/pym/_emerge/AsynchronousTask.py |
43 |
+++ b/pym/_emerge/AsynchronousTask.py |
44 |
@@ -4,6 +4,7 @@ |
45 |
import signal |
46 |
|
47 |
from portage import os |
48 |
+from portage.util.futures import asyncio |
49 |
from portage.util.SlotObject import SlotObject |
50 |
|
51 |
class AsynchronousTask(SlotObject): |
52 |
@@ -17,8 +18,7 @@ class AsynchronousTask(SlotObject): |
53 |
""" |
54 |
|
55 |
__slots__ = ("background", "cancelled", "returncode", "scheduler") + \ |
56 |
- ("_exit_listeners", "_exit_listener_stack", "_start_listeners", |
57 |
- "_waiting") |
58 |
+ ("_exit_listeners", "_exit_listener_stack", "_start_listeners") |
59 |
|
60 |
_cancelled_returncode = - signal.SIGINT |
61 |
|
62 |
@@ -71,12 +71,9 @@ class AsynchronousTask(SlotObject): |
63 |
Deprecated. Use async_wait() instead. |
64 |
""" |
65 |
if self.returncode is None: |
66 |
- if not self._waiting: |
67 |
- self._waiting = True |
68 |
- try: |
69 |
- self._wait() |
70 |
- finally: |
71 |
- self._waiting = False |
72 |
+ if self.scheduler.is_running(): |
73 |
+ raise asyncio.InvalidStateError('Result is not ready.') |
74 |
+ self.scheduler.run_until_complete(self.async_wait()) |
75 |
self._wait_hook() |
76 |
return self.returncode |
77 |
|
78 |
@@ -91,6 +88,8 @@ class AsynchronousTask(SlotObject): |
79 |
loop recursion (or stack overflow) that synchronous calling of |
80 |
exit listeners can cause. This method is thread-safe. |
81 |
""" |
82 |
+ if self.returncode is None: |
83 |
+ raise asyncio.InvalidStateError('Result is not ready.') |
84 |
self.scheduler.idle_add(self._async_wait_cb) |
85 |
|
86 |
def _async_wait_cb(self): |
87 |
-- |
88 |
2.13.6 |