Roll gtest-parallel.
BUG=
R=kwiberg@webrtc.org
Review URL: https://codereview.webrtc.org/1526383002
Cr-Commit-Position: refs/heads/master@{#11055}
diff --git a/third_party/gtest-parallel/README.webrtc b/third_party/gtest-parallel/README.webrtc
index 65974c4..6e0c066 100644
--- a/third_party/gtest-parallel/README.webrtc
+++ b/third_party/gtest-parallel/README.webrtc
@@ -1,5 +1,5 @@
URL: https://github.com/google/gtest-parallel
-Version: 8e26fe7e305353f1217baf5ff409b1dd1bd5ab39
+Version: c65f666eebfedde586cba0bd3381666edc6c4afe
License: Apache 2.0
License File: LICENSE
diff --git a/third_party/gtest-parallel/gtest-parallel b/third_party/gtest-parallel/gtest-parallel
index b847180..b609ab9 100755
--- a/third_party/gtest-parallel/gtest-parallel
+++ b/third_party/gtest-parallel/gtest-parallel
@@ -18,13 +18,62 @@
import multiprocessing
import optparse
import os
+import signal
import subprocess
import sys
import tempfile
+import thread
import threading
import time
import zlib
+# An object that catches SIGINT sent to the Python process and notices
+# if processes passed to wait() die by SIGINT (we need to look for
+# both of those cases, because pressing Ctrl+C can result in either
+# the main process or one of the subprocesses getting the signal).
+#
+# Before a SIGINT is seen, wait(p) will simply call p.wait() and
+# return the result. Once a SIGINT has been seen (in the main process
+# or a subprocess, including the one the current call is waiting for),
+# wait(p) will call p.terminate() and raise ProcessWasInterrupted.
+class SigintHandler(object):
+ class ProcessWasInterrupted(Exception): pass
+ sigint_returncodes = {-signal.SIGINT, # Unix
+ -1073741510, # Windows
+ }
+ def __init__(self):
+ self.__lock = threading.Lock()
+ self.__processes = set()
+ self.__got_sigint = False
+ signal.signal(signal.SIGINT, self.__sigint_handler)
+ def __on_sigint(self):
+ self.__got_sigint = True
+ while self.__processes:
+ try:
+ self.__processes.pop().terminate()
+ except OSError:
+ pass
+ def __sigint_handler(self, signal_num, frame):
+ with self.__lock:
+ self.__on_sigint()
+ def got_sigint(self):
+ with self.__lock:
+ return self.__got_sigint
+ def wait(self, p):
+ with self.__lock:
+ if self.__got_sigint:
+ p.terminate()
+ self.__processes.add(p)
+ code = p.wait()
+ with self.__lock:
+ self.__processes.discard(p)
+ if code in self.sigint_returncodes:
+ self.__on_sigint()
+ if self.__got_sigint:
+ raise self.ProcessWasInterrupted
+ return code
+sigint_handler = SigintHandler()
+
# Return the width of the terminal, or None if it couldn't be
# determined (e.g. because we're not being run interactively).
def term_width(out):
@@ -301,7 +350,10 @@
['--gtest_color=' + options.gtest_color],
stdout=log.file,
stderr=log.file)
- code = sub.wait()
+ try:
+ code = sigint_handler.wait(sub)
+ except sigint_handler.ProcessWasInterrupted:
+ thread.exit()
runtime_ms = int(1000 * (time.time() - begin))
logger.logfile(job_id, log.name)
@@ -344,4 +396,4 @@
if times.get_test_time(test_binary, test) is not None)
for (time_ms, test_binary, test) in ts:
print "%8s %s" % ("%dms" % time_ms, test)
-sys.exit(exit_code)
+sys.exit(-signal.SIGINT if sigint_handler.got_sigint() else exit_code)