Merge pull request #2300 from RobertTDowling/stm32-fix-time-driver-race
STM32: Fix race in alarm setting, which impacted scheduling.
This commit is contained in:
		@@ -474,16 +474,29 @@ impl Driver for RtcDriver {
 | 
				
			|||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let safe_timestamp = timestamp.max(t + 3);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            // Write the CCR value regardless of whether we're going to enable it now or not.
 | 
					            // Write the CCR value regardless of whether we're going to enable it now or not.
 | 
				
			||||||
            // This way, when we enable it later, the right value is already set.
 | 
					            // This way, when we enable it later, the right value is already set.
 | 
				
			||||||
            r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16));
 | 
					            r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
 | 
					            // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
 | 
				
			||||||
            let diff = timestamp - t;
 | 
					            let diff = timestamp - t;
 | 
				
			||||||
            r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
 | 
					            r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Reevaluate if the alarm timestamp is still in the future
 | 
				
			||||||
 | 
					            let t = self.now();
 | 
				
			||||||
 | 
					            if timestamp <= t {
 | 
				
			||||||
 | 
					                // If alarm timestamp has passed since we set it, we have a race condition and
 | 
				
			||||||
 | 
					                // the alarm may or may not have fired.
 | 
				
			||||||
 | 
					                // Disarm the alarm and return `false` to indicate that.
 | 
				
			||||||
 | 
					                // It is the caller's responsibility to handle this ambiguity.
 | 
				
			||||||
 | 
					                r.dier().modify(|w| w.set_ccie(n + 1, false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                alarm.timestamp.set(u64::MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // We're confident the alarm will ring in the future.
 | 
				
			||||||
            true
 | 
					            true
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -108,6 +108,10 @@ pub trait Driver: Send + Sync + 'static {
 | 
				
			|||||||
    /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`.
 | 
					    /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`.
 | 
				
			||||||
    /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set,
 | 
					    /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set,
 | 
				
			||||||
    /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously.
 | 
					    /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously.
 | 
				
			||||||
 | 
					    /// There is a rare third possibility that the alarm was barely in the future, and by the time it was enabled, it had slipped into the
 | 
				
			||||||
 | 
					    /// past.  This is can be detected by double-checking that the alarm is still in the future after enabling it; if it isn't, `false`
 | 
				
			||||||
 | 
					    /// should also be returned to indicate that the callback may have been called already by the alarm, but it is not guaranteed, so the
 | 
				
			||||||
 | 
					    /// caller should also call the callback, just like in the more common `false` case. (Note: This requires idempotency of the callback.)
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
 | 
					    /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user