diff --git a/stdlib/FileWatching/src/FileWatching.jl b/stdlib/FileWatching/src/FileWatching.jl index 1c8a684310feca..d929d1ebfb98d2 100644 --- a/stdlib/FileWatching/src/FileWatching.jl +++ b/stdlib/FileWatching/src/FileWatching.jl @@ -254,6 +254,10 @@ mutable struct _FDWatcher end end +function iswaiting(fwd::_FDWatcher, t::Task) + return fwd.notify.waitq === t.queue +end + mutable struct FDWatcher watcher::_FDWatcher readable::Bool @@ -653,10 +657,10 @@ function poll_fd(s::Union{RawFD, Sys.iswindows() ? WindowsRawSocket : Union{}}, try if timeout_s >= 0 result::FDEvent = FDEvent() - timer = Timer(timeout_s) do t - notify(wt) - end - @async begin + t = @async begin + timer = Timer(timeout_s) do t + notify(wt) + end try result = wait(fdw, readable=readable, writable=writable) catch e @@ -666,6 +670,12 @@ function poll_fd(s::Union{RawFD, Sys.iswindows() ? WindowsRawSocket : Union{}}, notify(wt) end wait(wt) + # It's possible that both the timer and the poll fired on the same + # libuv loop. In that case, which event we see here first depends + # on task schedule order. If we can see that the task isn't waiting + # on the file watcher anymore, just let it finish so we can see + # the modification to `result` + iswaiting(fdw, t) || wait(t) return result else return wait(fdw, readable=readable, writable=writable) diff --git a/stdlib/FileWatching/test/runtests.jl b/stdlib/FileWatching/test/runtests.jl index deee66cf529977..345ffce07482f6 100644 --- a/stdlib/FileWatching/test/runtests.jl +++ b/stdlib/FileWatching/test/runtests.jl @@ -12,7 +12,7 @@ using Base: uv_error, Experimental # Writable ends are always tested for write-ability before a write n = 20 -intvls = [2, .2, .1, .005] +intvls = [2, .2, .1, .005, .00001] pipe_fds = fill((Base.INVALID_OS_HANDLE, Base.INVALID_OS_HANDLE), n) for i in 1:n