diff --git a/crates/tests/winrt/Cargo.toml b/crates/tests/winrt/Cargo.toml index fa09f0050f..45916940ed 100644 --- a/crates/tests/winrt/Cargo.toml +++ b/crates/tests/winrt/Cargo.toml @@ -23,6 +23,7 @@ features = [ "Foundation_Numerics", "Storage_Streams", "System", + "System_Threading", "UI_Composition", "Win32_System_Com", "Win32_System_WinRT", diff --git a/crates/tests/winrt/tests/async.rs b/crates/tests/winrt/tests/async.rs index 44a843fd5c..08323a6409 100644 --- a/crates/tests/winrt/tests/async.rs +++ b/crates/tests/winrt/tests/async.rs @@ -1,7 +1,13 @@ +use std::future::IntoFuture; + +use futures::{executor::LocalPool, future, task::SpawnExt}; +use windows::{ + Storage::Streams::*, + System::Threading::{ThreadPool, WorkItemHandler}, +}; + #[test] fn async_get() -> windows::core::Result<()> { - use windows::Storage::Streams::*; - let stream = &InMemoryRandomAccessStream::new()?; let writer = DataWriter::CreateDataWriter(stream)?; @@ -25,8 +31,6 @@ fn async_get() -> windows::core::Result<()> { } async fn async_await() -> windows::core::Result<()> { - use windows::Storage::Streams::*; - let stream = &InMemoryRandomAccessStream::new()?; let writer = DataWriter::CreateDataWriter(stream)?; @@ -53,3 +57,43 @@ async fn async_await() -> windows::core::Result<()> { fn test_async_await() -> windows::core::Result<()> { futures::executor::block_on(async_await()) } + +#[test] +fn test_async_updates_waker() -> windows::core::Result<()> { + let mut pool = LocalPool::new(); + + let (tx, rx) = std::sync::mpsc::channel::<()>(); + + let winrt_future = ThreadPool::RunAsync(&WorkItemHandler::new(move |_| { + rx.recv().unwrap(); + Ok(()) + }))? + .into_future(); + + let task = pool + .spawner() + .spawn_with_handle(async move { + // Poll the future once on a LocalPool task + match future::select(winrt_future, future::ready(())).await { + future::Either::Left(_) => panic!("threadpool action can't finish yet"), + future::Either::Right(((), future)) => future, + } + }) + .unwrap(); + let winrt_future = pool.run_until(task); + + pool.spawner() + .spawn(async move { + // Now run the future to completion on a *different* LocalPool task. + // This will hang unless winrt_future properly updates its saved waker to the new task. + let (result, ()) = future::join(winrt_future, async { + tx.send(()).unwrap(); + }) + .await; + result.unwrap(); + }) + .unwrap(); + pool.run(); + + Ok(()) +}