Catch exceptions in project list generator
If the generator that produces per-project worker arguments raises an
exception it triggers python bug http://bugs.python.org/issue8296.
Rewrite the generator expression as a generator function, and catch
Exceptions and KeyboardInterrupts to end the iteration.
Also add a pool worker initializer to disable SIGINT to prevent
KeyboardInterrupts inside multiprocessing.Pool in the worker threads
causing the same problem.
Fixes easy-to-reproduce hangs when hitting ctrl-c during
repo forall -c echo
Change-Id: Ie4a65b3e1e07a64ed6bb6ff20f3912c4326718ca
diff --git a/subcmds/forall.py b/subcmds/forall.py
index 88b23fb..6a6d30c 100644
--- a/subcmds/forall.py
+++ b/subcmds/forall.py
@@ -20,6 +20,7 @@
import re
import os
import select
+import signal
import sys
import subprocess
@@ -207,14 +208,12 @@
os.environ['REPO_COUNT'] = str(len(projects))
- pool = multiprocessing.Pool(opt.jobs)
+ pool = multiprocessing.Pool(opt.jobs, InitWorker)
try:
config = self.manifest.manifestProject.config
results_it = pool.imap(
DoWorkWrapper,
- ([mirror, opt, cmd, shell, cnt, config, self._SerializeProject(p)]
- for cnt, p in enumerate(projects))
- )
+ self.ProjectArgs(projects, mirror, opt, cmd, shell, config))
pool.close()
for r in results_it:
rc = rc or r
@@ -236,12 +235,28 @@
if rc != 0:
sys.exit(rc)
+ def ProjectArgs(self, projects, mirror, opt, cmd, shell, config):
+ for cnt, p in enumerate(projects):
+ try:
+ project = self._SerializeProject(p)
+ except Exception as e:
+ print('Project list error: %r' % e,
+ file=sys.stderr)
+ return
+ except KeyboardInterrupt:
+ print('Project list interrupted',
+ file=sys.stderr)
+ return
+ yield [mirror, opt, cmd, shell, cnt, config, project]
class WorkerKeyboardInterrupt(Exception):
""" Keyboard interrupt exception for worker processes. """
pass
+def InitWorker():
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+
def DoWorkWrapper(args):
""" A wrapper around the DoWork() method.