Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] SpawnProcess: fix event loop recursion in _pipe_logger_exit (bug 613990)
Date: Mon, 27 Mar 2017 06:58:10
Message-Id: 20170327065437.15628-1-zmedico@gentoo.org
1 Fix SpawnProcess._pipe_logger_exit to wait for process exit status
2 asynchronously, in order to avoid event loop recursion. This is
3 required for asyncio compatibility, and also protects emerge from
4 exceeding the maximum recursion depth limit like in bug 402335.
5
6 X-Gentoo-bug: 613990
7 X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=613990
8 ---
9 pym/_emerge/SpawnProcess.py | 3 +--
10 pym/_emerge/SubProcess.py | 23 ++++++++++++++++++++++-
11 2 files changed, 23 insertions(+), 3 deletions(-)
12
13 diff --git a/pym/_emerge/SpawnProcess.py b/pym/_emerge/SpawnProcess.py
14 index e046640..7326254 100644
15 --- a/pym/_emerge/SpawnProcess.py
16 +++ b/pym/_emerge/SpawnProcess.py
17 @@ -170,8 +170,7 @@ class SpawnProcess(SubProcess):
18
19 def _pipe_logger_exit(self, pipe_logger):
20 self._pipe_logger = None
21 - self._unregister()
22 - self.wait()
23 + self._async_waitpid()
24
25 def _waitpid_loop(self):
26 SubProcess._waitpid_loop(self)
27 diff --git a/pym/_emerge/SubProcess.py b/pym/_emerge/SubProcess.py
28 index 13d9382..b81cfd5 100644
29 --- a/pym/_emerge/SubProcess.py
30 +++ b/pym/_emerge/SubProcess.py
31 @@ -12,7 +12,7 @@ import errno
32 class SubProcess(AbstractPollTask):
33
34 __slots__ = ("pid",) + \
35 - ("_dummy_pipe_fd", "_files", "_reg_id")
36 + ("_dummy_pipe_fd", "_files", "_reg_id", "_waitpid_id")
37
38 # This is how much time we allow for waitpid to succeed after
39 # we've sent a kill signal to our subprocess.
40 @@ -101,6 +101,23 @@ class SubProcess(AbstractPollTask):
41
42 return self.returncode
43
44 + def _async_waitpid(self):
45 + """
46 + Wait for exit status of self.pid asynchronously, and then
47 + set the returncode and notify exit listeners. This is
48 + prefered over _waitpid_loop, since the synchronous nature
49 + of _waitpid_loop can cause event loop recursion.
50 + """
51 + if self._waitpid_id is None:
52 + self._waitpid_id = self.scheduler.child_watch_add(
53 + self.pid, self._async_waitpid_cb)
54 +
55 + def _async_waitpid_cb(self, pid, condition, user_data=None):
56 + if pid != self.pid:
57 + raise AssertionError("expected pid %s, got %s" % (self.pid, pid))
58 + self._set_returncode((pid, condition))
59 + self.wait()
60 +
61 def _waitpid_loop(self):
62 source_id = self.scheduler.child_watch_add(
63 self.pid, self._waitpid_cb)
64 @@ -129,6 +146,10 @@ class SubProcess(AbstractPollTask):
65 self.scheduler.source_remove(self._reg_id)
66 self._reg_id = None
67
68 + if self._waitpid_id is not None:
69 + self.scheduler.source_remove(self._waitpid_id)
70 + self._waitpid_id = None
71 +
72 if self._files is not None:
73 for f in self._files.values():
74 if isinstance(f, int):
75 --
76 2.10.2

Replies