From 0221ebc9b1460230d11407ea747b6bca99d67271 Mon Sep 17 00:00:00 2001 From: Sukera Date: Sat, 6 Apr 2024 09:28:22 +0200 Subject: [PATCH 1/3] 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 90f74441c7fbd..f469ddd7b39c7 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) || throw(ConcurrencyViolationError("yield: Task not runnable")) 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 e870c7f491c13..e20b581941857 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) From 6280d38e0cbf708a9041ab11f166d1c9bbc4082c Mon Sep 17 00:00:00 2001 From: Sukera Date: Sat, 6 Apr 2024 12:01:15 +0200 Subject: [PATCH 2/3] Check that the correct error is thrown --- test/misc.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/misc.jl b/test/misc.jl index e20b581941857..aeca80fc1f2aa 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -254,12 +254,12 @@ 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()) +@test_throws ConcurrencyViolationError("Cannot throw an exception to the currently running task!") Base.throwto(current_task(), ArgumentError()) # issue #41347 let t = @async 1 wait(t) - @test_throws ErrorException yield(t) + @test_throws ConcurrencyViolationError yield(t) end let t = @async error(42) From 41d026beafd303bea592e89b688e417139b20571 Mon Sep 17 00:00:00 2001 From: Sukera Date: Sat, 6 Apr 2024 14:36:38 +0200 Subject: [PATCH 3/3] Remove incorrect throw in `throwto` --- base/task.jl | 2 -- test/misc.jl | 1 - 2 files changed, 3 deletions(-) diff --git a/base/task.jl b/base/task.jl index f469ddd7b39c7..653153478108e 100644 --- a/base/task.jl +++ b/base/task.jl @@ -1095,8 +1095,6 @@ 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 aeca80fc1f2aa..4a09015b0dc88 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -254,7 +254,6 @@ 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!") Base.throwto(current_task(), ArgumentError()) # issue #41347 let t = @async 1