Skip to content

Commit fdc79e1

Browse files
committed
Greatly improve test interrupt handling.
1 parent 4d6aee6 commit fdc79e1

File tree

2 files changed

+29
-45
lines changed

2 files changed

+29
-45
lines changed

Project.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
88
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
99
IOCapture = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
1010
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
11-
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
1211
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1312
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1413

@@ -17,7 +16,6 @@ Dates = "1"
1716
Distributed = "1"
1817
IOCapture = "0.2.5"
1918
Printf = "1"
20-
REPL = "1"
2119
Random = "1"
2220
Test = "1"
2321
julia = "1.10"

src/ParallelTestRunner.jl

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export runtests, addworkers, addworker
44

55
using Distributed
66
using Dates
7-
import REPL
87
using Printf: @sprintf
98
using Base.Filesystem: path_separator
109
import Test
@@ -423,9 +422,9 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
423422

424423
# list tests, if requested
425424
if do_list
426-
println("Available tests:")
425+
println(stdout, "Available tests:")
427426
for test in sort(tests)
428-
println(" - $test")
427+
println(stdout, " - $test")
429428
end
430429
exit(0)
431430
end
@@ -451,15 +450,14 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
451450

452451
t0 = time()
453452
results = []
454-
tasks = Task[]
455453
running_tests = Dict{String, Tuple{Int, Float64}}() # test => (worker, start_time)
456454
test_lock = ReentrantLock() # to protect crucial access to tests and running_tests
457455

458456
done = false
459457
function stop_work()
460458
if !done
461459
done = true
462-
for task in tasks
460+
for task in worker_tasks
463461
task == current_task() && continue
464462
Base.istaskdone(task) && continue
465463
try; schedule(task, InterruptException(); error=true); catch; end
@@ -468,33 +466,6 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
468466
end
469467

470468

471-
#
472-
# input
473-
#
474-
475-
# Keyboard monitor (for more reliable CTRL-C handling)
476-
if isa(stdin, Base.TTY)
477-
# NOTE: this should be the first task; we really want it to complete
478-
pushfirst!(tasks, @async begin
479-
term = REPL.Terminals.TTYTerminal("xterm", stdin, stdout, stderr)
480-
REPL.Terminals.raw!(term, true)
481-
try
482-
while !done
483-
c = read(term, Char)
484-
if c == '\x3'
485-
println(stderr, "\nCaught interrupt, stopping...")
486-
stop_work()
487-
break
488-
end
489-
end
490-
finally
491-
REPL.Terminals.raw!(term, false)
492-
end
493-
end)
494-
end
495-
# TODO: we have to be _fast_ here, as Pkg.jl only gives us 4 seconds to clean up
496-
497-
498469
#
499470
# output
500471
#
@@ -626,6 +597,13 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
626597
sleep(0.1)
627598
end
628599
catch ex
600+
if isa(ex, InterruptException)
601+
# the printer should keep on running,
602+
# but we need to signal other tasks to stop
603+
stop_work()
604+
else
605+
rethrow()
606+
end
629607
isa(ex, InterruptException) || rethrow()
630608
finally
631609
if isempty(tests) && isempty(running_tests)
@@ -641,8 +619,9 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
641619
# execution
642620
#
643621

622+
worker_tasks = Task[]
644623
for p in workers()
645-
push!(tasks, @async begin
624+
push!(worker_tasks, @async begin
646625
while length(tests) > 0 && !done
647626
# if a worker failed, spawn a new one
648627
if p === nothing
@@ -665,7 +644,13 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
665644
result = try
666645
remotecall_fetch(runtest, wrkr, RecordType, test_runners[test], test, init_code)
667646
catch ex
668-
isa(ex, InterruptException) && return
647+
if isa(ex, InterruptException)
648+
# the worker got interrupted, signal other tasks to stop
649+
stop_work()
650+
return
651+
end
652+
653+
# return any other exception as the result
669654
# XXX: also put this in a test record?
670655
ex
671656
end
@@ -700,10 +685,6 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
700685

701686
delete!(running_tests, test)
702687
end
703-
704-
if p !== nothing
705-
recycle_worker(p)
706-
end
707688
end)
708689
end
709690

@@ -712,10 +693,10 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
712693
# finalization
713694
#
714695

715-
# monitor tasks for failure so that each one doesn't need a try/catch + stop_work()
696+
# monitor worker tasks for failure so that each one doesn't need a try/catch + stop_work()
716697
try
717698
while true
718-
if any(istaskfailed, tasks)
699+
if any(istaskfailed, worker_tasks)
719700
println(io_ctx.stderr, "\nCaught an error, stopping...")
720701
break
721702
elseif done || Base.@lock(test_lock, isempty(tests) && isempty(running_tests))
@@ -729,10 +710,13 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
729710
finally
730711
stop_work()
731712
end
732-
## `wait()` to actually catch any exceptions
713+
714+
# wait for the printer to finish so that all results have been printed
733715
close(printer_channel)
734716
wait(printer_task)
735-
for task in tasks
717+
718+
# wait for worker tasks to catch unhandled exceptions
719+
for task in worker_tasks
736720
try
737721
wait(task)
738722
catch err
@@ -744,6 +728,7 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
744728
isa(err, InterruptException) || rethrow()
745729
end
746730
end
731+
@async rmprocs(; waitfor=0)
747732

748733
# print the output generated by each testset
749734
for (testname, result, start, stop) in results
@@ -881,7 +866,8 @@ function runtests(ARGS; testfilter = Returns(true), RecordType = TestRecord,
881866
end
882867
throw(Test.FallbackTestSetException("Test run finished with errors"))
883868
end
884-
return nothing
869+
870+
return
885871
end # runtests
886872

887873
end # module ParallelTestRunner

0 commit comments

Comments
 (0)