aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/time_driver.rs
diff options
context:
space:
mode:
authorRobertTDowling <[email protected]>2023-12-17 15:11:03 -0800
committerRobertTDowling <[email protected]>2023-12-17 15:35:35 -0800
commitb857334f92fc188004567edb93e0d1dfce4c259e (patch)
tree78f90e470c3d477dc97b78badf321e31dfe599ce /embassy-stm32/src/time_driver.rs
parenta2d4bab2f8a4a9b994bc0289938a9f725950715f (diff)
STM32: Fix race in alarm setting, which impacted scheduling.
Detect potential race condition (should be rare) and return false back to caller, allowing them to handle the possibility that either the alarm was never set because it was in the past (old meaning of false), or that in fact the alarm was set and may have fired within the race window (new meaning of false). In either case, the caller needs to make sure the callback got called.
Diffstat (limited to 'embassy-stm32/src/time_driver.rs')
-rw-r--r--embassy-stm32/src/time_driver.rs19
1 files changed, 16 insertions, 3 deletions
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index ea9c22d87..9981800b2 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -474,16 +474,29 @@ impl Driver for RtcDriver {
474 return false; 474 return false;
475 } 475 }
476 476
477 let safe_timestamp = timestamp.max(t + 3);
478
479 // Write the CCR value regardless of whether we're going to enable it now or not. 477 // Write the CCR value regardless of whether we're going to enable it now or not.
480 // This way, when we enable it later, the right value is already set. 478 // This way, when we enable it later, the right value is already set.
481 r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)); 479 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
482 480
483 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. 481 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
484 let diff = timestamp - t; 482 let diff = timestamp - t;
485 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); 483 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
486 484
485 // Reevaluate if the alarm timestamp is still in the future
486 let t = self.now();
487 if timestamp <= t {
488 // If alarm timestamp has passed since we set it, we have a race condition and
489 // the alarm may or may not have fired.
490 // Disarm the alarm and return `false` to indicate that.
491 // It is the caller's responsibility to handle this ambiguity.
492 r.dier().modify(|w| w.set_ccie(n + 1, false));
493
494 alarm.timestamp.set(u64::MAX);
495
496 return false;
497 }
498
499 // We're confident the alarm will ring in the future.
487 true 500 true
488 }) 501 })
489 } 502 }