Path: blob/main/crates/test-programs/src/bin/async_cancel_callee.rs
1693 views
mod bindings {1wit_bindgen::generate!({2path: "../misc/component-async-tests/wit",3world: "cancel-callee",4});5}67use test_programs::async_::{8CALLBACK_CODE_EXIT, CALLBACK_CODE_WAIT, EVENT_CANCELLED, EVENT_NONE, EVENT_SUBTASK,9STATUS_RETURN_CANCELLED, STATUS_RETURNED, STATUS_STARTED, context_get, context_set,10subtask_cancel, subtask_drop, task_cancel, waitable_join, waitable_set_drop, waitable_set_new,11};1213#[cfg(target_arch = "wasm32")]14#[link(wasm_import_module = "[export]local:local/sleep-with-options")]15unsafe extern "C" {16#[link_name = "[task-return][async]sleep-millis"]17fn task_return_sleep_millis();18}19#[cfg(not(target_arch = "wasm32"))]20unsafe extern "C" fn task_return_sleep_millis() {21unreachable!()22}2324#[cfg(target_arch = "wasm32")]25#[link(wasm_import_module = "local:local/sleep")]26unsafe extern "C" {27#[link_name = "[async]sleep-millis"]28fn sleep_millis(_: u64);29}30#[cfg(not(target_arch = "wasm32"))]31unsafe fn sleep_millis(_: u64) {32unreachable!()33}3435#[cfg(target_arch = "wasm32")]36#[link(wasm_import_module = "local:local/sleep")]37unsafe extern "C" {38#[link_name = "[async-lower][async]sleep-millis"]39fn sleep_millis_async(ms: u64) -> u32;40}41#[cfg(not(target_arch = "wasm32"))]42unsafe fn sleep_millis_async(_ms: u64) -> u32 {43unreachable!()44}4546const ON_CANCEL_TASK_RETURN: u8 = 0;47const ON_CANCEL_TASK_CANCEL: u8 = 1;4849const _MODE_NORMAL: u8 = 0;50const _MODE_TRAP_CANCEL_GUEST_AFTER_START_CANCELLED: u8 = 1;51const _MODE_TRAP_CANCEL_GUEST_AFTER_RETURN_CANCELLED: u8 = 2;52const _MODE_TRAP_CANCEL_GUEST_AFTER_RETURN: u8 = 3;53const MODE_TRAP_CANCEL_HOST_AFTER_RETURN_CANCELLED: u8 = 4;54const MODE_TRAP_CANCEL_HOST_AFTER_RETURN: u8 = 5;55const MODE_LEAK_TASK_AFTER_CANCEL: u8 = 6;5657#[derive(Clone, Copy)]58struct SleepParams {59time_in_millis: u64,60on_cancel: u8,61on_cancel_delay_millis: u64,62synchronous_delay: bool,63mode: u8,64}6566enum State {67S0(SleepParams),68S1 {69set: u32,70waitable: u32,71params: SleepParams,72},73S2 {74set: u32,75waitable: u32,76params: SleepParams,77},78}7980#[unsafe(export_name = "local:local/backpressure#set-backpressure")]81unsafe extern "C" fn export_set_backpressure(enabled: bool) {82wit_bindgen::backpressure_set(enabled);83}8485#[unsafe(export_name = "local:local/sleep#[async]sleep-millis")]86unsafe extern "C" fn export_sleep_sleep_millis(time_in_millis: u64) {87unsafe {88sleep_millis(time_in_millis);89}90}9192#[unsafe(export_name = "[async-lift]local:local/sleep-with-options#[async]sleep-millis")]93unsafe extern "C" fn export_sleep_with_options_sleep_millis(94time_in_millis: u64,95on_cancel: u8,96on_cancel_delay_millis: u64,97synchronous_delay: bool,98mode: u8,99) -> u32 {100unsafe {101context_set(102u32::try_from(Box::into_raw(Box::new(State::S0(SleepParams {103time_in_millis,104on_cancel,105on_cancel_delay_millis,106synchronous_delay,107mode,108}))) as usize)109.unwrap(),110);111callback_sleep_with_options_sleep_millis(EVENT_NONE, 0, 0)112}113}114115#[unsafe(export_name = "[callback][async-lift]local:local/sleep-with-options#[async]sleep-millis")]116unsafe extern "C" fn callback_sleep_with_options_sleep_millis(117event0: u32,118event1: u32,119event2: u32,120) -> u32 {121unsafe {122let state = &mut *(usize::try_from(context_get()).unwrap() as *mut State);123match state {124State::S0(params) => {125assert_eq!(event0, EVENT_NONE);126127let status = sleep_millis_async(params.time_in_millis);128129let waitable = status >> 4;130let status = status & 0xF;131132assert_eq!(status, STATUS_STARTED);133134let set = waitable_set_new();135waitable_join(waitable, set);136137*state = State::S1 {138set,139waitable,140params: *params,141};142143CALLBACK_CODE_WAIT | (set << 4)144}145146State::S1 {147set,148waitable,149params,150} => {151assert_eq!(event0, EVENT_CANCELLED);152153let result = subtask_cancel(*waitable);154155assert_eq!(result, STATUS_RETURN_CANCELLED);156157if params.mode == MODE_TRAP_CANCEL_HOST_AFTER_RETURN_CANCELLED {158// This should trap, since `waitable` has already been159// cancelled:160subtask_cancel(*waitable);161unreachable!()162}163164waitable_join(*waitable, 0);165166if params.mode != MODE_LEAK_TASK_AFTER_CANCEL {167subtask_drop(*waitable);168}169170if params.on_cancel_delay_millis == 0 {171match params.on_cancel {172ON_CANCEL_TASK_RETURN => task_return_sleep_millis(),173ON_CANCEL_TASK_CANCEL => task_cancel(),174_ => unreachable!(),175}176177CALLBACK_CODE_EXIT178} else if params.synchronous_delay {179sleep_millis(params.on_cancel_delay_millis);180181match params.on_cancel {182ON_CANCEL_TASK_RETURN => task_return_sleep_millis(),183ON_CANCEL_TASK_CANCEL => task_cancel(),184_ => unreachable!(),185}186187CALLBACK_CODE_EXIT188} else {189let status = sleep_millis_async(params.on_cancel_delay_millis);190191let waitable = status >> 4;192let status = status & 0xF;193194assert_eq!(status, STATUS_STARTED);195196waitable_join(waitable, *set);197198let set = *set;199200*state = State::S2 {201set,202waitable,203params: *params,204};205206CALLBACK_CODE_WAIT | (set << 4)207}208}209210State::S2 {211set,212waitable,213params,214} => {215assert_eq!(event0, EVENT_SUBTASK);216assert_eq!(event1, *waitable);217assert_eq!(event2, STATUS_RETURNED);218219if params.mode == MODE_TRAP_CANCEL_HOST_AFTER_RETURN {220// This should trap, since `waitable` has already returned:221subtask_cancel(*waitable);222unreachable!()223}224225waitable_join(*waitable, 0);226subtask_drop(*waitable);227waitable_set_drop(*set);228229match params.on_cancel {230ON_CANCEL_TASK_RETURN => task_return_sleep_millis(),231ON_CANCEL_TASK_CANCEL => task_cancel(),232_ => unreachable!(),233}234235CALLBACK_CODE_EXIT236}237}238}239}240241// Unused function; required since this file is built as a `bin`:242fn main() {}243244245