self.pkgsettings[root] = portage.config(
clone=trees[root]["vartree"].settings)
self.curval = 0
+ self._spawned_pids = []
def merge(self, mylist, favorites, mtimedb):
+ try:
+ return self._merge(mylist, favorites, mtimedb)
+ finally:
+ if self._spawned_pids:
+ from portage import process
+ process.spawned_pids.extend(self._spawned_pids)
+ self._spawned_pids = []
+
+ def _poll_child_processes(self):
+ """
+ After each merge, collect status from child processes
+ in order to clean up zombies (such as the parallel-fetch
+ process).
+ """
+ spawned_pids = self._spawned_pids
+ if not spawned_pids:
+ return
+ for pid in list(spawned_pids):
+ try:
+ if os.waitpid(pid, os.WNOHANG) == (0, 0):
+ continue
+ except OSError:
+ # This pid has been cleaned up elsewhere.
+ continue
+ spawned_pids.remove(pid)
+
+ def _merge(self, mylist, favorites, mtimedb):
from portage.elog import elog_process
from portage.elog.filtering import filter_mergephases
failed_fetches = []
fetch_args.append(myopt)
else:
fetch_args.append(myopt +"="+ myarg)
- portage.process.spawn(fetch_args, env=fetch_env,
- fd_pipes=fd_pipes, returnpid=True)
+ self._spawned_pids.extend(
+ portage.process.spawn(
+ fetch_args, env=fetch_env,
+ fd_pipes=fd_pipes, returnpid=True))
logfile.close() # belongs to the spawned process
del fetch_log, logfile, fd_pipes, fetch_env, fetch_args, \
resume_opts
# due to power failure, SIGKILL, etc...
mtimedb.commit()
self.curval += 1
+ self._poll_child_processes()
if "--pretend" not in self.myopts:
emergelog(xterm_titles, " *** Finished. Cleaning up...")