Skip to content

Commit

Permalink
Clarify wait(::Task) documentation (JuliaLang#53722)
Browse files Browse the repository at this point in the history
Small follow-up to JuliaLang#53685, since
having critical documentation for a specific method be only mentioned in
a catch-all docstring isn't quite as helpful as it could be (e.g. when
looking at inline documentation with LSP, where it happens to know that
the variable being passed is a `Task`). In addition, this also documents
that `wait` on a `Task` will throw if given `current_task`.

I've also split the function into a prototype and the actual
implementation, so that the same "more specific docs at the method
definition" transform can be applied for `GenericCondition` too.
  • Loading branch information
Seelengrab committed Apr 16, 2024
1 parent f259eba commit 824ceef
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 10 deletions.
23 changes: 15 additions & 8 deletions base/condition.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,16 @@ end
"""
wait([x])
Block the current task until some event occurs, depending on the type of the argument:
Block the current task until some event occurs.
* [`Channel`](@ref): Wait for a value to be appended to the channel.
* [`Condition`](@ref): Wait for [`notify`](@ref) on a condition and return the `val`
parameter passed to `notify`. Waiting on a condition additionally allows passing
`first=true` which results in the waiter being put _first_ in line to wake up on `notify`
instead of the usual first-in-first-out behavior.
parameter passed to `notify`. See the `Condition`-specific docstring of `wait` for
the exact behavior.
* `Process`: Wait for a process or process chain to exit. The `exitcode` field of a process
can be used to determine success or failure.
* [`Task`](@ref): Wait for a `Task` to finish. If the task fails with an exception, a
`TaskFailedException` (which wraps the failed task) is thrown. Waiting on a task
additionally allows passing `throw=false` which prevents throwing a `TaskFailedException`
when the task fails.
* [`Task`](@ref): Wait for a `Task` to finish. See the `Task`-specific docstring of `wait` for
the exact behavior.
* [`RawFD`](@ref): Wait for changes on a file descriptor (see the `FileWatching` package).
If no argument is passed, the task blocks for an undefined period. A task can only be
Expand All @@ -124,6 +121,16 @@ restarted by an explicit call to [`schedule`](@ref) or [`yieldto`](@ref).
Often `wait` is called within a `while` loop to ensure a waited-for condition is met before
proceeding.
"""
function wait end

"""
wait(c::GenericCondition; first::Bool=false)
Wait for [`notify`](@ref) on `c` and return the `val` parameter passed to `notify`.
If the keyword `first` is set to `true`, the waiter will be put _first_
in line to wake up on `notify`. Otherwise, `wait` has first-in-first-out (FIFO) behavior.
"""
function wait(c::GenericCondition; first::Bool=false)
ct = current_task()
_wait2(c, ct, first)
Expand Down
12 changes: 11 additions & 1 deletion base/task.jl
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,18 @@ function _wait2(t::Task, waiter::Task)
nothing
end

"""
wait(t::Task; throw=true)
Wait for a `Task` to finish.
The keyword `throw` (defaults to `true`) controls whether a failed task results
in an error, thrown as a [`TaskFailedException`](@ref) which wraps the failed task.
Throws a `ConcurrencyViolationError` if `t` is the currently running task, to prevent deadlocks.
"""
function wait(t::Task; throw=true)
t === current_task() && error("deadlock detected: cannot wait on current task")
t === current_task() && Core.throw(ConcurrencyViolationError("deadlock detected: cannot wait on current task"))
_wait(t)
if throw && istaskfailed(t)
Core.throw(TaskFailedException(t))
Expand Down
2 changes: 1 addition & 1 deletion test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ let c = Ref(0),
@test c[] == 100
end

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

# issue #41347
let t = @async 1
Expand Down

0 comments on commit 824ceef

Please sign in to comment.