From 31a7be561ef34c134447d92a3d391b17ecd7c790 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 13 May 2015 00:04:36 -0700 Subject: [PATCH 1/2] 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 --- subcmds/forall.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/subcmds/forall.py b/subcmds/forall.py index 88b23fbd..6a6d30c9 100644 --- a/subcmds/forall.py +++ b/subcmds/forall.py @@ -20,6 +20,7 @@ import multiprocessing import re import os import select +import signal import sys import subprocess @@ -207,14 +208,12 @@ without iterating through the remaining projects. 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 @@ without iterating through the remaining projects. 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. From c4b301f988ad7499257538070f78f5e50e61b3ae Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 13 May 2015 00:10:02 -0700 Subject: [PATCH 2/2] Skip sleep and retry if git remote update exits with a signal Pressing ctrl-c during repo sync often hangs for 30 to 45 seconds due to the time.sleep and retry in _RemoteFetch. If git exits with a signal, for example -2 for SIGINT triggered by ctrl-c, skip the sleep and retry. Change-Id: I32da12c2dcc96d9cc0b12a066e824b12ebfb52a0 --- project.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/project.py b/project.py index 00e41ada..a41d26a8 100644 --- a/project.py +++ b/project.py @@ -1908,6 +1908,9 @@ class Project(object): # mode, we just tried sync'ing from the upstream field; it doesn't exist, thus # abort the optimization attempt and do a full sync. break + elif ret < 0: + # Git died with a signal, exit immediately + break time.sleep(random.randint(30, 45)) if initial: