mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-29 06:54:33 +01:00
Fix race condition in calculate_now
(#860)
* Fix race condition in calculate_now * Add changelog * Update changelog * Refine comment * More comment fixes
This commit is contained in:
parent
f377471e44
commit
bbed945285
8 changed files with 27 additions and 15 deletions
|
@ -13,6 +13,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||||
- Fix race condition in `nrf::rtc`.
|
- Fix race condition in `nrf::rtc`.
|
||||||
- Fix errata in `nrf::rtc`.
|
- Fix errata in `nrf::rtc`.
|
||||||
- Add internal counter integrity check to all half-period based monotonics.
|
- Add internal counter integrity check to all half-period based monotonics.
|
||||||
|
- Apply race condition fixes from `rtic-time`.
|
||||||
|
|
||||||
## v1.4.0 - 2023-12-04
|
## v1.4.0 - 2023-12-04
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,7 @@ macro_rules! make_timer {
|
||||||
let gpt = unsafe{ $timer::instance() };
|
let gpt = unsafe{ $timer::instance() };
|
||||||
|
|
||||||
Self::Instant::from_ticks(calculate_now(
|
Self::Instant::from_ticks(calculate_now(
|
||||||
$period.load(Ordering::Relaxed),
|
|| $period.load(Ordering::Relaxed),
|
||||||
|| ral::read_reg!(ral::gpt, gpt, CNT)
|
|| ral::read_reg!(ral::gpt, gpt, CNT)
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,7 @@ macro_rules! make_rtc {
|
||||||
fn now() -> Self::Instant {
|
fn now() -> Self::Instant {
|
||||||
let rtc = unsafe { &*$rtc::PTR };
|
let rtc = unsafe { &*$rtc::PTR };
|
||||||
Self::Instant::from_ticks(calculate_now(
|
Self::Instant::from_ticks(calculate_now(
|
||||||
$overflow.load(Ordering::Relaxed),
|
|| $overflow.load(Ordering::Relaxed),
|
||||||
|| TimerValueU24(rtc.counter.read().bits())
|
|| TimerValueU24(rtc.counter.read().bits())
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,7 +242,7 @@ macro_rules! make_timer {
|
||||||
let timer = unsafe { &*$timer::PTR };
|
let timer = unsafe { &*$timer::PTR };
|
||||||
|
|
||||||
Self::Instant::from_ticks(calculate_now(
|
Self::Instant::from_ticks(calculate_now(
|
||||||
$overflow.load(Ordering::Relaxed),
|
|| $overflow.load(Ordering::Relaxed),
|
||||||
|| {
|
|| {
|
||||||
timer.tasks_capture[3].write(|w| unsafe { w.bits(1) });
|
timer.tasks_capture[3].write(|w| unsafe { w.bits(1) });
|
||||||
timer.cc[3].read().bits()
|
timer.cc[3].read().bits()
|
||||||
|
|
|
@ -234,7 +234,7 @@ macro_rules! make_timer {
|
||||||
|
|
||||||
fn now() -> Self::Instant {
|
fn now() -> Self::Instant {
|
||||||
Self::Instant::from_ticks(calculate_now(
|
Self::Instant::from_ticks(calculate_now(
|
||||||
$overflow.load(Ordering::Relaxed),
|
|| $overflow.load(Ordering::Relaxed),
|
||||||
|| $timer.cnt().read().cnt()
|
|| $timer.cnt().read().cnt()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Fix race condition in `half_period_counter::calculate_now`.
|
||||||
|
This sadly required a minor API change.
|
||||||
|
|
||||||
## v1.1.0 - 2023-12-04
|
## v1.1.0 - 2023-12-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
//!
|
//!
|
||||||
//! fn now() -> u64 {
|
//! fn now() -> u64 {
|
||||||
//! rtic_time::half_period_counter::calculate_now(
|
//! rtic_time::half_period_counter::calculate_now(
|
||||||
//! HALF_PERIOD_COUNTER.load(Ordering::Relaxed),
|
//! || HALF_PERIOD_COUNTER.load(Ordering::Relaxed),
|
||||||
//! || timer_get_value(),
|
//! || timer_get_value(),
|
||||||
//! )
|
//! )
|
||||||
//! }
|
//! }
|
||||||
|
@ -191,19 +191,27 @@ impl_timer_ops!(u128);
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `half_periods` - The period counter value. If read from an atomic, can use `Ordering::Relaxed`.
|
/// * `half_periods` - A closure/function that when called produces the period counter value. If read from an atomic, can use `Ordering::Relaxed`.
|
||||||
/// * `timer_value` - A closure/function that when called produces the current timer value.
|
/// * `timer_value` - A closure/function that when called produces the current timer value.
|
||||||
pub fn calculate_now<P, T, F, O>(half_periods: P, timer_value: F) -> O
|
pub fn calculate_now<P, T, F1, F2, O>(half_periods: F1, timer_value: F2) -> O
|
||||||
where
|
where
|
||||||
T: TimerValue,
|
T: TimerValue,
|
||||||
O: From<P> + From<T> + TimerOps,
|
O: From<P> + From<T> + TimerOps,
|
||||||
F: FnOnce() -> T,
|
F1: FnOnce() -> P,
|
||||||
|
F2: FnOnce() -> T,
|
||||||
{
|
{
|
||||||
// Important: half_period **must** be read first.
|
// This is timing critical; for fast-overflowing timers (like the 1MHz 16-bit timers on STM32),
|
||||||
// Otherwise we have another mathematical race condition.
|
// it could lead to erroneous behavior if preempted in between the two reads.
|
||||||
let half_periods = O::from(half_periods);
|
// Hence the critical section.
|
||||||
compiler_fence(Ordering::Acquire);
|
let (half_periods, timer_value) = critical_section::with(|_| {
|
||||||
let timer_value = O::from(timer_value());
|
// Important: half_periods **must** be read first.
|
||||||
|
// Otherwise the mathematical principle that prevents
|
||||||
|
// the race condition does not work.
|
||||||
|
let half_periods = O::from(half_periods());
|
||||||
|
compiler_fence(Ordering::Acquire);
|
||||||
|
let timer_value = O::from(timer_value());
|
||||||
|
(half_periods, timer_value)
|
||||||
|
});
|
||||||
|
|
||||||
// Credits to the `time-driver` of `embassy-stm32`.
|
// Credits to the `time-driver` of `embassy-stm32`.
|
||||||
//
|
//
|
||||||
|
|
|
@ -5,7 +5,7 @@ macro_rules! do_test_u8 {
|
||||||
let periods: u32 = $periods;
|
let periods: u32 = $periods;
|
||||||
let counter: u8 = $counter;
|
let counter: u8 = $counter;
|
||||||
let expected: u32 = $expected;
|
let expected: u32 = $expected;
|
||||||
let actual: u32 = calculate_now(periods, || counter);
|
let actual: u32 = calculate_now(|| periods, || counter);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
actual, expected,
|
actual, expected,
|
||||||
"Expected: ({} | {}) => {}, got: {}",
|
"Expected: ({} | {}) => {}, got: {}",
|
||||||
|
@ -19,7 +19,7 @@ macro_rules! do_test_u16 {
|
||||||
let periods: u16 = $periods;
|
let periods: u16 = $periods;
|
||||||
let counter: u16 = $counter;
|
let counter: u16 = $counter;
|
||||||
let expected: u32 = $expected;
|
let expected: u32 = $expected;
|
||||||
let actual: u32 = calculate_now(periods, || counter);
|
let actual: u32 = calculate_now(|| periods, || counter);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
actual, expected,
|
actual, expected,
|
||||||
"Expected: ({} | {}) => {}, got: {}",
|
"Expected: ({} | {}) => {}, got: {}",
|
||||||
|
|
Loading…
Reference in a new issue