Skip to content

Commit

Permalink
fix #41347, better checks for yield and yieldto with finished tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson committed Jun 29, 2021
1 parent be08627 commit 8f2441e
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 6 deletions.
8 changes: 8 additions & 0 deletions base/task.jl
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ A fast, unfair-scheduling version of `schedule(t, arg); yield()` which
immediately yields to `t` before calling the scheduler.
"""
function yield(t::Task, @nospecialize(x=nothing))
(t._state === task_state_runnable && t.queue === nothing) || error("yield: Task not runnable")
t.result = x
enq_work(current_task())
set_next_task(t)
Expand All @@ -730,6 +731,13 @@ call to `yieldto`. This is a low-level call that only switches tasks, not consid
or scheduling in any way. Its use is discouraged.
"""
function yieldto(t::Task, @nospecialize(x=nothing))
# TODO: these are legacy behaviors; these should perhaps be a scheduler
# state error instead.
if t._state === task_state_done
return x
elseif t._state === task_state_failed
throw(t.result)
end
t.result = x
set_next_task(t)
return try_yieldto(identity)
Expand Down
7 changes: 1 addition & 6 deletions src/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,12 +475,7 @@ JL_DLLEXPORT void jl_switch(void)
if (t == ct) {
return;
}
if (t->_state != JL_TASK_STATE_RUNNABLE || (t->started && t->stkbuf == NULL)) {
ct->_isexception = t->_isexception;
ct->result = t->result;
jl_gc_wb(ct, ct->result);
return;
}
assert(t->_state == JL_TASK_STATE_RUNNABLE);
if (ptls->in_finalizer)
jl_error("task switch not allowed from inside gc finalizer");
if (ptls->in_pure_callback)
Expand Down
11 changes: 11 additions & 0 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,17 @@ end

@test_throws ErrorException("deadlock detected: cannot wait on current task") wait(current_task())

# issue #41347
let t = @async 1
wait(t)
@test_throws ErrorException yield(t)
end

let t = @async error(42)
Base._wait(t)
@test_throws ErrorException("42") yieldto(t)
end

# test that @sync is lexical (PR #27164)

const x27164 = Ref(0)
Expand Down

0 comments on commit 8f2441e

Please sign in to comment.