rahul-thakoor / rust_gpiozero

A library inspired by gpiozero written in Rust
https://crates.io/crates/rust_gpiozero
Apache License 2.0
232 stars 27 forks source link

Fix race condition when stopping blinking #49

Open smortime opened 10 months ago

smortime commented 10 months ago

Was running into couple different race conditions when calling blink then trying to set the LED back to on. Minimal program to recreate bug :

use std::{thread, time::Duration};
use rust_gpiozero::LED;

fn main() {
    let mut led = LED::new(12);
    led.on();
    thread::sleep(Duration::from_secs(5));
    led.blink(3, 3);
    thread::sleep(Duration::from_secs(5));
    led.on();
    thread::sleep(Duration::from_secs(5));
    led.off();
}

Two race conditions I was hitting:

  1. led.on() called while blinker is running; it sets the blinking to false then turns the device to on but by the time blinker wakes from sleep the device is on and it then turns it off again before bailing from its loop
  2. If you call led.on() between the on/off sleep interval the blinker will then turn it off

The first is remediated by removing device.lock().unwrap().off(); from the if !blinking.load(Ordering::SeqCst){ .. } condition and just relying on who ever calls self.stop() to set the final state it wants.

The second remediated by adding the if !blinking.load(Ordering::SeqCst){ .. } check between sleeps to avoid clobbering the state whoever called stop set (feel there might be cleaner way to do this part 😅).