57
57
58
58
Create a timer that wakes up tasks waiting for it (by calling [`wait`](@ref) on the timer object).
59
59
60
- Waiting tasks are woken after an initial delay of `delay` seconds, and then repeating with the given
61
- `interval` in seconds. If `interval` is equal to `0`, the timer is only triggered once. When
62
- the timer is closed (by [`close`](@ref)) waiting tasks are woken with an error. Use [`isopen`](@ref)
63
- to check whether a timer is still active.
60
+ Waiting tasks are woken after an initial delay of at least `delay` seconds, and then repeating after
61
+ at least `interval` seconds again elapse. If `interval` is equal to `0`, the timer is only triggered
62
+ once. When the timer is closed (by [`close`](@ref)) waiting tasks are woken with an error. Use
63
+ [`isopen`](@ref) to check whether a timer is still active.
64
+
65
+ Note: `interval` is subject to accumulating time skew. If you need precise events at a particular
66
+ absolute time, create a new timer at each expiration with the difference to the next time computed.
64
67
"""
65
68
mutable struct Timer
66
69
handle:: Ptr{Cvoid}
@@ -71,8 +74,9 @@ mutable struct Timer
71
74
function Timer (timeout:: Real ; interval:: Real = 0.0 )
72
75
timeout ≥ 0 || throw (ArgumentError (" timer cannot have negative timeout of $timeout seconds" ))
73
76
interval ≥ 0 || throw (ArgumentError (" timer cannot have negative repeat interval of $interval seconds" ))
74
- timeout = UInt64 (round (timeout * 1000 )) + 1
75
- interval = UInt64 (round (interval * 1000 ))
77
+ # libuv has a tendency to timeout 1 ms early, so we need +1 on the timeout (in milliseconds), unless it is zero
78
+ timeoutms = ceil (UInt64, timeout * 1000 ) + ! iszero (timeout)
79
+ intervalms = ceil (UInt64, interval * 1000 )
76
80
loop = eventloop ()
77
81
78
82
this = new (Libc. malloc (_sizeof_uv_timer), ThreadSynchronizer (), true , false )
@@ -84,7 +88,7 @@ mutable struct Timer
84
88
ccall (:uv_update_time , Cvoid, (Ptr{Cvoid},), loop)
85
89
err = ccall (:uv_timer_start , Cint, (Ptr{Cvoid}, Ptr{Cvoid}, UInt64, UInt64),
86
90
this, @cfunction (uv_timercb, Cvoid, (Ptr{Cvoid},)),
87
- timeout, interval )
91
+ timeoutms, intervalms )
88
92
@assert err == 0
89
93
iolock_end ()
90
94
return this
@@ -219,18 +223,18 @@ end
219
223
"""
220
224
Timer(callback::Function, delay; interval = 0)
221
225
222
- Create a timer that wakes up tasks waiting for it (by calling [`wait`](@ref) on the timer object) and
223
- calls the function `callback`.
226
+ Create a timer that runs the function `callback` at each timer expiration.
224
227
225
- Waiting tasks are woken and the function `callback` is called after an initial delay of `delay` seconds,
226
- and then repeating with the given `interval` in seconds. If `interval` is equal to `0`, the timer
227
- is only triggered once. The function `callback` is called with a single argument, the timer itself.
228
- When the timer is closed ( by [ `close`](@ref)) waiting tasks are woken with an error. Use [`isopen`](@ref)
229
- to check whether a timer is still active .
228
+ Waiting tasks are woken and the function `callback` is called after an initial delay of `delay`
229
+ seconds, and then repeating with the given `interval` in seconds. If `interval` is equal to `0`, the
230
+ callback is only run once. The function `callback` is called with a single argument, the timer
231
+ itself. Stop a timer by calling `close`. The `cb` may still be run one final time, if the timer has
232
+ already expired .
230
233
231
234
# Examples
232
235
233
- Here the first number is printed after a delay of two seconds, then the following numbers are printed quickly.
236
+ Here the first number is printed after a delay of two seconds, then the following numbers are
237
+ printed quickly.
234
238
235
239
```julia-repl
236
240
julia> begin
0 commit comments