commit:     c5ab0696cec1f0f020d2d8ad416f9b1444a467de
Author:     Zac Medico <zmedico <AT> gentoo <DOT> org>
AuthorDate: Sun Apr 22 18:16:55 2018 +0000
Commit:     Zac Medico <zmedico <AT> gentoo <DOT> org>
CommitDate: Sun Apr 22 18:16:55 2018 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=c5ab0696

SubProcess: fix _unregister_if_appropriate event loop recursion (bug 614104)

Override the AbstractPollTask._unregister_if_appropriate method to avoid
event loop recursion when the pid exit status is not yet available, by
calling self._async_waitpid() instead of self.wait(). Also make
_async_waitpid fallback to _async_wait if the pid exit status happens to
be available already.

Bug: https://bugs.gentoo.org/614104

 pym/_emerge/SubProcess.py | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/pym/_emerge/SubProcess.py b/pym/_emerge/SubProcess.py
index 141181d9f..f684c5a22 100644
--- a/pym/_emerge/SubProcess.py
+++ b/pym/_emerge/SubProcess.py
@@ -108,7 +108,9 @@ class SubProcess(AbstractPollTask):
                prefered over _waitpid_loop, since the synchronous nature
                of _waitpid_loop can cause event loop recursion.
                """
-               if self._waitpid_id is None:
+               if self.returncode is not None:
+                       self._async_wait()
+               elif self._waitpid_id is None:
                        self._waitpid_id = self.scheduler.child_watch_add(
                                self.pid, self._async_waitpid_cb)
 
@@ -158,6 +160,22 @@ class SubProcess(AbstractPollTask):
                                        f.close()
                        self._files = None
 
+       def _unregister_if_appropriate(self, event):
+               """
+               Override the AbstractPollTask._unregister_if_appropriate method 
to
+               call _async_waitpid instead of wait(), so that event loop 
recursion
+               is not triggered when the pid exit status is not yet available.
+               """
+               if self._registered:
+                       if event & self._exceptional_events:
+                               self._log_poll_exception(event)
+                               self._unregister()
+                               self.cancel()
+                               self._async_waitpid()
+                       elif event & self.scheduler.IO_HUP:
+                               self._unregister()
+                               self._async_waitpid()
+
        def _set_returncode(self, wait_retval):
                """
                Set the returncode in a manner compatible with

Reply via email to