Skip to content

Commit a589997

Browse files
committed
Add safety comments
Signed-off-by: Michael X. Grey <[email protected]>
1 parent 82f4da6 commit a589997

File tree

1 file changed

+72
-13
lines changed

1 file changed

+72
-13
lines changed

rclrs/src/timer.rs

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,26 +86,50 @@ impl<Scope: WorkScope> TimerState<Scope> {
8686
pub fn get_timer_period(&self) -> Result<Duration, RclrsError> {
8787
let mut timer_period_ns = 0;
8888
unsafe {
89+
// SAFETY: The unwrap is safe here since we never use the rcl_timer
90+
// in a way that could panic while the mutex is locked.
8991
let rcl_timer = self.handle.rcl_timer.lock().unwrap();
92+
93+
// SAFETY: The rcl_timer is kept valid by the TimerState. This C
94+
// function call is thread-safe and only requires a valid rcl_timer
95+
// to be passed in.
9096
rcl_timer_get_period(&*rcl_timer, &mut timer_period_ns)
9197
}
9298
.ok()?;
9399

94100
rcl_duration(timer_period_ns)
95101
}
96102

97-
/// Cancels the timer, stopping the execution of the callback
103+
/// Cancels the timer, stopping the execution of the callback.
104+
///
105+
/// [`TimerState::is_ready`] will always return false while the timer is in
106+
/// a cancelled state. [`TimerState::reset`] can be used to revert the timer
107+
/// out of the cancelled state.
98108
pub fn cancel(&self) -> Result<(), RclrsError> {
99-
let mut rcl_timer = self.handle.rcl_timer.lock().unwrap();
100-
let cancel_result = unsafe { rcl_timer_cancel(&mut *rcl_timer) }.ok()?;
109+
let cancel_result = unsafe {
110+
// SAFETY: The unwrap is safe here since we never use the rcl_timer
111+
// in a way that could panic while the mutex is locked.
112+
let mut rcl_timer = self.handle.rcl_timer.lock().unwrap();
113+
114+
// SAFETY: The rcl_timer is kept valid by the TimerState. This C
115+
// function call is thread-safe and only requires a valid rcl_timer
116+
// to be passed in.
117+
rcl_timer_cancel(&mut *rcl_timer)
118+
}.ok()?;
101119
Ok(cancel_result)
102120
}
103121

104122
/// Checks whether the timer is canceled or not
105123
pub fn is_canceled(&self) -> Result<bool, RclrsError> {
106124
let mut is_canceled = false;
107125
unsafe {
126+
// SAFETY: The unwrap is safe here since we never use the rcl_timer
127+
// in a way that could panic while the mutex is locked.
108128
let rcl_timer = self.handle.rcl_timer.lock().unwrap();
129+
130+
// SAFETY: The rcl_timer is kept valid by the TimerState. This C
131+
// function call is thread-safe and only requires a valid rcl_timer
132+
// to be passed in.
109133
rcl_timer_is_canceled(&*rcl_timer, &mut is_canceled)
110134
}
111135
.ok()?;
@@ -128,7 +152,13 @@ impl<Scope: WorkScope> TimerState<Scope> {
128152
pub fn time_since_last_call(&self) -> Result<Duration, RclrsError> {
129153
let mut time_value_ns: i64 = 0;
130154
unsafe {
155+
// SAFETY: The unwrap is safe here since we never use the rcl_timer
156+
// in a way that could panic while the mutex is locked.
131157
let rcl_timer = self.handle.rcl_timer.lock().unwrap();
158+
159+
// SAFETY: The rcl_timer is kept valid by the TimerState. This C
160+
// function call is thread-safe and only requires a valid rcl_timer
161+
// to be passed in.
132162
rcl_timer_get_time_since_last_call(&*rcl_timer, &mut time_value_ns)
133163
}
134164
.ok()?;
@@ -140,7 +170,13 @@ impl<Scope: WorkScope> TimerState<Scope> {
140170
pub fn time_until_next_call(&self) -> Result<Duration, RclrsError> {
141171
let mut time_value_ns: i64 = 0;
142172
unsafe {
173+
// SAFETY: The unwrap is safe here since we never use the rcl_timer
174+
// in a way that could panic while the mutex is locked.
143175
let rcl_timer = self.handle.rcl_timer.lock().unwrap();
176+
177+
// SAFETY: The rcl_timer is kept valid by the TimerState. This C
178+
// function call is thread-safe and only requires a valid rcl_timer
179+
// to be passed in.
144180
rcl_timer_get_time_until_next_call(&*rcl_timer, &mut time_value_ns)
145181
}
146182
.ok()?;
@@ -149,9 +185,20 @@ impl<Scope: WorkScope> TimerState<Scope> {
149185
}
150186

151187
/// Resets the timer.
188+
///
189+
/// For all timers it will reset the last call time to now. For cancelled
190+
/// timers it will revert the timer to no longer being cancelled.
152191
pub fn reset(&self) -> Result<(), RclrsError> {
192+
// SAFETY: The unwrap is safe here since we never use the rcl_timer
193+
// in a way that could panic while the mutex is locked.
153194
let mut rcl_timer = self.handle.rcl_timer.lock().unwrap();
154-
unsafe { rcl_timer_reset(&mut *rcl_timer) }.ok()
195+
196+
unsafe {
197+
// SAFETY: The rcl_timer is kept valid by the TimerState. This C
198+
// function call is thread-safe and only requires a valid rcl_timer
199+
// to be passed in.
200+
rcl_timer_reset(&mut *rcl_timer)
201+
}.ok()
155202
}
156203

157204
/// Checks if the timer is ready (not canceled)
@@ -215,8 +262,10 @@ impl<Scope: WorkScope> TimerState<Scope> {
215262
let rcl_timer_callback: rcl_timer_callback_t = None;
216263

217264
let rcl_timer = Arc::new(Mutex::new(
218-
// SAFETY: Zero-initializing a timer is always safe
219-
unsafe { rcl_get_zero_initialized_timer() },
265+
unsafe {
266+
// SAFETY: Zero-initializing a timer is always safe
267+
rcl_get_zero_initialized_timer()
268+
},
220269
));
221270

222271
unsafe {
@@ -340,8 +389,16 @@ impl<Scope: WorkScope> TimerState<Scope> {
340389
/// in the [`Timer`] struct. This means there are no side-effects to this
341390
/// except to keep track of when the timer has been called.
342391
fn rcl_call(&self) -> Result<(), RclrsError> {
392+
// SAFETY: The unwrap is safe here since we never use the rcl_timer
393+
// in a way that could panic while the mutex is locked.
343394
let mut rcl_timer = self.handle.rcl_timer.lock().unwrap();
344-
unsafe { rcl_timer_call(&mut *rcl_timer) }.ok()
395+
396+
unsafe {
397+
// SAFETY: The rcl_timer is kept valid by the TimerState. This C
398+
// function call is thread-safe and only requires a valid rcl_timer
399+
// to be passed in.
400+
rcl_timer_call(&mut *rcl_timer)
401+
}.ok()
345402
}
346403

347404
/// Used by [`Timer::execute`] to restore the state of the callback if and
@@ -469,15 +526,17 @@ pub(crate) struct TimerHandle {
469526
impl Drop for TimerHandle {
470527
fn drop(&mut self) {
471528
let _lifecycle = ENTITY_LIFECYCLE_MUTEX.lock().unwrap();
472-
// SAFETY: The lifecycle mutex is locked and the clock for the timer
473-
// must still be valid because TimerHandle keeps it alive.
474-
unsafe { rcl_timer_fini(&mut *self.rcl_timer.lock().unwrap()) };
529+
unsafe {
530+
// SAFETY: The lifecycle mutex is locked and the clock for the timer
531+
// must still be valid because TimerHandle keeps it alive.
532+
rcl_timer_fini(&mut *self.rcl_timer.lock().unwrap())
533+
};
475534
}
476535
}
477536

478537
// SAFETY: The functions accessing this type, including drop(), shouldn't care about the thread
479538
// they are running in. Therefore, this type can be safely sent to another thread.
480-
unsafe impl Send for rcl_timer_t {}
539+
impl Send for rcl_timer_t {}
481540

482541
#[cfg(test)]
483542
mod tests {
@@ -759,8 +818,8 @@ mod tests {
759818
handle: Arc::clone(&timer.handle),
760819
};
761820

762-
// SAFETY: Node timers expect a payload of ()
763821
unsafe {
822+
// SAFETY: Node timers expect a payload of ()
764823
executable.execute(&mut ()).unwrap();
765824
}
766825
assert!(!executed.load(Ordering::Acquire));
@@ -790,8 +849,8 @@ mod tests {
790849

791850
thread::sleep(Duration::from_millis(2));
792851

793-
// SAFETY: Node timers expect a payload of ()
794852
unsafe {
853+
// SAFETY: Node timers expect a payload of ()
795854
executable.execute(&mut ()).unwrap();
796855
}
797856
assert!(executed.load(Ordering::Acquire));

0 commit comments

Comments
 (0)