|
| 1 | +function cancel!(tid::Union{Int,Nothing}=nothing; |
| 2 | + sch_uid::Union{UInt64,Nothing}=nothing, |
| 3 | + force::Bool=false, halt_sch::Bool=false) |
| 4 | + remotecall_fetch(1, tid, sch_uid, force, halt_sch) do tid, sch_uid, force, halt_sch |
| 5 | + state = Sch.EAGER_STATE[] |
| 6 | + @lock state.lock _cancel!(state, tid, sch_uid, force, halt_sch) |
| 7 | + end |
| 8 | +end |
| 9 | +function _cancel!(state, tid, sch_uid, force, halt_sch) |
| 10 | + @assert islocked(state.lock) |
| 11 | + |
| 12 | + # Get the scheduler uid |
| 13 | + if sch_uid === nothing |
| 14 | + sch_uid = state.uid |
| 15 | + end |
| 16 | + |
| 17 | + # Cancel ready tasks |
| 18 | + for task in state.ready |
| 19 | + tid !== nothing && task.id == tid && continue |
| 20 | + @dagdebug tid :cancel "Cancelling ready task" |
| 21 | + state.cache[task] = InterruptException() |
| 22 | + state.errored[task] = true |
| 23 | + Sch.set_failed!(state, task) |
| 24 | + end |
| 25 | + empty!(state.ready) |
| 26 | + |
| 27 | + # Cancel waiting tasks |
| 28 | + for task in keys(state.waiting) |
| 29 | + tid !== nothing && task.id == tid && continue |
| 30 | + @dagdebug tid :cancel "Cancelling waiting task" |
| 31 | + state.cache[task] = InterruptException() |
| 32 | + state.errored[task] = true |
| 33 | + Sch.set_failed!(state, task) |
| 34 | + end |
| 35 | + empty!(state.waiting) |
| 36 | + |
| 37 | + # Cancel running tasks at the processor level |
| 38 | + wids = unique(map(root_worker_id, values(state.running_on))) |
| 39 | + for wid in wids |
| 40 | + remotecall_fetch(wid, tid, sch_uid, force) do _tid, sch_uid, force |
| 41 | + Dagger.Sch.proc_states(sch_uid) do states |
| 42 | + for (proc, state) in states |
| 43 | + istate = state.state |
| 44 | + any_cancelled = false |
| 45 | + @lock istate.queue begin |
| 46 | + for (tid, task) in istate.tasks |
| 47 | + _tid !== nothing && tid == _tid && continue |
| 48 | + task_spec = istate.task_specs[tid] |
| 49 | + Tf = task_spec[6] |
| 50 | + Tf === typeof(Sch.eager_thunk) && continue |
| 51 | + istaskdone(task) && continue |
| 52 | + any_cancelled = true |
| 53 | + @dagdebug tid :cancel "Cancelling running task ($Tf)" |
| 54 | + if force |
| 55 | + @dagdebug tid :cancel "Interrupting running task ($Tf)" |
| 56 | + Threads.@spawn Base.throwto(task, InterruptException()) |
| 57 | + else |
| 58 | + # Tell the processor to just drop this task |
| 59 | + task_occupancy = task_spec[4] |
| 60 | + time_util = task_spec[2] |
| 61 | + istate.proc_occupancy[] -= task_occupancy |
| 62 | + istate.time_pressure[] -= time_util |
| 63 | + push!(istate.cancelled, tid) |
| 64 | + to_proc = istate.proc |
| 65 | + put!(istate.return_queue, (myid(), to_proc, tid, (InterruptException(), nothing))) |
| 66 | + end |
| 67 | + end |
| 68 | + end |
| 69 | + if any_cancelled |
| 70 | + notify(istate.reschedule) |
| 71 | + end |
| 72 | + end |
| 73 | + end |
| 74 | + return |
| 75 | + end |
| 76 | + end |
| 77 | + |
| 78 | + if halt_sch |
| 79 | + unlock(state.lock) |
| 80 | + |
| 81 | + # Give tasks a moment to be processed |
| 82 | + sleep(0.5) |
| 83 | + |
| 84 | + # Halt the scheduler |
| 85 | + @dagdebug nothing :cancel "Halting the scheduler" |
| 86 | + notify(state.halt) |
| 87 | + put!(state.chan, (1, nothing, nothing, (Sch.SchedulerHaltedException(), nothing))) |
| 88 | + |
| 89 | + # Wait for the scheduler to halt |
| 90 | + @dagdebug nothing :cancel "Waiting for scheduler to halt" |
| 91 | + while Sch.EAGER_INIT[] |
| 92 | + sleep(0.1) |
| 93 | + end |
| 94 | + @dagdebug nothing :cancel "Scheduler halted" |
| 95 | + |
| 96 | + lock(state.lock) |
| 97 | + end |
| 98 | + |
| 99 | + return |
| 100 | +end |
0 commit comments