@@ -33,21 +33,30 @@ pub use timer_options::*;
33
33
// TODO: callback type prevents us from making the Timer implement the Debug trait.
34
34
// #[derive(Debug)]
35
35
pub struct Timer {
36
- pub ( crate ) rcl_timer : Arc < Mutex < rcl_timer_t > > ,
36
+ pub ( crate ) handle : TimerHandle ,
37
37
/// The callback function that runs when the timer is due.
38
38
callback : Arc < Mutex < Option < AnyTimerCallback > > > ,
39
39
/// We hold onto the Timer's clock for the whole lifespan of the Timer to
40
40
/// make sure the underlying `rcl_clock_t` remains valid.
41
- clock : Clock ,
42
41
pub ( crate ) in_use_by_wait_set : Arc < AtomicBool > ,
43
42
}
44
43
44
+ /// Manage the lifecycle of an `rcl_timer_t`, including managing its dependency
45
+ /// on `rcl_clock_t` by ensuring that this dependency are [dropped after][1]
46
+ /// the `rcl_timer_t`.
47
+ ///
48
+ /// [1]: <https://doc.rust-lang.org/reference/destructors.html>
49
+ pub ( crate ) struct TimerHandle {
50
+ pub ( crate ) rcl_timer : Arc < Mutex < rcl_timer_t > > ,
51
+ clock : Clock ,
52
+ }
53
+
45
54
impl Timer {
46
55
/// Gets the period of the timer
47
56
pub fn get_timer_period ( & self ) -> Result < Duration , RclrsError > {
48
57
let mut timer_period_ns = 0 ;
49
58
unsafe {
50
- let rcl_timer = self . rcl_timer . lock ( ) . unwrap ( ) ;
59
+ let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
51
60
rcl_timer_get_period ( & * rcl_timer, & mut timer_period_ns)
52
61
} . ok ( ) ?;
53
62
@@ -56,7 +65,7 @@ impl Timer {
56
65
57
66
/// Cancels the timer, stopping the execution of the callback
58
67
pub fn cancel ( & self ) -> Result < ( ) , RclrsError > {
59
- let mut rcl_timer = self . rcl_timer . lock ( ) . unwrap ( ) ;
68
+ let mut rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
60
69
let cancel_result = unsafe { rcl_timer_cancel ( & mut * rcl_timer) } . ok ( ) ?;
61
70
Ok ( cancel_result)
62
71
}
@@ -65,7 +74,7 @@ impl Timer {
65
74
pub fn is_canceled ( & self ) -> Result < bool , RclrsError > {
66
75
let mut is_canceled = false ;
67
76
unsafe {
68
- let rcl_timer = self . rcl_timer . lock ( ) . unwrap ( ) ;
77
+ let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
69
78
rcl_timer_is_canceled ( & * rcl_timer, & mut is_canceled)
70
79
} . ok ( ) ?;
71
80
Ok ( is_canceled)
@@ -75,7 +84,7 @@ impl Timer {
75
84
pub fn time_since_last_call ( & self ) -> Result < Duration , RclrsError > {
76
85
let mut time_value_ns: i64 = 0 ;
77
86
unsafe {
78
- let rcl_timer = self . rcl_timer . lock ( ) . unwrap ( ) ;
87
+ let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
79
88
rcl_timer_get_time_since_last_call ( & * rcl_timer, & mut time_value_ns)
80
89
} . ok ( ) ?;
81
90
@@ -86,7 +95,7 @@ impl Timer {
86
95
pub fn time_until_next_call ( & self ) -> Result < Duration , RclrsError > {
87
96
let mut time_value_ns: i64 = 0 ;
88
97
unsafe {
89
- let rcl_timer = self . rcl_timer . lock ( ) . unwrap ( ) ;
98
+ let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
90
99
rcl_timer_get_time_until_next_call ( & * rcl_timer, & mut time_value_ns)
91
100
} . ok ( ) ?;
92
101
@@ -95,15 +104,15 @@ impl Timer {
95
104
96
105
/// Resets the timer.
97
106
pub fn reset ( & self ) -> Result < ( ) , RclrsError > {
98
- let mut rcl_timer = self . rcl_timer . lock ( ) . unwrap ( ) ;
107
+ let mut rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
99
108
unsafe { rcl_timer_reset ( & mut * rcl_timer) } . ok ( )
100
109
}
101
110
102
111
/// Checks if the timer is ready (not canceled)
103
112
pub fn is_ready ( & self ) -> Result < bool , RclrsError > {
104
113
let is_ready = unsafe {
105
114
let mut is_ready: bool = false ;
106
- let rcl_timer = self . rcl_timer . lock ( ) . unwrap ( ) ;
115
+ let rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
107
116
rcl_timer_is_ready ( & * rcl_timer, & mut is_ready) . ok ( ) ?;
108
117
is_ready
109
118
} ;
@@ -173,23 +182,27 @@ impl Timer {
173
182
callback : AnyTimerCallback ,
174
183
) -> Result < Timer , RclrsError > {
175
184
let period = period. as_nanos ( ) as i64 ;
176
- let mut rcl_clock = clock. get_rcl_clock ( ) . lock ( ) . unwrap ( ) ;
177
- let mut rcl_context = context. rcl_context . lock ( ) . unwrap ( ) ;
178
185
179
186
// Callbacks will be handled at the rclrs layer.
180
187
let rcl_timer_callback: rcl_timer_callback_t = None ;
181
188
182
- let mut rcl_timer;
189
+ let rcl_timer = Arc :: new ( Mutex :: new (
190
+ // SAFETY: Zero-initializing a timer is always safe
191
+ unsafe { rcl_get_zero_initialized_timer ( ) }
192
+ ) ) ;
193
+
183
194
unsafe {
195
+ let mut rcl_clock = clock. get_rcl_clock ( ) . lock ( ) . unwrap ( ) ;
196
+ let mut rcl_context = context. rcl_context . lock ( ) . unwrap ( ) ;
197
+
184
198
// SAFETY: Getting a default value is always safe.
185
- rcl_timer = rcl_get_zero_initialized_timer ( ) ;
186
199
let allocator = rcutils_get_default_allocator ( ) ;
187
200
188
201
let _lifecycle = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
189
202
// SAFETY: We lock the lifecycle mutex since rcl_timer_init is not
190
203
// thread-safe.
191
204
rcl_timer_init (
192
- & mut rcl_timer,
205
+ & mut * rcl_timer. lock ( ) . unwrap ( ) ,
193
206
& mut * rcl_clock,
194
207
& mut * rcl_context,
195
208
period,
@@ -199,9 +212,8 @@ impl Timer {
199
212
} . ok ( ) ?;
200
213
201
214
let timer = Timer {
202
- rcl_timer : Arc :: new ( Mutex :: new ( rcl_timer) ) ,
215
+ handle : TimerHandle { rcl_timer, clock } ,
203
216
callback : Arc :: new ( Mutex :: new ( Some ( callback) ) ) ,
204
- clock : clock. clone ( ) ,
205
217
in_use_by_wait_set : Arc :: new ( AtomicBool :: new ( false ) ) ,
206
218
} ;
207
219
Ok ( timer)
@@ -253,7 +265,7 @@ impl Timer {
253
265
/// in the [`Timer`] struct. This means there are no side-effects to this
254
266
/// except to keep track of when the timer has been called.
255
267
fn rcl_call ( & self ) -> Result < ( ) , RclrsError > {
256
- let mut rcl_timer = self . rcl_timer . lock ( ) . unwrap ( ) ;
268
+ let mut rcl_timer = self . handle . rcl_timer . lock ( ) . unwrap ( ) ;
257
269
unsafe { rcl_timer_call ( & mut * rcl_timer) } . ok ( )
258
270
}
259
271
@@ -268,16 +280,18 @@ impl Timer {
268
280
}
269
281
270
282
/// 'Drop' trait implementation to be able to release the resources
271
- impl Drop for rcl_timer_t {
283
+ impl Drop for TimerHandle {
272
284
fn drop ( & mut self ) {
273
- // SAFETY: No preconditions for this function
274
- unsafe { rcl_timer_fini ( & mut * self ) } ;
285
+ let _lifecycle = ENTITY_LIFECYCLE_MUTEX . lock ( ) . unwrap ( ) ;
286
+ // SAFETY: The lifecycle mutex is locked and the clock for the timer
287
+ // must still be valid because TimerHandle keeps it alive.
288
+ unsafe { rcl_timer_fini ( & mut * self . rcl_timer . lock ( ) . unwrap ( ) ) } ;
275
289
}
276
290
}
277
291
278
292
impl PartialEq for Timer {
279
293
fn eq ( & self , other : & Self ) -> bool {
280
- Arc :: ptr_eq ( & self . rcl_timer , & other. rcl_timer )
294
+ Arc :: ptr_eq ( & self . handle . rcl_timer , & other. handle . rcl_timer )
281
295
}
282
296
}
283
297
@@ -334,7 +348,7 @@ mod tests {
334
348
fn test_new_with_source_clock ( ) {
335
349
let ( clock, source) = Clock :: with_source ( ) ;
336
350
// No manual time set, it should default to 0
337
- assert ! ( clock. now( ) . nsec == 0 ) ;
351
+ assert_eq ! ( clock. now( ) . nsec, 0 ) ;
338
352
let set_time = 1234i64 ;
339
353
source. set_ros_time_override ( set_time) ;
340
354
0 commit comments