()
| 188 | #[tokio::test] |
| 189 | #[cfg_attr(miri, ignore)] |
| 190 | async fn suspend_while_suspending() { |
| 191 | let mut store = async_store(); |
| 192 | |
| 193 | // Create a synchronous function which calls our asynchronous function and |
| 194 | // runs it locally. This shouldn't generally happen but we know everything |
| 195 | // is synchronous in this test so it's fine for us to do this. |
| 196 | // |
| 197 | // The purpose of this test is intended to stress various cases in how |
| 198 | // we manage pointers in ways that are not necessarily common but are still |
| 199 | // possible in safe code. |
| 200 | let func_ty = FuncType::new(store.engine(), None, None); |
| 201 | let async_thunk = Func::new_async(&mut store, func_ty, |_caller, _params, _results| { |
| 202 | Box::new(async { Ok(()) }) |
| 203 | }); |
| 204 | let func_ty = FuncType::new(store.engine(), None, None); |
| 205 | let sync_call_async_thunk = |
| 206 | Func::new(&mut store, func_ty, move |mut caller, _params, _results| { |
| 207 | let mut future = Box::pin(async_thunk.call_async(&mut caller, &[], &mut [])); |
| 208 | let poll = future |
| 209 | .as_mut() |
| 210 | .poll(&mut Context::from_waker(Waker::noop())); |
| 211 | assert!(poll.is_ready()); |
| 212 | Ok(()) |
| 213 | }); |
| 214 | |
| 215 | // A small async function that simply awaits once to pump the loops and |
| 216 | // then finishes. |
| 217 | let func_ty = FuncType::new(store.engine(), None, None); |
| 218 | let async_import = Func::new_async(&mut store, func_ty, move |_caller, _params, _results| { |
| 219 | Box::new(async move { |
| 220 | tokio::task::yield_now().await; |
| 221 | Ok(()) |
| 222 | }) |
| 223 | }); |
| 224 | |
| 225 | let module = Module::new( |
| 226 | store.engine(), |
| 227 | " |
| 228 | (module |
| 229 | (import \"\" \"\" (func $sync_call_async_thunk)) |
| 230 | (import \"\" \"\" (func $async_import)) |
| 231 | (func (export \"\") |
| 232 | ;; Set some store-local state and pointers |
| 233 | call $sync_call_async_thunk |
| 234 | ;; .. and hopefully it's all still configured correctly |
| 235 | call $async_import)) |
| 236 | ", |
| 237 | ) |
| 238 | .unwrap(); |
| 239 | let instance = Instance::new_async( |
| 240 | &mut store, |
| 241 | &module, |
| 242 | &[sync_call_async_thunk.into(), async_import.into()], |
| 243 | ) |
| 244 | .await |
| 245 | .unwrap(); |
| 246 | let func = instance.get_func(&mut store, "").unwrap(); |
| 247 | func.call_async(&mut store, &[], &mut []).await.unwrap(); |
nothing calls this directly
no test coverage detected