-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
asyncevents: fix missing GC root and race #44956
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,13 +45,22 @@ the async condition object itself. | |
""" | ||
function AsyncCondition(cb::Function) | ||
async = AsyncCondition() | ||
t = @task while _trywait(async) | ||
cb(async) | ||
isopen(async) || return | ||
t = @task begin | ||
unpreserve_handle(async) | ||
while _trywait(async) | ||
cb(async) | ||
isopen(async) || return | ||
end | ||
end | ||
# here we are mimicking parts of _trywait, in coordination with task `t` | ||
preserve_handle(async) | ||
@lock async.cond begin | ||
if async.set | ||
schedule(t) | ||
else | ||
_wait2(async.cond, t) | ||
end | ||
end | ||
lock(async.cond) | ||
_wait2(async.cond, t) | ||
unlock(async.cond) | ||
return async | ||
end | ||
|
||
|
@@ -115,6 +124,7 @@ function _trywait(t::Union{Timer, AsyncCondition}) | |
# full barrier now for AsyncCondition | ||
t isa Timer || Core.Intrinsics.atomic_fence(:acquire_release) | ||
else | ||
t.isopen || return false | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is outside a lock, don't we need to acquire load/release store There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's conceivable that someone writes async = AsyncCondition()
t1 = @spawn begin # code in external library
f1()
ccall(:uv_async_send, Cvoid, (Ptr{Cvoid},), async)
end
t2 = @spawn begin
try
wait(async)
catch err
err isa EOFError || rethrow()
end
close(async)
f2()
end
t3 = @spawn begin
try
wait(async)
catch err
err isa EOFError || rethrow()
end
close(async)
f3()
end and expect But I'm also OK with documenting that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Establishing happens-before seems like a good idea. We don't do that currently, so it is not relevant to this PR however. |
||
t.handle == C_NULL && return false | ||
iolock_begin() | ||
set = t.set | ||
|
@@ -123,14 +133,12 @@ function _trywait(t::Union{Timer, AsyncCondition}) | |
lock(t.cond) | ||
try | ||
set = t.set | ||
if !set | ||
if t.handle != C_NULL | ||
iolock_end() | ||
set = wait(t.cond) | ||
unlock(t.cond) | ||
iolock_begin() | ||
lock(t.cond) | ||
end | ||
if !set && t.isopen && t.handle != C_NULL | ||
iolock_end() | ||
set = wait(t.cond) | ||
unlock(t.cond) | ||
iolock_begin() | ||
lock(t.cond) | ||
end | ||
finally | ||
unlock(t.cond) | ||
|
@@ -266,19 +274,28 @@ julia> begin | |
""" | ||
function Timer(cb::Function, timeout::Real; interval::Real=0.0) | ||
timer = Timer(timeout, interval=interval) | ||
t = @task while _trywait(timer) | ||
try | ||
cb(timer) | ||
catch err | ||
write(stderr, "Error in Timer:\n") | ||
showerror(stderr, err, catch_backtrace()) | ||
return | ||
t = @task begin | ||
unpreserve_handle(timer) | ||
while _trywait(timer) | ||
try | ||
cb(timer) | ||
catch err | ||
write(stderr, "Error in Timer:\n") | ||
showerror(stderr, err, catch_backtrace()) | ||
return | ||
end | ||
isopen(timer) || return | ||
end | ||
end | ||
# here we are mimicking parts of _trywait, in coordination with task `t` | ||
preserve_handle(timer) | ||
@lock timer.cond begin | ||
if timer.set | ||
schedule(t) | ||
else | ||
_wait2(timer.cond, t) | ||
end | ||
isopen(timer) || return | ||
end | ||
lock(timer.cond) | ||
_wait2(timer.cond, t) | ||
unlock(timer.cond) | ||
return timer | ||
end | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't
async
reachable throught.code
? Why would it be finalized in the old code?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t is only reachable through async
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahhhh