commit: b530e4e67b843837093e545cf81fd4ab8336d2c2 Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Sun Apr 29 21:09:59 2018 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Sun Apr 29 21:26:37 2018 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=b530e4e6
SubProcess: add_child_handler asyncio compat (bug 654276) Migrate to asyncio's AbstractChildWatcher.add_child_handler interface. Re-use PopenProcess code introduced in commit be800bf0153a28ce034277d103a2021f93ac8b2e. Also remove the child_watch_add method from SchedulerInterface, since there are no more consumers. Bug: https://bugs.gentoo.org/654276 pym/_emerge/SubProcess.py | 58 ++++----------------------- pym/portage/util/_async/PopenProcess.py | 20 ++------- pym/portage/util/_async/SchedulerInterface.py | 1 - 3 files changed, 11 insertions(+), 68 deletions(-) diff --git a/pym/_emerge/SubProcess.py b/pym/_emerge/SubProcess.py index 3939de3ed..aa4778737 100644 --- a/pym/_emerge/SubProcess.py +++ b/pym/_emerge/SubProcess.py @@ -19,28 +19,7 @@ class SubProcess(AbstractPollTask): _cancel_timeout = 1000 # 1 second def _poll(self): - if self.returncode is not None: - return self.returncode - if self.pid is None: - return self.returncode - if self._registered: - return self.returncode - - try: - # With waitpid and WNOHANG, only check the - # first element of the tuple since the second - # element may vary (bug #337465). - retval = os.waitpid(self.pid, os.WNOHANG) - except OSError as e: - if e.errno != errno.ECHILD: - raise - del e - retval = (self.pid, 1) - - if retval[0] == 0: - return None - self._set_returncode(retval) - self._async_wait() + # Simply rely on _async_waitpid_cb to set the returncode. return self.returncode def _cancel(self): @@ -71,20 +50,16 @@ class SubProcess(AbstractPollTask): 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) + self._waitpid_id = self.pid + self.scheduler._asyncio_child_watcher.\ + add_child_handler(self.pid, self._async_waitpid_cb) - def _async_waitpid_cb(self, pid, condition, user_data=None): + def _async_waitpid_cb(self, pid, returncode): if pid != self.pid: raise AssertionError("expected pid %s, got %s" % (self.pid, pid)) - self._set_returncode((pid, condition)) + self.returncode = returncode self._async_wait() - def _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)) - def _orphan_process_warn(self): pass @@ -100,7 +75,8 @@ class SubProcess(AbstractPollTask): self._reg_id = None if self._waitpid_id is not None: - self.scheduler.source_remove(self._waitpid_id) + self.scheduler._asyncio_child_watcher.\ + remove_child_handler(self._waitpid_id) self._waitpid_id = None if self._files is not None: @@ -126,21 +102,3 @@ class SubProcess(AbstractPollTask): 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 - subprocess.Popen.returncode: A negative value -N indicates - that the child was terminated by signal N (Unix only). - """ - self._unregister() - - pid, status = wait_retval - - if os.WIFSIGNALED(status): - retval = - os.WTERMSIG(status) - else: - retval = os.WEXITSTATUS(status) - - self.returncode = retval - diff --git a/pym/portage/util/_async/PopenProcess.py b/pym/portage/util/_async/PopenProcess.py index 3fb60d527..c1931327a 100644 --- a/pym/portage/util/_async/PopenProcess.py +++ b/pym/portage/util/_async/PopenProcess.py @@ -25,23 +25,9 @@ class PopenProcess(SubProcess): def _pipe_reader_exit(self, pipe_reader): self._async_waitpid() - def _async_waitpid(self): - if self.returncode is None: - self.scheduler._asyncio_child_watcher.\ - add_child_handler(self.pid, self._async_waitpid_cb) - else: - self._unregister() - self._async_wait() - - def _async_waitpid_cb(self, pid, returncode): + def _async_waitpid_cb(self, *args, **kwargs): + SubProcess._async_waitpid_cb(self, *args, **kwargs) if self.proc.returncode is None: # Suppress warning messages like this: # ResourceWarning: subprocess 1234 is still running - self.proc.returncode = returncode - self._unregister() - self.returncode = returncode - self._async_wait() - - def _poll(self): - # Simply rely on _async_waitpid_cb to set the returncode. - return self.returncode + self.proc.returncode = self.returncode diff --git a/pym/portage/util/_async/SchedulerInterface.py b/pym/portage/util/_async/SchedulerInterface.py index be118ae0e..ff39bc587 100644 --- a/pym/portage/util/_async/SchedulerInterface.py +++ b/pym/portage/util/_async/SchedulerInterface.py @@ -13,7 +13,6 @@ class SchedulerInterface(SlotObject): _event_loop_attrs = ("IO_ERR", "IO_HUP", "IO_IN", "IO_NVAL", "IO_OUT", "IO_PRI", - "child_watch_add", "io_add_watch", "source_remove", "timeout_add",