◐ Shell
clean mode source ↗

[WIP][2.7] bpo-30351: regrtest: add --timeout by vstinner · Pull Request #3019 · python/cpython

Expand Up @@ -188,6 +188,10 @@ import imp import platform import sysconfig try: import threading except ImportError: threading = None

# Some times __path__ and __file__ are not absolute (e.g. while running from Expand Down Expand Up @@ -330,6 +334,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, directly to set the values that would normally be set by flags on the command line. """ watchdog = None
regrtest_start_time = time.time()
test_support.record_original_stdout(sys.stdout) Expand All @@ -342,7 +348,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=', 'multiprocess=', 'slaveargs=', 'forever', 'header', 'pgo', 'failfast', 'match=', 'testdir=', 'list-tests', 'list-cases', 'coverage', 'matchfile=', 'fail-env-changed']) 'coverage', 'matchfile=', 'fail-env-changed', 'timeout=']) except getopt.error, msg: usage(2, msg)
Expand All @@ -355,6 +361,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, list_tests = False list_cases_opt = False fail_env_changed = False timeout = None for o, a in opts: if o in ('-h', '--help'): usage(0) Expand Down Expand Up @@ -392,6 +399,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, with open(filename) as fp: for line in fp: match_tests.append(line.strip()) elif o == '--timeout': timeout = float(a) elif o in ('-l', '--findleaks'): findleaks = True elif o in ('-L', '--runleaks'): Expand Down Expand Up @@ -470,6 +479,14 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, if failfast and not (verbose or verbose3): usage("-G/--failfast needs either -v or -W")
if timeout is not None: if threading is None: print("ERROR: --timeout needs threading support") sys.exit(1)
watchdog = WatchDogThread(timeout) watchdog.start()
if testdir: testdir = os.path.abspath(testdir)
Expand Down Expand Up @@ -801,6 +818,9 @@ def get_running(workers): display_progress(test_index, text)
def local_runtest(): if watchdog is not None: watchdog.reset()
result = runtest(test, verbose, quiet, huntrleaks, None, pgo, failfast=failfast, match_tests=match_tests, Expand All @@ -822,6 +842,8 @@ def local_runtest(): if verbose3 and result[0] == FAILED: if not pgo: print "Re-running test %r in verbose mode" % test if watchdog is not None: watchdog.reset() runtest(test, True, quiet, huntrleaks, None, pgo, testdir=testdir) except KeyboardInterrupt: Expand Down Expand Up @@ -898,6 +920,8 @@ def local_runtest(): print "Re-running test %r in verbose mode" % test sys.stdout.flush() try: if watchdog is not None: watchdog.reset() test_support.verbose = True ok = runtest(test, True, quiet, huntrleaks, None, pgo, testdir=testdir) Expand Down Expand Up @@ -927,6 +951,10 @@ def local_runtest(): if runleaks: os.system("leaks %d" % os.getpid())
if watchdog is not None: watchdog.stop() watchdog.stop()
print duration = time.time() - regrtest_start_time print("Total duration: %s" % format_duration(duration)) Expand Down Expand Up @@ -1963,6 +1991,70 @@ def getexpected(self): assert self.isvalid() return self.expected

if threading is not None: class WatchDogThread(threading.Thread): daemon = True
def __init__(self, timeout): threading.Thread.__init__(self) self.timeout = timeout self.stream = sys.__stdout__ self.quit = False self.reset()
def reset(self): self.deadline = time.time() + self.timeout
def write(self, line): self.stream.write(line + "\n") self.stream.flush()
def run(self): while True: # the sleep duration impacts the delay of .join() # called by .stop() time.sleep(0.1) if self.quit: return if time.time() >= self.deadline: break
try: self.dump_threads() except: self.write("FAILED TO DUMP THREADS") os._exit(1)
def stop(self): if not self.is_alive(): return
print("Stop watchdog") self.quit = True self.join()
def dump_thread(self, stack): for filename, lineno, name, line in traceback.extract_stack(stack): self.write('File: "%s", line %d, in %s' % (filename, lineno, name)) line = line.strip() if line: self.write(" %s" % line)
def dump_threads(self): self.write("*** STACKTRACE - START ***")
for threadId, stack in sys._current_frames().items(): self.write("# ThreadID: %s" % threadId) try: self.dump_thread(stack) except: self.write("FAILED TO DUMP THREAD STACK") self.write("")
self.write("*** STACKTRACE - END ***")

def main_in_temp_cwd(): """Run main() in a temporary working directory.""" global TEMPDIR Expand Down