From c37ee02026ce4aeb3ab77ecf89f49d6a3f3d5d1f Mon Sep 17 00:00:00 2001 From: Sukera Date: Sat, 6 Apr 2024 09:28:22 +0200 Subject: [PATCH] Throw `ConcurrencyViolationError` on `yield` & `throwto` with `current_task` Previously, this errored with a nasty type assert *somewhere* in the runtime. Throwing a proper `ConcurrencyViolationError` allows this to be debugged, and makes the error condition known. --- base/task.jl | 10 ++++++++-- test/misc.jl | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/base/task.jl b/base/task.jl index 90f74441c7fbda..3aba7c418eb03e 100644 --- a/base/task.jl +++ b/base/task.jl @@ -1040,11 +1040,15 @@ end A fast, unfair-scheduling version of `schedule(t, arg); yield()` which immediately yields to `t` before calling the scheduler. + +Throws a `ConcurrencyViolationError` if `t` is the currently running task. """ function yield(t::Task, @nospecialize(x=nothing)) - (t._state === task_state_runnable && t.queue === nothing) || error("yield: Task not runnable") + current = current_task() + t === current && throw(ConcurrencyViolationError("Cannot yield to currently running task!")) + (t._state === task_state_runnable && t.queue === nothing) || error("yield: Task not runnable $t") t.result = x - enq_work(current_task()) + enq_work(current) set_next_task(t) return try_yieldto(ensure_rescheduled) end @@ -1091,6 +1095,8 @@ end # yield to a task, throwing an exception in it function throwto(t::Task, @nospecialize exc) + current = current_task() + t === current && throw(ConcurrencyViolationError("Cannot throw an exception to the currently running task!")) t.result = exc t._isexception = true set_next_task(t) diff --git a/test/misc.jl b/test/misc.jl index e870c7f491c139..e20b5819418579 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -253,6 +253,9 @@ end @test_throws ErrorException("deadlock detected: cannot wait on current task") wait(current_task()) +@test_throws ConcurrencyViolationError("Cannot yield to currently running task!") yield(current_task()) +@test_throws ConcurrencyViolationError("Cannot throw an exception to the currently running task!") throwto(current_task(), ArgumentError()) + # issue #41347 let t = @async 1 wait(t)