| 558 | #[tokio::test] |
| 559 | #[cfg_attr(miri, ignore)] |
| 560 | async fn resume_separate_thread3() { |
| 561 | let _ = env_logger::try_init(); |
| 562 | |
| 563 | // This test doesn't actually do anything with cross-thread polls, but |
| 564 | // instead it deals with scheduling futures at "odd" times. |
| 565 | // |
| 566 | // First we'll set up a *synchronous* call which will initialize TLS info. |
| 567 | // This call is simply to a host-defined function, but it still has the same |
| 568 | // "enter into wasm" semantics since it's just calling a trampoline. In this |
| 569 | // situation we'll set up the TLS info so it's in place while the body of |
| 570 | // the function executes... |
| 571 | let mut store = Store::new(&Engine::default(), None); |
| 572 | let f = Func::wrap(&mut store, move |mut caller: Caller<'_, _>| -> Result<()> { |
| 573 | // ... and the execution of this host-defined function (while the TLS |
| 574 | // info is initialized), will set up a recursive call into wasm. This |
| 575 | // recursive call will be done asynchronously so we can suspend it |
| 576 | // halfway through. |
| 577 | let f = async { |
| 578 | let mut store = async_store(); |
| 579 | let module = Module::new( |
| 580 | store.engine(), |
| 581 | " |
| 582 | (module |
| 583 | (import \"\" \"\" (func)) |
| 584 | (start 0) |
| 585 | ) |
| 586 | ", |
| 587 | ) |
| 588 | .unwrap(); |
| 589 | let func = Func::wrap_async(&mut store, |_, _: ()| { |
| 590 | Box::new(async { |
| 591 | tokio::task::yield_now().await; |
| 592 | }) |
| 593 | }); |
| 594 | drop(Instance::new_async(&mut store, &module, &[func.into()]).await); |
| 595 | unreachable!() |
| 596 | }; |
| 597 | let mut future = Box::pin(f); |
| 598 | let poll = future |
| 599 | .as_mut() |
| 600 | .poll(&mut Context::from_waker(Waker::noop())); |
| 601 | assert!(poll.is_pending()); |
| 602 | |
| 603 | // ... so at this point our call into wasm is suspended. The call into |
| 604 | // wasm will have overwritten TLS info, and we sure hope that the |
| 605 | // information is restored at this point. Note that we squirrel away the |
| 606 | // future somewhere else to get dropped later. If we were to drop it |
| 607 | // here then we would reenter the future's suspended stack to clean it |
| 608 | // up, which would do more alterations of TLS information we're not |
| 609 | // testing here. |
| 610 | *caller.data_mut() = Some(future); |
| 611 | |
| 612 | // ... all in all this function will need access to the original TLS |
| 613 | // information to raise the trap. This TLS information should be |
| 614 | // restored even though the asynchronous execution is suspended. |
| 615 | bail!("") |
| 616 | }); |
| 617 | assert!(f.call(&mut store, &[], &mut []).is_err()); |