Instantiates a wasm module and runs its exports with dummy values, all in an async fashion. Attempts to stress yields in host functions to ensure that exiting and resuming a wasm function call works.
(wasm: &[u8], config: &generators::Config, mut poll_amts: &[u32])
| 1075 | /// Attempts to stress yields in host functions to ensure that exiting and |
| 1076 | /// resuming a wasm function call works. |
| 1077 | pub fn call_async(wasm: &[u8], config: &generators::Config, mut poll_amts: &[u32]) { |
| 1078 | let mut store = config.to_store(); |
| 1079 | let module = match compile_module(store.engine(), wasm, KnownValid::Yes, config) { |
| 1080 | Some(module) => module, |
| 1081 | None => return, |
| 1082 | }; |
| 1083 | |
| 1084 | // Configure a helper thread to periodically increment the epoch to |
| 1085 | // forcibly enable yields-via-epochs if epochs are in use. Note that this |
| 1086 | // is required because the wasm isn't otherwise guaranteed to necessarily |
| 1087 | // call any imports which will also increment the epoch. |
| 1088 | let mut helper_thread = HelperThread::default(); |
| 1089 | if let generators::AsyncConfig::YieldWithEpochs { dur, .. } = &config.wasmtime.async_config { |
| 1090 | let engine = store.engine().clone(); |
| 1091 | helper_thread.run_periodically(*dur, move || engine.increment_epoch()); |
| 1092 | } |
| 1093 | |
| 1094 | // Generate a `Linker` where all function imports are custom-built to yield |
| 1095 | // periodically and additionally increment the epoch. |
| 1096 | let mut imports = Vec::new(); |
| 1097 | for import in module.imports() { |
| 1098 | let item = match import.ty() { |
| 1099 | ExternType::Func(ty) => { |
| 1100 | let poll_amt = take_poll_amt(&mut poll_amts); |
| 1101 | Func::new_async(&mut store, ty.clone(), move |caller, _, results| { |
| 1102 | let ty = ty.clone(); |
| 1103 | Box::new(async move { |
| 1104 | caller.engine().increment_epoch(); |
| 1105 | log::info!("yielding {poll_amt} times in import"); |
| 1106 | YieldN(poll_amt).await; |
| 1107 | for (ret_ty, result) in ty.results().zip(results) { |
| 1108 | *result = ret_ty.default_value().unwrap(); |
| 1109 | } |
| 1110 | Ok(()) |
| 1111 | }) |
| 1112 | }) |
| 1113 | .into() |
| 1114 | } |
| 1115 | other_ty => match other_ty.default_value(&mut store) { |
| 1116 | Ok(item) => item, |
| 1117 | Err(e) => { |
| 1118 | log::warn!("couldn't create import for {import:?}: {e:?}"); |
| 1119 | return; |
| 1120 | } |
| 1121 | }, |
| 1122 | }; |
| 1123 | imports.push(item); |
| 1124 | } |
| 1125 | |
| 1126 | // Run the instantiation process, asynchronously, and if everything |
| 1127 | // succeeds then pull out the instance. |
| 1128 | // log::info!("starting instantiation"); |
| 1129 | let instance = block_on(Timeout { |
| 1130 | future: Instance::new_async(&mut store, &module, &imports), |
| 1131 | polls: take_poll_amt(&mut poll_amts), |
| 1132 | end: Instant::now() + Duration::from_millis(2_000), |
| 1133 | }); |
| 1134 | let instance = match instance { |
no test coverage detected