Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02601994 authored by Hansong Zhang's avatar Hansong Zhang
Browse files

AsyncFd: clear_ready() before drop()

Otherwise select! won't continue to work.

Also we need rt-multi-thread for tokio::runtime::Runtime::new

Test: cargo test
Change-Id: I2b7cbf8bd93622f404f10b55df443daf5c1a19f2
parent 67193845
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ grpcio = "*"
lazy_static = "*"
log = "*"
nix = "*"
tokio = { version = "*", features = ['bytes', 'net'] }
tokio = { version = "*", features = ['bytes', 'macros', 'net', 'rt-multi-thread', 'time'] }

# Proc Macro dependency
paste = "*"
+27 −2
Original line number Diff line number Diff line
@@ -32,7 +32,9 @@ impl Alarm {

    /// Completes when the alarm has expired
    pub async fn expired(&mut self) {
        drop(self.fd.readable().await.unwrap());
        let mut read_ready = self.fd.readable().await.unwrap();
        read_ready.clear_ready();
        drop(read_ready);
        // Will not block, since we have confirmed it is readable
        self.fd.get_ref().wait().unwrap();
    }
@@ -60,7 +62,9 @@ pub struct Interval {
impl Interval {
    /// Call this to get the future for the next tick of the interval
    pub async fn tick(&mut self) {
        drop(self.fd.readable().await.unwrap());
        let mut read_ready = self.fd.readable().await.unwrap();
        read_ready.clear_ready();
        drop(read_ready);
        // Will not block, since we have confirmed it is readable
        self.fd.get_ref().wait().unwrap();
    }
@@ -94,6 +98,27 @@ mod tests {
        });
    }

    #[test]
    fn alarm_clear_ready_after_expired() {
        // After an alarm expired, we need to make sure we clear ready from AsyncFdReadyGuard.
        // Otherwise it's still ready and select! won't work.
        let runtime = tokio::runtime::Runtime::new().unwrap();
        runtime.block_on(async {
            let timer = Instant::now();
            let mut alarm = Alarm::new();
            alarm.reset(Duration::from_millis(10));
            alarm.expired().await;
            let ready_in_10_ms = async {
                tokio::time::sleep(Duration::from_millis(10)).await;
            };
            tokio::select! {
                _ = alarm.expired() => (),
                _ = ready_in_10_ms => (),
            }
            assert_near!(timer.elapsed().as_millis(), 20, 3);
        });
    }

    #[test]
    fn interval_schedule_and_then_drop() {
        let runtime = tokio::runtime::Runtime::new().unwrap();