Skip to content

Commit 68b6446

Browse files
jpsamarooJamesWrigley
authored andcommitted
cancellation: Add graceful vs. forced
1 parent 4de81b2 commit 68b6446

File tree

2 files changed

+32
-15
lines changed

2 files changed

+32
-15
lines changed

src/cancellation.jl

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
# DTask-level cancellation
22

3-
struct CancelToken
4-
cancelled::Base.RefValue{Bool}
3+
mutable struct CancelToken
4+
@atomic cancelled::Bool
5+
@atomic graceful::Bool
56
event::Base.Event
67
end
7-
CancelToken() = CancelToken(Ref(false), Base.Event())
8-
function cancel!(token::CancelToken)
9-
token.cancelled[] = true
8+
CancelToken() = CancelToken(false, false, Base.Event())
9+
function cancel!(token::CancelToken; graceful::Bool=true)
10+
if !graceful
11+
@atomic token.graceful = false
12+
end
13+
@atomic token.cancelled = true
1014
notify(token.event)
1115
return
1216
end
13-
is_cancelled(token::CancelToken) = token.cancelled[]
17+
function is_cancelled(token::CancelToken; must_force::Bool=false)
18+
if token.cancelled[]
19+
if must_force && token.graceful[]
20+
# If we're only responding to forced cancellation, ignore graceful cancellations
21+
return false
22+
end
23+
return true
24+
end
25+
return false
26+
end
1427
Base.wait(token::CancelToken) = wait(token.event)
1528
# TODO: Enable this for safety
1629
#Serialization.serialize(io::AbstractSerializer, ::CancelToken) =
@@ -128,7 +141,7 @@ function _cancel!(state, tid, force, halt_sch)
128141
push!(istate.cancelled, tid)
129142
to_proc = istate.proc
130143
put!(istate.return_queue, (myid(), to_proc, tid, (InterruptException(), nothing)))
131-
cancel!(istate.cancel_tokens[tid])
144+
cancel!(istate.cancel_tokens[tid]; graceful=false)
132145
end
133146
end
134147
end

src/task-tls.jl

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,30 @@ task_processor() = get_tls().processor
5252
@deprecate(thunk_processor(), task_processor())
5353

5454
"""
55-
task_cancelled() -> Bool
55+
task_cancelled(; must_force::Bool=false) -> Bool
5656
5757
Returns `true` if the current [`DTask`](@ref) has been cancelled, else `false`.
58+
If `must_force=true`, then only return `true` if the cancellation was forced.
5859
"""
59-
task_cancelled() = is_cancelled(get_tls().cancel_token)
60+
task_cancelled(; must_force::Bool=false) =
61+
is_cancelled(get_tls().cancel_token; must_force)
6062

6163
"""
62-
task_may_cancel!()
64+
task_may_cancel!(; must_force::Bool=false)
6365
6466
Throws an `InterruptException` if the current [`DTask`](@ref) has been cancelled.
67+
If `must_force=true`, then only throw if the cancellation was forced.
6568
"""
66-
function task_may_cancel!()
67-
if task_cancelled()
69+
function task_may_cancel!(;must_force::Bool=false)
70+
if task_cancelled(;must_force)
6871
throw(InterruptException())
6972
end
7073
end
7174

7275
"""
73-
task_cancel!()
76+
task_cancel!(; graceful::Bool=true)
7477
75-
Cancels the current [`DTask`](@ref).
78+
Cancels the current [`DTask`](@ref). If `graceful=true`, then the task will be
79+
cancelled gracefully, otherwise it will be forced.
7680
"""
77-
task_cancel!() = cancel!(get_tls().cancel_token)
81+
task_cancel!(; graceful::Bool=true) = cancel!(get_tls().cancel_token; graceful)

0 commit comments

Comments
 (0)