Path: blob/main/crates/test-programs/src/bin/async_intertask_communication.rs
1693 views
mod bindings {1wit_bindgen::generate!({2path: "../misc/component-async-tests/wit",3world: "intertask-communication",4});5}67use {8std::sync::atomic::{AtomicU32, Ordering::Relaxed},9test_programs::async_::{10BLOCKED, CALLBACK_CODE_EXIT, CALLBACK_CODE_WAIT, COMPLETED, EVENT_FUTURE_WRITE, EVENT_NONE,11context_get, context_set, waitable_join, waitable_set_drop, waitable_set_new,12},13};1415#[cfg(target_arch = "wasm32")]16#[link(wasm_import_module = "[export]local:local/run")]17unsafe extern "C" {18#[link_name = "[task-return][async]run"]19fn task_return_run();20}21#[cfg(not(target_arch = "wasm32"))]22unsafe extern "C" fn task_return_run() {23unreachable!()24}2526fn future_new() -> (u32, u32) {27#[cfg(target_arch = "wasm32")]28#[link(wasm_import_module = "local:local/intertask")]29unsafe extern "C" {30#[link_name = "[future-new-0]foo"]31fn future_new() -> u64;32}33#[cfg(not(target_arch = "wasm32"))]34unsafe extern "C" fn future_new() -> u64 {35unreachable!()36}3738let pair = unsafe { future_new() };39(40(pair >> 32).try_into().unwrap(),41(pair & 0xFFFFFFFF_u64).try_into().unwrap(),42)43}4445fn future_write(writer: u32) -> u32 {46#[cfg(target_arch = "wasm32")]47#[link(wasm_import_module = "local:local/intertask")]48unsafe extern "C" {49#[link_name = "[async-lower][future-write-0]foo"]50fn future_write(_: u32, _: u32) -> u32;51}52#[cfg(not(target_arch = "wasm32"))]53unsafe extern "C" fn future_write(_: u32, _: u32) -> u32 {54unreachable!()55}5657unsafe { future_write(writer, 0) }58}5960fn future_read(reader: u32) -> u32 {61#[cfg(target_arch = "wasm32")]62#[link(wasm_import_module = "local:local/intertask")]63unsafe extern "C" {64#[link_name = "[async-lower][future-read-0]foo"]65fn future_read(_: u32, _: u32) -> u32;66}67#[cfg(not(target_arch = "wasm32"))]68unsafe extern "C" fn future_read(_: u32, _: u32) -> u32 {69unreachable!()70}7172unsafe { future_read(reader, 0) }73}7475fn future_drop_readable(reader: u32) {76#[cfg(target_arch = "wasm32")]77#[link(wasm_import_module = "local:local/intertask")]78unsafe extern "C" {79#[link_name = "[future-drop-readable-0]foo"]80fn future_drop_readable(_: u32);81}82#[cfg(not(target_arch = "wasm32"))]83unsafe extern "C" fn future_drop_readable(_: u32) {84unreachable!()85}8687unsafe { future_drop_readable(reader) }88}8990fn future_drop_writable(writer: u32) {91#[cfg(target_arch = "wasm32")]92#[link(wasm_import_module = "local:local/intertask")]93unsafe extern "C" {94#[link_name = "[future-drop-writable-0]foo"]95fn future_drop_writable(_: u32);96}97#[cfg(not(target_arch = "wasm32"))]98unsafe extern "C" fn future_drop_writable(_: u32) {99unreachable!()100}101102unsafe { future_drop_writable(writer) }103}104105static TASK_NUMBER: AtomicU32 = AtomicU32::new(0);106static SET: AtomicU32 = AtomicU32::new(0);107108enum State {109S0 { number: u32 },110S1 { set: u32 },111}112113#[unsafe(export_name = "[async-lift]local:local/run#[async]run")]114unsafe extern "C" fn export_run() -> u32 {115unsafe {116context_set(117u32::try_from(Box::into_raw(Box::new(State::S0 {118number: TASK_NUMBER.fetch_add(1, Relaxed),119})) as usize)120.unwrap(),121);122callback_run(EVENT_NONE, 0, 0)123}124}125126#[unsafe(export_name = "[callback][async-lift]local:local/run#[async]run")]127unsafe extern "C" fn callback_run(event0: u32, event1: u32, event2: u32) -> u32 {128unsafe {129let state = &mut *(usize::try_from(context_get()).unwrap() as *mut State);130match state {131State::S0 { number } => {132assert_eq!(event0, EVENT_NONE);133134match *number {1350 => {136// Create a new waitable-set, store it for the other task to137// find, then return `CALLBACK_CODE_WAIT` to wait on it.138// This would lead to an infinite wait, except that the139// other task will add to the waitable-set after this one140// has started waiting and then trigger an event to wake it141// up.142let set = waitable_set_new();143144let old = SET.swap(set, Relaxed);145assert_eq!(old, 0);146147*state = State::S1 { set };148149CALLBACK_CODE_WAIT | (set << 4)150}1511 => {152// Retrieve the waitable-set our peer task is waiting on,153// create a future, write to write end, add the write end to154// the waitable-set, then read from the read end. The read155// should trigger an event on the write end, waking up the156// peer task.157let set = SET.swap(0, Relaxed);158assert_ne!(set, 0);159160let (tx, rx) = future_new();161let status = future_write(tx);162assert_eq!(status, BLOCKED);163164waitable_join(tx, set);165166let status = future_read(rx);167assert_eq!(status, COMPLETED); // i.e. one element was read168169future_drop_readable(rx);170171task_return_run();172CALLBACK_CODE_EXIT173}174_ => {175unreachable!()176}177}178}179180State::S1 { set } => {181assert_eq!(event0, EVENT_FUTURE_WRITE);182assert_eq!(event2, COMPLETED); // i.e. one element was written183184waitable_join(event1, 0);185waitable_set_drop(*set);186future_drop_writable(event1);187188TASK_NUMBER.store(0, Relaxed);189190task_return_run();191CALLBACK_CODE_EXIT192}193}194}195}196197// Unused function; required since this file is built as a `bin`:198fn main() {}199200201