Gentoo Archives: gentoo-portage-dev

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

Replies