notgull/async-winit

Infinite loop with two `Waiter`s on the same event

Opened this issue · 0 comments

use std::time::Duration;

use async_winit::event_loop::{EventLoop, EventLoopBuilder};
use async_winit::window::Window;
use async_winit::{DefaultThreadSafety, Timer};

use futures_lite::prelude::*;

fn main() {
    main2(EventLoopBuilder::new().build())
}

fn main2(evl: EventLoop) {
    let target = evl.window_target().clone();
    evl.block_on(async move {
        // Wait for a resume event to start.
        target.resumed().await;

        // Create a window.
        let window = Window::<DefaultThreadSafety>::new().await.unwrap();

        // Print resize events.
        let print_resize = {
            async {
                loop {
                    let new_size = window.resized().wait().await;
                    println!("(1) Window resized to {:?}", new_size);
                }
            }
        };

        let print_resize_again = {
            async {
                loop {
                    let new_size = window.resized().wait().await;
                    println!("(2) Window resized to {:?}", new_size);
                }
            }
        };

        // Wait for the window to close.
        async { window.close_requested().wait().await }
            .or(print_resize)
            .or(print_resize_again)  // comment this to make it work
            .await;

        // Exit.
        target.exit().await
    });
}

The above gets stuck in an infinite loop printing (1) and (2) alternatively:

(1) Window resized to PhysicalSize { width: 1904, height: 984 }
(2) Window resized to PhysicalSize { width: 1904, height: 984 }
(1) Window resized to PhysicalSize { width: 1904, height: 984 }
(2) Window resized to PhysicalSize { width: 1904, height: 984 }
...

With only one "print_resize" it works correctly. The issue might be in handler::Waiter. In my understanding, when a resize event is received:

  • one of the futures (say (1)) is notified
  • future (1) is polled, Waiter::poll_next notifies the next one in the chain (2).
  • future (1) immediately calls resized().wait() again, adding itself at the end of the list of listeners
  • future (2) is polled, Waiter::poll_next notifies the next one in the chain, i.e. (1) which just added itself
  • future (2) immediately calls resized().wait() again, adding itself at the end of the list of listeners
  • future (1) is polled, and this continues indefinitely