Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 93 additions & 1 deletion 94 Lib/test/regrtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,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 @@ -315,6 +319,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 @@ -327,7 +333,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='])
'coverage', 'matchfile=', 'timeout='])
except getopt.error, msg:
usage(2, msg)

Expand All @@ -339,6 +345,7 @@ def main(tests=None, testdir=None, verbose=0, quiet=False,
slaveargs = None
list_tests = False
list_cases_opt = False
timeout = None
for o, a in opts:
if o in ('-h', '--help'):
usage(0)
Expand Down Expand Up @@ -376,6 +383,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 @@ -452,6 +461,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 @@ -772,6 +789,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 @@ -793,6 +813,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 @@ -871,6 +893,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 @@ -900,6 +924,10 @@ def local_runtest():
if runleaks:
os.system("leaks %d" % os.getpid())

if watchdog is not None:
watchdog.stop()
watchdog.stop()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why twice? Maybe sleep between them?


print
duration = time.time() - regrtest_start_time
print("Total duration: %s" % format_duration(duration))
Expand Down Expand Up @@ -1910,6 +1938,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__
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't __stderr__ be more appropriate for debug and error messages?

Can't standard streams be None on Windows?

self.quit = False
self.reset()

def reset(self):
self.deadline = time.time() + self.timeout

def write(self, line):
self.stream.write(line + "\n")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe print >>self.stream, line? This works even if self.stream is None.

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")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Print a traceback?

os._exit(1)

def stop(self):
if not self.is_alive():
return

print("Stop watchdog")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.write()?

self.quit = True
self.join()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

join() takes the timeout argument. Is it worth to use it?


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 ***")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the case if the previous outputted line is not ended with a newline and for attracting an attention add a \n or two before the message.


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")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Print a traceback?

self.write("")

self.write("*** STACKTRACE - END ***")


def main_in_temp_cwd():
"""Run main() in a temporary working directory."""
global TEMPDIR
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.