@ -55,6 +55,9 @@ GNU_SKIP_RETURNCODE = 77
# mean that the test failed even before testing what it is supposed to test.
# mean that the test failed even before testing what it is supposed to test.
GNU_ERROR_RETURNCODE = 99
GNU_ERROR_RETURNCODE = 99
# Exit if 3 Ctrl-C's are received within one second
MAX_CTRLC = 3
def is_windows ( ) - > bool :
def is_windows ( ) - > bool :
platname = platform . system ( ) . lower ( )
platname = platform . system ( ) . lower ( )
return platname == ' windows '
return platname == ' windows '
@ -1549,6 +1552,7 @@ class TestHarness:
futures = deque ( ) # type: T.Deque[asyncio.Future]
futures = deque ( ) # type: T.Deque[asyncio.Future]
running_tests = dict ( ) # type: T.Dict[asyncio.Future, str]
running_tests = dict ( ) # type: T.Dict[asyncio.Future, str]
interrupted = False
interrupted = False
ctrlc_times = deque ( maxlen = MAX_CTRLC ) # type: T.Deque[float]
async def run_test ( test : SingleTestRunner ) - > None :
async def run_test ( test : SingleTestRunner ) - > None :
async with semaphore :
async with semaphore :
@ -1577,15 +1581,18 @@ class TestHarness:
del running_tests [ future ]
del running_tests [ future ]
future . cancel ( )
future . cancel ( )
def sigterm_handler ( ) - > None :
def cancel_all_tests ( ) - > None :
nonlocal interrupted
nonlocal interrupted
interrupted = True
while running_tests :
cancel_one_test ( False )
def sigterm_handler ( ) - > None :
if interrupted :
if interrupted :
return
return
interrupted = True
self . flush_logfiles ( )
self . flush_logfiles ( )
mlog . warning ( ' Received SIGTERM, exiting ' )
mlog . warning ( ' Received SIGTERM, exiting ' )
while running_tests :
cancel_all_tests ( )
cancel_one_test ( False )
def sigint_handler ( ) - > None :
def sigint_handler ( ) - > None :
# We always pick the longest-running future that has not been cancelled
# We always pick the longest-running future that has not been cancelled
@ -1593,7 +1600,12 @@ class TestHarness:
nonlocal interrupted
nonlocal interrupted
if interrupted :
if interrupted :
return
return
if running_tests :
ctrlc_times . append ( asyncio . get_event_loop ( ) . time ( ) )
if len ( ctrlc_times ) == MAX_CTRLC and ctrlc_times [ - 1 ] - ctrlc_times [ 0 ] < 1 :
self . flush_logfiles ( )
mlog . warning ( ' CTRL-C detected, exiting ' )
cancel_all_tests ( )
elif running_tests :
cancel_one_test ( True )
cancel_one_test ( True )
else :
else :
self . flush_logfiles ( )
self . flush_logfiles ( )