Use timeout_add to avoid recursion, bug #402335.
authorZac Medico <zmedico@gentoo.org>
Tue, 7 Feb 2012 02:58:51 +0000 (18:58 -0800)
committerZac Medico <zmedico@gentoo.org>
Tue, 7 Feb 2012 19:12:32 +0000 (11:12 -0800)
pym/_emerge/AbstractEbuildProcess.py
pym/_emerge/SubProcess.py

index 63368d4af4b340fdff2599d9c06e7c1bdffbf106..5742cb2a77847199a08767636271c4a5963ebb52 100644 (file)
@@ -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:
index 37922dc666bf0e766ba94fcff58a028d42dbcdba..c5cac7dde80839713ad7873e89b075a49bb09fe0 100644 (file)
@@ -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: