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