On Sun, 26 Mar 2017 23:54:37 -0700
Zac Medico <zmed...@gentoo.org> wrote:

> Fix SpawnProcess._pipe_logger_exit to wait for process exit status
> asynchronously, in order to avoid event loop recursion. This is
> required for asyncio compatibility, and also protects emerge from
> exceeding the maximum recursion depth limit like in bug 402335.
> 
> X-Gentoo-bug: 613990
> X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=613990
> ---
>  pym/_emerge/SpawnProcess.py |  3 +--
>  pym/_emerge/SubProcess.py   | 23 ++++++++++++++++++++++-
>  2 files changed, 23 insertions(+), 3 deletions(-)
> 
> diff --git a/pym/_emerge/SpawnProcess.py b/pym/_emerge/SpawnProcess.py
> index e046640..7326254 100644
> --- a/pym/_emerge/SpawnProcess.py
> +++ b/pym/_emerge/SpawnProcess.py
> @@ -170,8 +170,7 @@ class SpawnProcess(SubProcess):
>  
>       def _pipe_logger_exit(self, pipe_logger):
>               self._pipe_logger = None
> -             self._unregister()
> -             self.wait()
> +             self._async_waitpid()
>  
>       def _waitpid_loop(self):
>               SubProcess._waitpid_loop(self)
> diff --git a/pym/_emerge/SubProcess.py b/pym/_emerge/SubProcess.py
> index 13d9382..b81cfd5 100644
> --- a/pym/_emerge/SubProcess.py
> +++ b/pym/_emerge/SubProcess.py
> @@ -12,7 +12,7 @@ import errno
>  class SubProcess(AbstractPollTask):
>  
>       __slots__ = ("pid",) + \
> -             ("_dummy_pipe_fd", "_files", "_reg_id")
> +             ("_dummy_pipe_fd", "_files", "_reg_id",
> "_waitpid_id") 
>       # This is how much time we allow for waitpid to succeed after
>       # we've sent a kill signal to our subprocess.
> @@ -101,6 +101,23 @@ class SubProcess(AbstractPollTask):
>  
>               return self.returncode
>  
> +     def _async_waitpid(self):
> +             """
> +             Wait for exit status of self.pid asynchronously, and
> then
> +             set the returncode and notify exit listeners. This is
> +             prefered over _waitpid_loop, since the synchronous
> nature
> +             of _waitpid_loop can cause event loop recursion.
> +             """
> +             if self._waitpid_id is None:
> +                     self._waitpid_id =
> self.scheduler.child_watch_add(
> +                             self.pid, self._async_waitpid_cb)
> +
> +     def _async_waitpid_cb(self, pid, condition, user_data=None):
> +             if pid != self.pid:
> +                     raise AssertionError("expected pid %s, got
> %s" % (self.pid, pid))
> +             self._set_returncode((pid, condition))
> +             self.wait()
> +
>       def _waitpid_loop(self):
>               source_id = self.scheduler.child_watch_add(
>                       self.pid, self._waitpid_cb)
> @@ -129,6 +146,10 @@ class SubProcess(AbstractPollTask):
>                       self.scheduler.source_remove(self._reg_id)
>                       self._reg_id = None
>  
> +             if self._waitpid_id is not None:
> +
> self.scheduler.source_remove(self._waitpid_id)
> +                     self._waitpid_id = None
> +
>               if self._files is not None:
>                       for f in self._files.values():
>                               if isinstance(f, int):

looks fine

-- 
Brian Dolbec <dolsen>


Reply via email to