summaryrefslogtreecommitdiffstats
path: root/Lib/test/regrtest.py
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2012-07-25 22:47:15 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2012-07-25 22:47:15 (GMT)
commit0b9e7b9ea909de6377cab20568f9b52e7f0089ce (patch)
treed36750b2bb62b3e4bcbc86784654c17f4f65f7ad /Lib/test/regrtest.py
parentc5618f039d490c23a4297ae87668ac566e8d3b84 (diff)
parent09f2e6f902b02708225c7bef7f031869ad85b094 (diff)
downloadcpython-0b9e7b9ea909de6377cab20568f9b52e7f0089ce.zip
cpython-0b9e7b9ea909de6377cab20568f9b52e7f0089ce.tar.gz
cpython-0b9e7b9ea909de6377cab20568f9b52e7f0089ce.tar.bz2
Issue #15320: Make iterating the list of tests thread-safe when running tests in multiprocess mode.
Patch by Chris Jerdonek.
Diffstat (limited to 'Lib/test/regrtest.py')
-rwxr-xr-xLib/test/regrtest.py42
1 files changed, 29 insertions, 13 deletions
diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py
index 3c8359a..15d7d0b 100755
--- a/Lib/test/regrtest.py
+++ b/Lib/test/regrtest.py
@@ -614,17 +614,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
from subprocess import Popen, PIPE
debug_output_pat = re.compile(r"\[\d+ refs\]$")
output = Queue()
- def tests_and_args():
- for test in tests:
- args_tuple = (
- (test, verbose, quiet),
- dict(huntrleaks=huntrleaks, use_resources=use_resources,
- debug=debug, output_on_failure=verbose3,
- timeout=timeout, failfast=failfast,
- match_tests=match_tests)
- )
- yield (test, args_tuple)
- pending = tests_and_args()
+ pending = MultiprocessTests(tests)
opt_args = support.args_from_interpreter_flags()
base_cmd = [sys.executable] + opt_args + ['-m', 'test.regrtest']
def work():
@@ -632,10 +622,17 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
try:
while True:
try:
- test, args_tuple = next(pending)
+ test = next(pending)
except StopIteration:
output.put((None, None, None, None))
return
+ args_tuple = (
+ (test, verbose, quiet),
+ dict(huntrleaks=huntrleaks, use_resources=use_resources,
+ debug=debug, output_on_failure=verbose3,
+ timeout=timeout, failfast=failfast,
+ match_tests=match_tests)
+ )
# -E is needed by some tests, e.g. test_import
# Running the child from the same working directory ensures
# that TEMPDIR for the child is the same when
@@ -694,7 +691,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
test_index += 1
except KeyboardInterrupt:
interrupted = True
- pending.close()
+ pending.interrupted = True
for worker in workers:
worker.join()
else:
@@ -840,6 +837,25 @@ def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS):
tests.append(mod)
return stdtests + sorted(tests)
+# We do not use a generator so multiple threads can call next().
+class MultiprocessTests(object):
+
+ """A thread-safe iterator over tests for multiprocess mode."""
+
+ def __init__(self, tests):
+ self.interrupted = False
+ self.lock = threading.Lock()
+ self.tests = tests
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ with self.lock:
+ if self.interrupted:
+ raise StopIteration('tests interrupted')
+ return next(self.tests)
+
def replace_stdout():
"""Set stdout encoder error handler to backslashreplace (as stderr error
handler) to avoid UnicodeEncodeError when printing a traceback"""