1804060c8SJoel Dice mod bindings {
2804060c8SJoel Dice     wit_bindgen::generate!({
3804060c8SJoel Dice         path: "../misc/component-async-tests/wit",
4804060c8SJoel Dice         world: "intertask-communication",
5804060c8SJoel Dice     });
6804060c8SJoel Dice }
7804060c8SJoel Dice 
8804060c8SJoel Dice use {
9804060c8SJoel Dice     std::sync::atomic::{AtomicU32, Ordering::Relaxed},
10804060c8SJoel Dice     test_programs::async_::{
11804060c8SJoel Dice         BLOCKED, CALLBACK_CODE_EXIT, CALLBACK_CODE_WAIT, COMPLETED, EVENT_FUTURE_WRITE, EVENT_NONE,
12804060c8SJoel Dice         context_get, context_set, waitable_join, waitable_set_drop, waitable_set_new,
13804060c8SJoel Dice     },
14804060c8SJoel Dice };
15804060c8SJoel Dice 
16804060c8SJoel Dice #[cfg(target_arch = "wasm32")]
17804060c8SJoel Dice #[link(wasm_import_module = "[export]local:local/run")]
18804060c8SJoel Dice unsafe extern "C" {
19*020727d0SAlex Crichton     #[link_name = "[task-return]run"]
task_return_run()20804060c8SJoel Dice     fn task_return_run();
21804060c8SJoel Dice }
22804060c8SJoel Dice #[cfg(not(target_arch = "wasm32"))]
task_return_run()23804060c8SJoel Dice unsafe extern "C" fn task_return_run() {
24804060c8SJoel Dice     unreachable!()
25804060c8SJoel Dice }
26804060c8SJoel Dice 
future_new() -> (u32, u32)27804060c8SJoel Dice fn future_new() -> (u32, u32) {
28804060c8SJoel Dice     #[cfg(target_arch = "wasm32")]
29804060c8SJoel Dice     #[link(wasm_import_module = "local:local/intertask")]
30804060c8SJoel Dice     unsafe extern "C" {
31804060c8SJoel Dice         #[link_name = "[future-new-0]foo"]
32804060c8SJoel Dice         fn future_new() -> u64;
33804060c8SJoel Dice     }
34804060c8SJoel Dice     #[cfg(not(target_arch = "wasm32"))]
35804060c8SJoel Dice     unsafe extern "C" fn future_new() -> u64 {
36804060c8SJoel Dice         unreachable!()
37804060c8SJoel Dice     }
38804060c8SJoel Dice 
39804060c8SJoel Dice     let pair = unsafe { future_new() };
40804060c8SJoel Dice     (
41804060c8SJoel Dice         (pair >> 32).try_into().unwrap(),
42804060c8SJoel Dice         (pair & 0xFFFFFFFF_u64).try_into().unwrap(),
43804060c8SJoel Dice     )
44804060c8SJoel Dice }
45804060c8SJoel Dice 
future_write(writer: u32) -> u3246804060c8SJoel Dice fn future_write(writer: u32) -> u32 {
47804060c8SJoel Dice     #[cfg(target_arch = "wasm32")]
48804060c8SJoel Dice     #[link(wasm_import_module = "local:local/intertask")]
49804060c8SJoel Dice     unsafe extern "C" {
50804060c8SJoel Dice         #[link_name = "[async-lower][future-write-0]foo"]
51804060c8SJoel Dice         fn future_write(_: u32, _: u32) -> u32;
52804060c8SJoel Dice     }
53804060c8SJoel Dice     #[cfg(not(target_arch = "wasm32"))]
54804060c8SJoel Dice     unsafe extern "C" fn future_write(_: u32, _: u32) -> u32 {
55804060c8SJoel Dice         unreachable!()
56804060c8SJoel Dice     }
57804060c8SJoel Dice 
58804060c8SJoel Dice     unsafe { future_write(writer, 0) }
59804060c8SJoel Dice }
60804060c8SJoel Dice 
future_read(reader: u32) -> u3261804060c8SJoel Dice fn future_read(reader: u32) -> u32 {
62804060c8SJoel Dice     #[cfg(target_arch = "wasm32")]
63804060c8SJoel Dice     #[link(wasm_import_module = "local:local/intertask")]
64804060c8SJoel Dice     unsafe extern "C" {
65804060c8SJoel Dice         #[link_name = "[async-lower][future-read-0]foo"]
66804060c8SJoel Dice         fn future_read(_: u32, _: u32) -> u32;
67804060c8SJoel Dice     }
68804060c8SJoel Dice     #[cfg(not(target_arch = "wasm32"))]
69804060c8SJoel Dice     unsafe extern "C" fn future_read(_: u32, _: u32) -> u32 {
70804060c8SJoel Dice         unreachable!()
71804060c8SJoel Dice     }
72804060c8SJoel Dice 
73804060c8SJoel Dice     unsafe { future_read(reader, 0) }
74804060c8SJoel Dice }
75804060c8SJoel Dice 
future_drop_readable(reader: u32)76804060c8SJoel Dice fn future_drop_readable(reader: u32) {
77804060c8SJoel Dice     #[cfg(target_arch = "wasm32")]
78804060c8SJoel Dice     #[link(wasm_import_module = "local:local/intertask")]
79804060c8SJoel Dice     unsafe extern "C" {
80804060c8SJoel Dice         #[link_name = "[future-drop-readable-0]foo"]
81804060c8SJoel Dice         fn future_drop_readable(_: u32);
82804060c8SJoel Dice     }
83804060c8SJoel Dice     #[cfg(not(target_arch = "wasm32"))]
84804060c8SJoel Dice     unsafe extern "C" fn future_drop_readable(_: u32) {
85804060c8SJoel Dice         unreachable!()
86804060c8SJoel Dice     }
87804060c8SJoel Dice 
88804060c8SJoel Dice     unsafe { future_drop_readable(reader) }
89804060c8SJoel Dice }
90804060c8SJoel Dice 
future_drop_writable(writer: u32)91804060c8SJoel Dice fn future_drop_writable(writer: u32) {
92804060c8SJoel Dice     #[cfg(target_arch = "wasm32")]
93804060c8SJoel Dice     #[link(wasm_import_module = "local:local/intertask")]
94804060c8SJoel Dice     unsafe extern "C" {
95804060c8SJoel Dice         #[link_name = "[future-drop-writable-0]foo"]
96804060c8SJoel Dice         fn future_drop_writable(_: u32);
97804060c8SJoel Dice     }
98804060c8SJoel Dice     #[cfg(not(target_arch = "wasm32"))]
99804060c8SJoel Dice     unsafe extern "C" fn future_drop_writable(_: u32) {
100804060c8SJoel Dice         unreachable!()
101804060c8SJoel Dice     }
102804060c8SJoel Dice 
103804060c8SJoel Dice     unsafe { future_drop_writable(writer) }
104804060c8SJoel Dice }
105804060c8SJoel Dice 
106804060c8SJoel Dice static TASK_NUMBER: AtomicU32 = AtomicU32::new(0);
107804060c8SJoel Dice static SET: AtomicU32 = AtomicU32::new(0);
108804060c8SJoel Dice 
109804060c8SJoel Dice enum State {
110804060c8SJoel Dice     S0 { number: u32 },
111804060c8SJoel Dice     S1 { set: u32 },
112804060c8SJoel Dice }
113804060c8SJoel Dice 
114*020727d0SAlex Crichton #[unsafe(export_name = "[async-lift]local:local/run#run")]
export_run() -> u32115804060c8SJoel Dice unsafe extern "C" fn export_run() -> u32 {
116804060c8SJoel Dice     unsafe {
117804060c8SJoel Dice         context_set(
118804060c8SJoel Dice             u32::try_from(Box::into_raw(Box::new(State::S0 {
119804060c8SJoel Dice                 number: TASK_NUMBER.fetch_add(1, Relaxed),
120804060c8SJoel Dice             })) as usize)
121804060c8SJoel Dice             .unwrap(),
122804060c8SJoel Dice         );
123804060c8SJoel Dice         callback_run(EVENT_NONE, 0, 0)
124804060c8SJoel Dice     }
125804060c8SJoel Dice }
126804060c8SJoel Dice 
127*020727d0SAlex Crichton #[unsafe(export_name = "[callback][async-lift]local:local/run#run")]
callback_run(event0: u32, event1: u32, event2: u32) -> u32128804060c8SJoel Dice unsafe extern "C" fn callback_run(event0: u32, event1: u32, event2: u32) -> u32 {
129804060c8SJoel Dice     unsafe {
130804060c8SJoel Dice         let state = &mut *(usize::try_from(context_get()).unwrap() as *mut State);
131804060c8SJoel Dice         match state {
132804060c8SJoel Dice             State::S0 { number } => {
133804060c8SJoel Dice                 assert_eq!(event0, EVENT_NONE);
134804060c8SJoel Dice 
135804060c8SJoel Dice                 match *number {
136804060c8SJoel Dice                     0 => {
137804060c8SJoel Dice                         // Create a new waitable-set, store it for the other task to
138804060c8SJoel Dice                         // find, then return `CALLBACK_CODE_WAIT` to wait on it.
139804060c8SJoel Dice                         // This would lead to an infinite wait, except that the
140804060c8SJoel Dice                         // other task will add to the waitable-set after this one
141804060c8SJoel Dice                         // has started waiting and then trigger an event to wake it
142804060c8SJoel Dice                         // up.
143804060c8SJoel Dice                         let set = waitable_set_new();
144804060c8SJoel Dice 
145804060c8SJoel Dice                         let old = SET.swap(set, Relaxed);
146804060c8SJoel Dice                         assert_eq!(old, 0);
147804060c8SJoel Dice 
148804060c8SJoel Dice                         *state = State::S1 { set };
149804060c8SJoel Dice 
150804060c8SJoel Dice                         CALLBACK_CODE_WAIT | (set << 4)
151804060c8SJoel Dice                     }
152804060c8SJoel Dice                     1 => {
153804060c8SJoel Dice                         // Retrieve the waitable-set our peer task is waiting on,
154804060c8SJoel Dice                         // create a future, write to write end, add the write end to
155804060c8SJoel Dice                         // the waitable-set, then read from the read end.  The read
156804060c8SJoel Dice                         // should trigger an event on the write end, waking up the
157804060c8SJoel Dice                         // peer task.
158804060c8SJoel Dice                         let set = SET.swap(0, Relaxed);
159804060c8SJoel Dice                         assert_ne!(set, 0);
160804060c8SJoel Dice 
161804060c8SJoel Dice                         let (tx, rx) = future_new();
162804060c8SJoel Dice                         let status = future_write(tx);
163804060c8SJoel Dice                         assert_eq!(status, BLOCKED);
164804060c8SJoel Dice 
165804060c8SJoel Dice                         waitable_join(tx, set);
166804060c8SJoel Dice 
167804060c8SJoel Dice                         let status = future_read(rx);
168804060c8SJoel Dice                         assert_eq!(status, COMPLETED); // i.e. one element was read
169804060c8SJoel Dice 
170804060c8SJoel Dice                         future_drop_readable(rx);
171804060c8SJoel Dice 
172804060c8SJoel Dice                         task_return_run();
173804060c8SJoel Dice                         CALLBACK_CODE_EXIT
174804060c8SJoel Dice                     }
175804060c8SJoel Dice                     _ => {
176804060c8SJoel Dice                         unreachable!()
177804060c8SJoel Dice                     }
178804060c8SJoel Dice                 }
179804060c8SJoel Dice             }
180804060c8SJoel Dice 
181804060c8SJoel Dice             State::S1 { set } => {
182804060c8SJoel Dice                 assert_eq!(event0, EVENT_FUTURE_WRITE);
183804060c8SJoel Dice                 assert_eq!(event2, COMPLETED); // i.e. one element was written
184804060c8SJoel Dice 
185804060c8SJoel Dice                 waitable_join(event1, 0);
186804060c8SJoel Dice                 waitable_set_drop(*set);
187804060c8SJoel Dice                 future_drop_writable(event1);
188804060c8SJoel Dice 
189804060c8SJoel Dice                 TASK_NUMBER.store(0, Relaxed);
190804060c8SJoel Dice 
191804060c8SJoel Dice                 task_return_run();
192804060c8SJoel Dice                 CALLBACK_CODE_EXIT
193804060c8SJoel Dice             }
194804060c8SJoel Dice         }
195804060c8SJoel Dice     }
196804060c8SJoel Dice }
197804060c8SJoel Dice 
198804060c8SJoel Dice // Unused function; required since this file is built as a `bin`:
main()199804060c8SJoel Dice fn main() {}
200