6060
6161Create a timer that wakes up tasks waiting for it (by calling [`wait`](@ref) on the timer object).
6262
63- Waiting tasks are woken after an initial delay of `delay` seconds, and then repeating with the given
64- `interval` in seconds. If `interval` is equal to `0`, the timer is only triggered once. When
65- the timer is closed (by [`close`](@ref)) waiting tasks are woken with an error. Use [`isopen`](@ref)
66- to check whether a timer is still active.
63+ Waiting tasks are woken after an initial delay of at least `delay` seconds, and then repeating after
64+ at least `interval` seconds again elapse. If `interval` is equal to `0`, the timer is only triggered
65+ once. When the timer is closed (by [`close`](@ref)) waiting tasks are woken with an error. Use
66+ [`isopen`](@ref) to check whether a timer is still active.
67+
68+ Note: `interval` is subject to accumulating time skew. If you need precise events at a particular
69+ absolute time, create a new timer at each expiration with the difference to the next time computed.
6770"""
6871mutable struct Timer
6972 handle:: Ptr{Cvoid}
@@ -74,8 +77,9 @@ mutable struct Timer
7477 function Timer (timeout:: Real ; interval:: Real = 0.0 )
7578 timeout ≥ 0 || throw (ArgumentError (" timer cannot have negative timeout of $timeout seconds" ))
7679 interval ≥ 0 || throw (ArgumentError (" timer cannot have negative repeat interval of $interval seconds" ))
77- timeout = UInt64 (round (timeout * 1000 )) + 1
78- interval = UInt64 (ceil (interval * 1000 ))
80+ # libuv has a tendency to timeout 1 ms early, so we need +1 on the timeout (in milliseconds), unless it is zero
81+ timeoutms = ceil (UInt64, timeout * 1000 ) + ! iszero (timeout)
82+ intervalms = ceil (UInt64, interval * 1000 )
7983 loop = eventloop ()
8084
8185 this = new (Libc. malloc (_sizeof_uv_timer), ThreadSynchronizer (), true , false )
@@ -87,7 +91,7 @@ mutable struct Timer
8791 ccall (:uv_update_time , Cvoid, (Ptr{Cvoid},), loop)
8892 err = ccall (:uv_timer_start , Cint, (Ptr{Cvoid}, Ptr{Cvoid}, UInt64, UInt64),
8993 this, @cfunction (uv_timercb, Cvoid, (Ptr{Cvoid},)),
90- timeout, interval )
94+ timeoutms, intervalms )
9195 @assert err == 0
9296 iolock_end ()
9397 return this
@@ -222,18 +226,18 @@ end
222226"""
223227 Timer(callback::Function, delay; interval = 0)
224228
225- Create a timer that wakes up tasks waiting for it (by calling [`wait`](@ref) on the timer object) and
226- calls the function `callback`.
229+ Create a timer that runs the function `callback` at each timer expiration.
227230
228- Waiting tasks are woken and the function `callback` is called after an initial delay of `delay` seconds,
229- and then repeating with the given `interval` in seconds. If `interval` is equal to `0`, the timer
230- is only triggered once. The function `callback` is called with a single argument, the timer itself.
231- When the timer is closed ( by [ `close`](@ref)) waiting tasks are woken with an error. Use [`isopen`](@ref)
232- to check whether a timer is still active .
231+ Waiting tasks are woken and the function `callback` is called after an initial delay of `delay`
232+ seconds, and then repeating with the given `interval` in seconds. If `interval` is equal to `0`, the
233+ callback is only run once. The function `callback` is called with a single argument, the timer
234+ itself. Stop a timer by calling `close`. The `cb` may still be run one final time, if the timer has
235+ already expired .
233236
234237# Examples
235238
236- Here the first number is printed after a delay of two seconds, then the following numbers are printed quickly.
239+ Here the first number is printed after a delay of two seconds, then the following numbers are
240+ printed quickly.
237241
238242```julia-repl
239243julia> begin
0 commit comments