commit: 007236f06506744fdb67910af5d7fb69783dbfe1 Author: Zac Medico <zmedico <AT> gentoo <DOT> org> AuthorDate: Sat Nov 21 19:41:07 2015 +0000 Commit: Zac Medico <zmedico <AT> gentoo <DOT> org> CommitDate: Mon Nov 23 16:28:55 2015 +0000 URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=007236f0
SpawnProcess: re-check cgroup.procs until empty (bug 566420) For subshell die support (bug 465008), re-check cgroup.procs until it's empty, in case any of the listed processes fork before we've had a chance to kill them. X-Gentoo-Bug: 566420 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=566420 Acked-by: Alexander Berntsen <bernalex <AT> gentoo.org> pym/_emerge/SpawnProcess.py | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/pym/_emerge/SpawnProcess.py b/pym/_emerge/SpawnProcess.py index b4b4b5b..e046640 100644 --- a/pym/_emerge/SpawnProcess.py +++ b/pym/_emerge/SpawnProcess.py @@ -16,6 +16,8 @@ from _emerge.SubProcess import SubProcess import portage from portage import os from portage.const import BASH_BINARY +from portage.localization import _ +from portage.output import EOutput from portage.util import writemsg_level from portage.util._async.PipeLogger import PipeLogger @@ -35,6 +37,10 @@ class SpawnProcess(SubProcess): __slots__ = ("args",) + \ _spawn_kwarg_names + ("_pipe_logger", "_selinux_type",) + # Max number of attempts to kill the processes listed in cgroup.procs, + # given that processes may fork before they can be killed. + _CGROUP_CLEANUP_RETRY_MAX = 8 + def _start(self): if self.fd_pipes is None: @@ -209,10 +215,24 @@ class SpawnProcess(SubProcess): elif e.errno != errno.ESRCH: raise - # step 1: kill all orphans - pids = get_pids(self.cgroup) + # step 1: kill all orphans (loop in case of new forks) + remaining = self._CGROUP_CLEANUP_RETRY_MAX + while remaining: + remaining -= 1 + pids = get_pids(self.cgroup) + if pids: + kill_all(pids, signal.SIGKILL) + else: + break + if pids: - kill_all(pids, signal.SIGKILL) + msg = [] + msg.append( + _("Failed to kill pid(s) in '%(cgroup)s': %(pids)s") % dict( + cgroup=os.path.join(self.cgroup, 'cgroup.procs'), + pids=' '.join(str(pid) for pid in pids))) + + self._elog('eerror', msg) # step 2: remove the cgroup try: @@ -221,3 +241,8 @@ class SpawnProcess(SubProcess): # it may be removed already, or busy # we can't do anything good about it pass + + def _elog(self, elog_funcname, lines): + elog_func = getattr(EOutput(), elog_funcname) + for line in lines: + elog_func(line)
