From 445a6ea22c132f4c06c2cc7c48ec6e7af7116962 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Mon, 6 Feb 2012 18:58:51 -0800 Subject: Use timeout_add to avoid recursion, bug #402335. --- pym/_emerge/AbstractEbuildProcess.py | 37 ++++++++++++++++++++++++++++-------- pym/_emerge/SubProcess.py | 6 +++++- 2 files changed, 34 insertions(+), 9 deletions(-) (limited to 'pym') diff --git a/pym/_emerge/AbstractEbuildProcess.py b/pym/_emerge/AbstractEbuildProcess.py index 63368d4af..5742cb2a7 100644 --- a/pym/_emerge/AbstractEbuildProcess.py +++ b/pym/_emerge/AbstractEbuildProcess.py @@ -19,7 +19,7 @@ from portage.util import apply_secpass_permissions class AbstractEbuildProcess(SpawnProcess): __slots__ = ('phase', 'settings',) + \ - ('_build_dir', '_ipc_daemon', '_exit_command',) + ('_build_dir', '_ipc_daemon', '_exit_command', '_exit_timeout_id') _phases_without_builddir = ('clean', 'cleanrm', 'depend', 'help',) _phases_interactive_whitelist = ('config',) @@ -157,13 +157,30 @@ class AbstractEbuildProcess(SpawnProcess): def _exit_command_callback(self): if self._registered: # Let the process exit naturally, if possible. - self.scheduler.schedule(self._reg_id, timeout=self._exit_timeout) - if self._registered: - # If it doesn't exit naturally in a reasonable amount - # of time, kill it (solves bug #278895). We try to avoid - # this when possible since it makes sandbox complain about - # being killed by a signal. - self.cancel() + self._exit_timeout_id = \ + self.scheduler.timeout_add(self._exit_timeout, + self._exit_command_timeout_cb) + + def _exit_command_timeout_cb(self): + if self._registered: + # If it doesn't exit naturally in a reasonable amount + # of time, kill it (solves bug #278895). We try to avoid + # this when possible since it makes sandbox complain about + # being killed by a signal. + self.cancelled = True + self._cancel() + self._exit_timeout_id = \ + self.scheduler.timeout_add(self._cancel_timeout, + self._cancel_timeout_cb) + else: + self._exit_timeout_id = None + + return False # only run once + + def _cancel_timeout_cb(self): + self._exit_timeout_id = None + self.wait() + return False # only run once def _orphan_process_warn(self): phase = self.phase @@ -253,6 +270,10 @@ class AbstractEbuildProcess(SpawnProcess): def _set_returncode(self, wait_retval): SpawnProcess._set_returncode(self, wait_retval) + if self._exit_timeout_id is not None: + self.scheduler.source_remove(self._exit_timeout_id) + self._exit_timeout_id = None + if self._ipc_daemon is not None: self._ipc_daemon.cancel() if self._exit_command.exitcode is not None: diff --git a/pym/_emerge/SubProcess.py b/pym/_emerge/SubProcess.py index 37922dc66..c5cac7dde 100644 --- a/pym/_emerge/SubProcess.py +++ b/pym/_emerge/SubProcess.py @@ -16,6 +16,10 @@ class SubProcess(AbstractPollTask): # serve this purpose alone. _dummy_pipe_fd = 9 + # This is how much time we allow for waitpid to succeed after + # we've sent a kill signal to our subprocess. + _cancel_timeout = 1000 # 1 second + def _poll(self): if self.returncode is not None: return self.returncode @@ -60,7 +64,7 @@ class SubProcess(AbstractPollTask): if self._registered: if self.cancelled: - timeout = 1000 + timeout = self._cancel_timeout self.scheduler.schedule(self._reg_id, timeout=timeout) if self._registered: try: -- cgit v1.2.3-1-g7c22