Skip to content

Commit 33cf0c4

Browse files
authored
bpo-30675: Fix multiprocessing code in regrtest (#2220)
* Rewrite code to pass slaveargs from the master process to worker processes: reuse the same code of the Python master branch * Move code to initialize tests in a new setup_tests() function, similar change was done in the master branch * In a worker process, call setup_tests() with the namespace built from slaveargs to initialize correctly tests Before this change, warm_caches() was not called in worker processes because the setup was done before rebuilding the namespace from slaveargs. As a consequence, the huntrleaks feature was unstable. For example, test_zipfile reported randomly false positive on reference leaks.
1 parent 263dcc3 commit 33cf0c4

File tree

1 file changed

+63
-47
lines changed

1 file changed

+63
-47
lines changed

Lib/test/regrtest.py

Lines changed: 63 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
import tempfile
141141
import time
142142
import traceback
143+
import types
143144
import unittest
144145
import warnings
145146
from inspect import isabstract
@@ -448,17 +449,15 @@ def run_test_in_subprocess(testname, ns):
448449
# required to spawn a new process with PGO flag on/off
449450
if ns.pgo:
450451
base_cmd = base_cmd + ['--pgo']
451-
slaveargs = (
452-
(testname, ns.verbose, ns.quiet),
453-
dict(huntrleaks=ns.huntrleaks,
454-
use_resources=ns.use_resources,
455-
output_on_failure=ns.verbose3,
456-
timeout=ns.timeout, failfast=ns.failfast,
457-
match_tests=ns.match_tests, pgo=ns.pgo))
452+
453+
ns_dict = vars(ns)
454+
slaveargs = (ns_dict, testname)
455+
slaveargs = json.dumps(slaveargs)
456+
458457
# Running the child from the same working directory as regrtest's original
459458
# invocation ensures that TEMPDIR for the child is the same when
460459
# sysconfig.is_python_build() is true. See issue 15300.
461-
popen = Popen(base_cmd + ['--slaveargs', json.dumps(slaveargs)],
460+
popen = Popen(base_cmd + ['--slaveargs', slaveargs],
462461
stdout=PIPE, stderr=PIPE,
463462
universal_newlines=True,
464463
close_fds=(os.name != 'nt'),
@@ -468,6 +467,43 @@ def run_test_in_subprocess(testname, ns):
468467
return retcode, stdout, stderr
469468

470469

470+
def setup_tests(ns):
471+
if ns.huntrleaks:
472+
# Avoid false positives due to various caches
473+
# filling slowly with random data:
474+
warm_caches()
475+
if ns.memlimit is not None:
476+
support.set_memlimit(ns.memlimit)
477+
if ns.threshold is not None:
478+
import gc
479+
gc.set_threshold(ns.threshold)
480+
if ns.nowindows:
481+
print('The --nowindows (-n) option is deprecated. '
482+
'Use -vv to display assertions in stderr.')
483+
try:
484+
import msvcrt
485+
except ImportError:
486+
pass
487+
else:
488+
msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
489+
msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
490+
msvcrt.SEM_NOGPFAULTERRORBOX|
491+
msvcrt.SEM_NOOPENFILEERRORBOX)
492+
try:
493+
msvcrt.CrtSetReportMode
494+
except AttributeError:
495+
# release build
496+
pass
497+
else:
498+
for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
499+
if ns.verbose and ns.verbose >= 2:
500+
msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
501+
msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
502+
else:
503+
msvcrt.CrtSetReportMode(m, 0)
504+
505+
506+
471507
def main(tests=None, **kwargs):
472508
"""Execute a test suite.
473509
@@ -509,58 +545,38 @@ def main(tests=None, **kwargs):
509545

510546
ns = _parse_args(sys.argv[1:], **kwargs)
511547

512-
if ns.huntrleaks:
513-
# Avoid false positives due to various caches
514-
# filling slowly with random data:
515-
warm_caches()
516-
if ns.memlimit is not None:
517-
support.set_memlimit(ns.memlimit)
518-
if ns.threshold is not None:
519-
import gc
520-
gc.set_threshold(ns.threshold)
521-
if ns.nowindows:
522-
print('The --nowindows (-n) option is deprecated. '
523-
'Use -vv to display assertions in stderr.')
524-
try:
525-
import msvcrt
526-
except ImportError:
527-
pass
528-
else:
529-
msvcrt.SetErrorMode(msvcrt.SEM_FAILCRITICALERRORS|
530-
msvcrt.SEM_NOALIGNMENTFAULTEXCEPT|
531-
msvcrt.SEM_NOGPFAULTERRORBOX|
532-
msvcrt.SEM_NOOPENFILEERRORBOX)
533-
try:
534-
msvcrt.CrtSetReportMode
535-
except AttributeError:
536-
# release build
537-
pass
538-
else:
539-
for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]:
540-
if ns.verbose and ns.verbose >= 2:
541-
msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE)
542-
msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR)
543-
else:
544-
msvcrt.CrtSetReportMode(m, 0)
545-
if ns.wait:
546-
input("Press any key to continue...")
547-
548548
if ns.slaveargs is not None:
549-
args, kwargs = json.loads(ns.slaveargs)
550-
if kwargs.get('huntrleaks'):
549+
ns_dict, testname = json.loads(ns.slaveargs)
550+
ns = types.SimpleNamespace(**ns_dict)
551+
552+
setup_tests(ns)
553+
554+
if ns.huntrleaks:
551555
unittest.BaseTestSuite._cleanup = False
556+
552557
try:
553-
result = runtest(*args, **kwargs)
558+
result = runtest(testname, ns.verbose, ns.quiet,
559+
ns.huntrleaks,
560+
output_on_failure=ns.verbose3,
561+
timeout=ns.timeout, failfast=ns.failfast,
562+
match_tests=ns.match_tests, pgo=ns.pgo,
563+
use_resources=ns.use_resources)
554564
except KeyboardInterrupt:
555565
result = INTERRUPTED, ''
556566
except BaseException as e:
557567
traceback.print_exc()
558568
result = CHILD_ERROR, str(e)
569+
559570
sys.stdout.flush()
560571
print() # Force a newline (just in case)
561572
print(json.dumps(result))
562573
sys.exit(0)
563574

575+
setup_tests(ns)
576+
577+
if ns.wait:
578+
input("Press any key to continue...")
579+
564580
good = []
565581
bad = []
566582
skipped = []

0 commit comments

Comments
 (0)