summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico2012-02-07 02:58:51 (GMT)
committerZac Medico2012-02-07 19:12:32 (GMT)
commit445a6ea22c132f4c06c2cc7c48ec6e7af7116962 (patch)
treeb58ab2ad51696b7588a0a644e58ee6e4cc7329bf
parent839f369f259a7c019c1f544bf4c153058355f6d4 (diff)
Use timeout_add to avoid recursion, bug #402335.
-rw-r--r--pym/_emerge/AbstractEbuildProcess.py37
-rw-r--r--pym/_emerge/SubProcess.py6
2 files changed, 34 insertions, 9 deletions
diff --git a/pym/_emerge/AbstractEbuildProcess.py b/pym/_emerge/AbstractEbuildProcess.py
index 63368d4..5742cb2 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 37922dc..c5cac7d 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: