diff --git a/.github/actions/install-wasi-sdk/action.yml b/.github/actions/install-wasi-sdk/action.yml index 468e3873a..6132d9965 100644 --- a/.github/actions/install-wasi-sdk/action.yml +++ b/.github/actions/install-wasi-sdk/action.yml @@ -5,18 +5,18 @@ runs: using: composite steps: - run: | - curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sdk-24.0-x86_64-linux.tar.gz -L | tar xzvf - - echo "WASI_SDK_PATH=`pwd`/wasi-sdk-24.0-x86_64-linux" >> $GITHUB_ENV + curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.tar.gz -L | tar xzvf - + echo "WASI_SDK_PATH=`pwd`/wasi-sdk-25.0-x86_64-linux" >> $GITHUB_ENV if: runner.os == 'Linux' shell: bash - run: | - curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sdk-24.0-x86_64-macos.tar.gz -L | tar xzvf - - echo "WASI_SDK_PATH=`pwd`/wasi-sdk-24.0-x86_64-macos" >> $GITHUB_ENV + curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-macos.tar.gz -L | tar xzvf - + echo "WASI_SDK_PATH=`pwd`/wasi-sdk-25.0-x86_64-macos" >> $GITHUB_ENV if: runner.os == 'macOS' shell: bash - run: | - curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sdk-24.0-x86_64-windows.tar.gz -L | tar xzvf - - echo "WASI_SDK_PATH=`pwd`/wasi-sdk-24.0-x86_64-windows" >> $GITHUB_ENV + curl https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-windows.tar.gz -L | tar xzvf - + echo "WASI_SDK_PATH=`pwd`/wasi-sdk-25.0-x86_64-windows" >> $GITHUB_ENV if: runner.os == 'Windows' shell: bash - name: Setup `wasm-tools` diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 67a86dd80..185301efe 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -151,10 +151,10 @@ jobs: - name: Install wasm32-wasip1 target run: rustup target add wasm32-wasip1 - # Verify the output of the `./ci/rebuild-libcabi-realloc.sh` script is + # Verify the output of the `./ci/rebuild-libwit-bindgen-cabi.sh` script is # up-to-date. - uses: ./.github/actions/install-wasi-sdk - - run: ./ci/rebuild-libcabi-realloc.sh + - run: ./ci/rebuild-libwit-bindgen-cabi.sh - run: git diff --exit-code # Test various feature combinations, make sure they all build diff --git a/ci/rebuild-libcabi-realloc.sh b/ci/rebuild-libwit-bindgen-cabi.sh similarity index 65% rename from ci/rebuild-libcabi-realloc.sh rename to ci/rebuild-libwit-bindgen-cabi.sh index 0d76fa947..0caa6b89b 100755 --- a/ci/rebuild-libcabi-realloc.sh +++ b/ci/rebuild-libwit-bindgen-cabi.sh @@ -41,13 +41,16 @@ set -ex version=$(./ci/print-current-version.sh | sed 's/\./_/g') -sym=cabi_realloc_wit_bindgen_$version +realloc=cabi_realloc_wit_bindgen_$version -cat >./crates/guest-rust/rt/src/cabi_realloc.rs <<-EOF +rm -f crates/guest-rust/rt/src/wit_bindgen_*.{rs,o,c} +rm -f crates/guest-rust/rt/src/libwit_bindgen_cabi.a + +cat >./crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.rs <<-EOF // This file is generated by $0 #[unsafe(no_mangle)] -pub unsafe extern "C" fn $sym( +pub unsafe extern "C" fn $realloc( old_ptr: *mut u8, old_len: usize, align: usize, @@ -57,29 +60,48 @@ pub unsafe extern "C" fn $sym( } EOF -cat >./crates/guest-rust/rt/src/cabi_realloc.c <<-EOF +cat >./crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.c <<-EOF // This file is generated by $0 #include -extern void *$sym(void *ptr, size_t old_size, size_t align, size_t new_size); +extern void *$realloc(void *ptr, size_t old_size, size_t align, size_t new_size); __attribute__((__weak__, __export_name__("cabi_realloc"))) void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size) { - return $sym(ptr, old_size, align, new_size); + return $realloc(ptr, old_size, align, new_size); } EOF -rm -f crates/guest-rust/rt/src/cabi_realloc.o -$WASI_SDK_PATH/bin/clang crates/guest-rust/rt/src/cabi_realloc.c \ - -O -c -o crates/guest-rust/rt/src/cabi_realloc.o +cat >./crates/guest-rust/rt/src/wit_bindgen_cabi_wasip3.c <<-EOF +// This file is generated by $0 + +#include + +static void *WASIP3_TASK = NULL; + +__attribute__((__weak__)) +void *wasip3_task_set(void *ptr) { + void *ret = WASIP3_TASK; + WASIP3_TASK = ptr; + return ret; +} +EOF + +build() { + file=$1 + $WASI_SDK_PATH/bin/clang crates/guest-rust/rt/src/$1.c \ + -O -c -o crates/guest-rust/rt/src/$1.o + # Remove the `producers` section. This appears to differ whether the host for + # clang is either macOS or Linux. Not needed here anyway, so discard it to help + # either host produce the same object. + wasm-tools strip -d producers ./crates/guest-rust/rt/src/$1.o \ + -o ./crates/guest-rust/rt/src/$1.o +} -# Remove the `producers` section. This appears to differ whether the host for -# clang is either macOS or Linux. Not needed here anyway, so discard it to help -# either host produce the same object. -wasm-tools strip -d producers ./crates/guest-rust/rt/src/cabi_realloc.o \ - -o ./crates/guest-rust/rt/src/cabi_realloc.o +build wit_bindgen_cabi_realloc +build wit_bindgen_cabi_wasip3 -rm -f crates/guest-rust/rt/src/libwit_bindgen_cabi_realloc.a -$WASI_SDK_PATH/bin/llvm-ar crus crates/guest-rust/rt/src/libwit_bindgen_cabi_realloc.a \ - crates/guest-rust/rt/src/cabi_realloc.o +$WASI_SDK_PATH/bin/llvm-ar crus crates/guest-rust/rt/src/libwit_bindgen_cabi.a \ + crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.o \ + crates/guest-rust/rt/src/wit_bindgen_cabi_wasip3.o diff --git a/crates/guest-rust/rt/README.md b/crates/guest-rust/rt/README.md index 2c9c8b2cc..c2824b04c 100644 --- a/crates/guest-rust/rt/README.md +++ b/crates/guest-rust/rt/README.md @@ -8,13 +8,13 @@ crate is to contain "runtime" code related to the macro-expansion of the be removed in some situations. This crate contains a precompiled object file and archive at -`src/cabi_realloc.o` and `src/libwit_bindgen_cabi_realloc.a`. This is compiled -from the source `src/cabi_realloc.c` and is checked in as precompiled to avoid -needing a C compiler at compile-time which isn't always available. This object -file is only used on wasm targets. +`src/wit_bindgen_cabi.o` and `src/libwit_bindgen_cabi.a`. This is compiled +from the source `src/wit_bindgen_cabi.c` and is checked in as precompiled to +avoid needing a C compiler at compile-time which isn't always available. This +object file is only used on wasm targets. The object file is compiled by -[this script]https://github.com/bytecodealliance/wit-bindgen/blob/main/ci/rebuild-libcabi-realloc.sh) +[this script]https://github.com/bytecodealliance/wit-bindgen/blob/main/ci/rebuild-libwit-bindgen-cabi.sh) and is verified in repository continuous integration that the checked-in versions match what CI produces. diff --git a/crates/guest-rust/rt/build.rs b/crates/guest-rust/rt/build.rs index 4bfbed9e0..c8c95090b 100644 --- a/crates/guest-rust/rt/build.rs +++ b/crates/guest-rust/rt/build.rs @@ -16,10 +16,10 @@ fn main() { let mut src = env::current_dir().unwrap(); src.push("src"); - src.push("libwit_bindgen_cabi_realloc.a"); + src.push("libwit_bindgen_cabi.a"); let dst_name = format!( - "wit_bindgen_cabi_realloc{}", + "wit_bindgen_cabi{}", env!("CARGO_PKG_VERSION").replace(".", "_") ); let dst = out_dir.join(format!("lib{dst_name}.a")); diff --git a/crates/guest-rust/rt/src/async_support.rs b/crates/guest-rust/rt/src/async_support.rs index 5a9f25fd0..5749e3364 100644 --- a/crates/guest-rust/rt/src/async_support.rs +++ b/crates/guest-rust/rt/src/async_support.rs @@ -8,6 +8,7 @@ extern crate std; use core::sync::atomic::{AtomicBool, Ordering}; use std::boxed::Box; use std::collections::HashMap; +use std::ffi::c_void; use std::fmt::{self, Debug, Display}; use std::future::Future; use std::mem; @@ -15,7 +16,7 @@ use std::pin::Pin; use std::ptr; use std::string::String; use std::sync::Arc; -use std::task::{Context, Poll, Wake, Waker}; +use std::task::{Context, Poll, Wake}; use std::vec::Vec; use futures::channel::oneshot; @@ -36,6 +37,7 @@ macro_rules! rtdebug { } mod abi_buffer; +mod cabi; mod future_support; mod stream_support; mod waitable; @@ -60,21 +62,32 @@ struct FutureState { tasks: Option>, /// The waitable set containing waitables created by this task, if any. waitable_set: Option, - /// A map of waitables to the corresponding waker and completion code. - /// - /// This is primarily filled in and managed by `WaitableOperation`. The - /// waker here comes straight from `std::task::Context` and the pointer is - /// otherwise stored within the `WaitableOperation` The raw pointer here - /// has a disconnected lifetime with each future but the management of the - /// internal states with respect to drop should always ensure that this is - /// only ever pointing to active waitable operations. - /// - /// When a waitable notification is received the corresponding entry in this - /// map is removed, the status code is filled in, and the waker is notified. - wakers: HashMap)>, + + /// State of all waitables in `waitable_set`, and the ptr/callback they're + /// associated with. + waitables: HashMap, + + /// Raw structure used to pass to `cabi::wasip3_task_set` + wasip3_task: cabi::wasip3_task, } impl FutureState { + fn new(future: BoxFuture) -> FutureState { + FutureState { + todo: 0, + tasks: Some([future].into_iter().collect()), + waitable_set: None, + waitables: HashMap::new(), + wasip3_task: cabi::wasip3_task { + // This pointer is filled in before calling `wasip3_task_set`. + ptr: ptr::null_mut(), + version: cabi::WASIP3_TASK_V1, + waitable_register, + waitable_unregister, + }, + } + } + fn get_or_create_waitable_set(&mut self) -> u32 { *self.waitable_set.get_or_insert_with(waitable_set_new) } @@ -88,7 +101,32 @@ impl FutureState { } fn remaining_work(&self) -> bool { - self.todo > 0 || !self.wakers.is_empty() + self.todo > 0 || !self.waitables.is_empty() + } +} + +unsafe extern "C" fn waitable_register( + ptr: *mut c_void, + waitable: u32, + callback: unsafe extern "C" fn(*mut c_void, u32), + callback_ptr: *mut c_void, +) -> *mut c_void { + let ptr = ptr.cast::(); + assert!(!ptr.is_null()); + (*ptr).add_waitable(waitable); + match (*ptr).waitables.insert(waitable, (callback_ptr, callback)) { + Some((prev, _)) => prev, + None => ptr::null_mut(), + } +} + +unsafe extern "C" fn waitable_unregister(ptr: *mut c_void, waitable: u32) -> *mut c_void { + let ptr = ptr.cast::(); + assert!(!ptr.is_null()); + (*ptr).remove_waitable(waitable); + match (*ptr).waitables.remove(&waitable) { + Some((prev, _)) => prev, + None => ptr::null_mut(), } } @@ -145,6 +183,22 @@ unsafe fn poll(state: *mut FutureState) -> Poll<()> { } } + // Finish our `wasip3_task` by initializing its self-referential pointer, + // and then register it for the duration of this function with + // `wasip3_task_set`. The previous value of `wasip3_task_set` will get + // restored when this function returns. + struct ResetTask(*mut cabi::wasip3_task); + impl Drop for ResetTask { + fn drop(&mut self) { + unsafe { + cabi::wasip3_task_set(self.0); + } + } + } + (*state).wasip3_task.ptr = state.cast(); + let prev = cabi::wasip3_task_set(&mut (*state).wasip3_task); + let _reset = ResetTask(prev); + loop { if let Some(futures) = (*state).tasks.as_mut() { let old = CURRENT; @@ -191,16 +245,9 @@ pub fn first_poll( future: impl Future + 'static, fun: impl FnOnce(&T) + 'static, ) -> i32 { - let state = Box::into_raw(Box::new(FutureState { - todo: 0, - tasks: Some( - [Box::pin(future.map(|v| fun(&v))) as BoxFuture] - .into_iter() - .collect(), - ), - waitable_set: None, - wakers: HashMap::new(), - })); + let state = Box::into_raw(Box::new(FutureState::new(Box::pin( + future.map(|v| fun(&v)), + )))); let done = unsafe { poll(state).is_ready() }; unsafe { callback_code(state, done) } } @@ -339,9 +386,8 @@ unsafe fn callback_with_state( "EVENT_{{STREAM,FUTURE}}_{{READ,WRITE}}({event0:#x}, {event1:#x}, {event2:#x})" ); (*state).remove_waitable(event1 as u32); - let (waker, code) = (*state).wakers.remove(&(event1 as u32)).unwrap(); - *code = Some(event2 as u32); - waker.wake(); + let (ptr, callback) = (*state).waitables.remove(&(event1 as u32)).unwrap(); + callback(ptr, event2 as u32); let done = poll(state).is_ready(); callback_code(state, done) @@ -469,16 +515,7 @@ pub fn spawn(future: impl Future + 'static) { // TODO: refactor so `'static` bounds aren't necessary pub fn block_on(future: impl Future + 'static) -> T { let (tx, mut rx) = oneshot::channel(); - let state = &mut FutureState { - todo: 0, - tasks: Some( - [Box::pin(future.map(move |v| drop(tx.send(v)))) as BoxFuture] - .into_iter() - .collect(), - ), - waitable_set: None, - wakers: HashMap::new(), - }; + let state = &mut FutureState::new(Box::pin(future.map(move |v| drop(tx.send(v)))) as BoxFuture); loop { match unsafe { poll(state) } { Poll::Ready(()) => break rx.try_recv().unwrap().unwrap(), diff --git a/crates/guest-rust/rt/src/async_support/cabi.rs b/crates/guest-rust/rt/src/async_support/cabi.rs new file mode 100644 index 000000000..be9945de9 --- /dev/null +++ b/crates/guest-rust/rt/src/async_support/cabi.rs @@ -0,0 +1,112 @@ +//! Definition of the "C ABI" of how imported functions interact with exported +//! tasks. +//! +//! Ok this crate is written in Rust, why in the world does this exist? This +//! comment is intended to explain this rationale but the tl;dr; is we want +//! this to work: +//! +//! * Within a single component ... +//! * One rust crate uses `wit-bindgen 0.A.0` to generate an exported function. +//! * One rust crate uses `wit-bindgen 0.B.0` to bind an imported function. +//! * The two crates are connected in the application with +//! `std::future::Future`. +//! +//! Without this module this situation won't work because 0.A.0 has no +//! knowledge of 0.B.0 meaning that 0.B.0 has no means of inserting a `waitable` +//! into the `waitable-set` managed by 0.A.0's export. +//! +//! To solve this problem the long-term intention is that something will live +//! in `wasi-libc` itself, but in the meantime it's living "somewhere" within +//! `wit-bindgen 0.*.0`. Specifically all `wit-bindgen` versions will +//! reference, via C linkage, a single function which is used to manipulate a +//! single pointer in linear memory. This pointer is a `wasip3_task` structure +//! which has all the various fields to use it. +//! +//! The `wasip3_task_set` symbol is itself defined in C inside of the +//! `src/wit_bindgen_cabi.c` file at this time, specifically because it's +//! annotated with `__weak__` meaning that any definition of it suffices. This +//! isn't possible to define in stable Rust (specifically `__weak__`). +//! +//! Once `wasip3_task_set` is defined everything then operates via indirection, +//! aka based off the returned pointer. The intention is that exported functions +//! will set this (it's sort of like an executor) and then imported functions +//! will all use this as the source of registering waitables. In the end that +//! means that it's possible to share types with `std::future::Future` that +//! are backed at the ABI level with this "channel". +//! +//! In the future it's hoped that this can move into `wasi-libc` itself, or if +//! `wasi-libc` provides something else that would be prioritized over this. +//! For now this is basically an affordance that we're going to be frequently +//! releaseing new major versions of `wit-bindgen` and we don't want to force +//! applications to all be using the exact same version of the bindings +//! generator and async bindings. +//! +//! Additionally for now this file is serving as documentation of this +//! interface. + +use core::ffi::c_void; + +#[cfg(target_family = "wasm")] +extern "C" { + /// Sets the global task pointer to `ptr` provided. Returns the previous + /// value. + /// + /// This function acts as a dual getter and a setter. To get the + /// current task pointer a dummy `ptr` can be provided (e.g. NULL) and then + /// it's passed back when you're done working with it. When setting the + /// current task pointer it's recommended to call this and then call it + /// again with the previous value when the tasks's work is done. + /// + /// For executors they need to ensure that the `ptr` passed in lives for + /// the entire lifetime of the component model task. + pub fn wasip3_task_set(ptr: *mut wasip3_task) -> *mut wasip3_task; +} + +#[cfg(not(target_family = "wasm"))] +pub unsafe extern "C" fn wasip3_task_set(ptr: *mut wasip3_task) -> *mut wasip3_task { + let _ = ptr; + unreachable!(); +} + +/// The first version of `wasip3_task` which implies the existence of the +/// fields `ptr`, `waitable_register`, and `waitable_unregister`. +pub const WASIP3_TASK_V1: u32 = 1; + +/// Indirect "vtable" used to connect imported functions and exported tasks. +/// Executors (e.g. exported functions) define and manage this while imports +/// use it. +#[repr(C)] +pub struct wasip3_task { + /// Currently `WASIP3_TASK_V1`. Indicates what fields are present next + /// depending on the version here. + pub version: u32, + + /// Private pointer owned by the `wasip3_task` itself, passed to callbacks + /// below as the first argument. + pub ptr: *mut c_void, + + /// Register a new `waitable` for this exported task. + /// + /// This exported task will add `waitable` to its `waitable-set`. When it + /// becomes ready then `callback` will be invoked with the ready code as + /// well as the `callback_ptr` provided. + /// + /// If `waitable` was previously registered with this task then the + /// previous `callback_ptr` is returned. Otherwise `NULL` is returned. + /// + /// It's the caller's responsibility to ensure that `callback_ptr` is valid + /// until `callback` is invoked, `waitable_unregister` is invoked, or + /// `waitable_register` is called again to overwrite the value. + pub waitable_register: unsafe extern "C" fn( + ptr: *mut c_void, + waitable: u32, + callback: unsafe extern "C" fn(callback_ptr: *mut c_void, code: u32), + callback_ptr: *mut c_void, + ) -> *mut c_void, + + /// Removes the `waitable` from this task's `waitable-set`. + /// + /// Returns the `callback_ptr` passed to `waitable_register` if present, or + /// `NULL` if it's not present. + pub waitable_unregister: unsafe extern "C" fn(ptr: *mut c_void, waitable: u32) -> *mut c_void, +} diff --git a/crates/guest-rust/rt/src/async_support/waitable.rs b/crates/guest-rust/rt/src/async_support/waitable.rs index 956fc46aa..129151394 100644 --- a/crates/guest-rust/rt/src/async_support/waitable.rs +++ b/crates/guest-rust/rt/src/async_support/waitable.rs @@ -1,11 +1,13 @@ //! Generic support for "any waitable" and performing asynchronous operations on //! that waitable. -use super::results; +use super::{cabi, results}; +use std::ffi::c_void; use std::marker; use std::mem; use std::pin::Pin; -use std::task::{Context, Poll}; +use std::ptr; +use std::task::{Context, Poll, Waker}; /// Generic future-based operation on any "waitable" in the component model. /// @@ -42,6 +44,8 @@ struct CompletionStatus { /// happens. code: Option, + waker: Option, + /// This is necessary to ensure that `Pin<&mut CompletionStatus>` carries /// the "pin guarantee", basically to mean that it's not safe to construct /// `Pin<&mut CompletionStatus>` and it must somehow require `unsafe` code. @@ -130,6 +134,7 @@ where state: WaitableOperationState::Start(state), completion_status: CompletionStatus { code: None, + waker: None, _pinned: marker::PhantomPinned, }, } @@ -154,12 +159,38 @@ where /// * Fill in `completion_status` with the result of a completion event. /// * Call `cx.waker().wake()`. pub fn register_waker(self: Pin<&mut Self>, waitable: u32, cx: &mut Context) { - let (_, completion_status) = self.pin_project(); + let (_, mut completion_status) = self.pin_project(); + debug_assert!(completion_status.as_mut().code_mut().is_none()); + *completion_status.as_mut().waker_mut() = Some(cx.waker().clone()); + + // SAFETY: There's quite a lot going on here. First is the usage of + // `task` below, and for that see `unregister_waker` below for why this + // pattern should be safe. + // + // Otherwise we're handing off a pointer to `completion_status` to the + // `task` itself. That should be safe as we're guaranteed, via + // `Pin<&mut Self>`, that before `&mut Self` is deallocated the + // destructor will be run which will perform de-registration via + // cancellation. unsafe { - (*super::CURRENT).add_waitable(waitable); - (*super::CURRENT) - .wakers - .insert(waitable, (cx.waker().clone(), completion_status.code_mut())); + let task = cabi::wasip3_task_set(ptr::null_mut()); + assert!(!task.is_null()); + assert!((*task).version >= cabi::WASIP3_TASK_V1); + let ptr: *mut CompletionStatus = completion_status.get_unchecked_mut(); + let prev = ((*task).waitable_register)((*task).ptr, waitable, cabi_wake, ptr.cast()); + // We might be inserting a waker for the first time or overwriting + // the previous waker. Only assert the expected value here if the + // previous value was non-null. + if !prev.is_null() { + assert_eq!(ptr, prev.cast()); + } + cabi::wasip3_task_set(task); + } + + unsafe extern "C" fn cabi_wake(ptr: *mut c_void, code: u32) { + let ptr: &mut CompletionStatus = &mut *ptr.cast::(); + ptr.code = Some(code); + ptr.waker.take().unwrap().wake() } } @@ -169,17 +200,42 @@ where /// This relinquishes control of the original `completion_status` pointer /// passed to `register_waker` after this call has completed. pub fn unregister_waker(self: Pin<&mut Self>, waitable: u32) { + // SAFETY: the contract of `wasip3_task_set` is that the returned + // pointer is valid for the lifetime of our entire task, so it's valid + // for this stack frame. Additionally we assert it's non-null to + // double-check it's initialized and additionally check the version for + // the fields that we access. + // + // Otherwise the `waitable_unregister` callback should be safe because: + // + // * We're fulfilling the contract where the first argument must be + // `(*task).ptr` + // * We own the `waitable` that we're passing in, so we're fulfilling + // the contract that arbitrary waitables for other units of work + // aren't being manipulated. unsafe { - (*super::CURRENT).remove_waitable(waitable); - let _prev = (*super::CURRENT).wakers.remove(&waitable); - // Note that `_prev` here is not guaranteed to be either `Some` or - // `None`. A racy completion notification may have come in and + let task = cabi::wasip3_task_set(ptr::null_mut()); + assert!(!task.is_null()); + assert!((*task).version >= cabi::WASIP3_TASK_V1); + let prev = ((*task).waitable_unregister)((*task).ptr, waitable); + + // Note that `_prev` here is not guaranteed to be either `NULL` or + // not. A racy completion notification may have come in and // removed our waitable from the map even though we're in the // `InProgress` state, meaning it may not be present. // // The main thing is that after this method is called the // internal `completion_status` is guaranteed to no longer be in - // `FuturesState`. + // `task`. + // + // Note, though, that if present this must be our `CompletionStatus` + // pointer. + if !prev.is_null() { + let ptr: *mut CompletionStatus = self.pin_project().1.get_unchecked_mut(); + assert_eq!(ptr, prev.cast()); + } + + cabi::wasip3_task_set(task); } } @@ -374,4 +430,8 @@ impl CompletionStatus { fn code_mut(self: Pin<&mut Self>) -> &mut Option { unsafe { &mut self.get_unchecked_mut().code } } + + fn waker_mut(self: Pin<&mut Self>) -> &mut Option { + unsafe { &mut self.get_unchecked_mut().waker } + } } diff --git a/crates/guest-rust/rt/src/cabi_realloc.o b/crates/guest-rust/rt/src/cabi_realloc.o deleted file mode 100644 index 3ce8afc46..000000000 Binary files a/crates/guest-rust/rt/src/cabi_realloc.o and /dev/null differ diff --git a/crates/guest-rust/rt/src/lib.rs b/crates/guest-rust/rt/src/lib.rs index 31b60afb0..608d04846 100644 --- a/crates/guest-rust/rt/src/lib.rs +++ b/crates/guest-rust/rt/src/lib.rs @@ -13,9 +13,9 @@ use core::ptr::{self, NonNull}; #[doc(hidden)] pub use bitflags; -/// For more information about this see `./ci/rebuild-libcabi-realloc.sh`. +/// For more information about this see `./ci/rebuild-libwit-bindgen-cabi.sh`. #[cfg(not(target_env = "p2"))] -mod cabi_realloc; +mod wit_bindgen_cabi; /// This function is called from generated bindings and will be deleted by /// the linker. The purpose of this function is to force a reference to the @@ -23,7 +23,7 @@ mod cabi_realloc; /// command line. That way `wasm-ld` will pick it up, see it needs to be /// exported, and then export it. /// -/// For more information about this see `./ci/rebuild-libcabi-realloc.sh`. +/// For more information about this see `./ci/rebuild-libwit-bindgen-cabi.sh`. pub fn maybe_link_cabi_realloc() { #[cfg(all(target_family = "wasm", not(target_env = "p2")))] { @@ -55,7 +55,7 @@ pub fn maybe_link_cabi_realloc() { /// NB: this function is called by a generated function in the /// `cabi_realloc` module above. It's otherwise never explicitly called. /// -/// For more information about this see `./ci/rebuild-libcabi-realloc.sh`. +/// For more information about this see `./ci/rebuild-libwit-bindgen-cabi.sh`. #[cfg(not(target_env = "p2"))] pub unsafe fn cabi_realloc( old_ptr: *mut u8, diff --git a/crates/guest-rust/rt/src/libwit_bindgen_cabi.a b/crates/guest-rust/rt/src/libwit_bindgen_cabi.a new file mode 100644 index 000000000..bd13c66e7 Binary files /dev/null and b/crates/guest-rust/rt/src/libwit_bindgen_cabi.a differ diff --git a/crates/guest-rust/rt/src/libwit_bindgen_cabi_realloc.a b/crates/guest-rust/rt/src/libwit_bindgen_cabi_realloc.a deleted file mode 100644 index c14633576..000000000 Binary files a/crates/guest-rust/rt/src/libwit_bindgen_cabi_realloc.a and /dev/null differ diff --git a/crates/guest-rust/rt/src/wit_bindgen_cabi.c b/crates/guest-rust/rt/src/wit_bindgen_cabi.c new file mode 100644 index 000000000..e7cf56f5f --- /dev/null +++ b/crates/guest-rust/rt/src/wit_bindgen_cabi.c @@ -0,0 +1,20 @@ +// This file is generated by ./ci/rebuild-libwit-bindgen-cabi.sh + +#include +#include + +extern void *cabi_realloc_wit_bindgen_0_41_0(void *ptr, size_t old_size, size_t align, size_t new_size); + +__attribute__((__weak__, __export_name__("cabi_realloc"))) +void *cabi_realloc(void *ptr, size_t old_size, size_t align, size_t new_size) { + return cabi_realloc_wit_bindgen_0_41_0(ptr, old_size, align, new_size); +} + +static void *WASIP3_TASK = NULL; + +__attribute__((__weak__)) +void *wasip3_task_set(void *ptr) { + void *ret = WASIP3_TASK; + WASIP3_TASK = ptr; + return ret; +} diff --git a/crates/guest-rust/rt/src/wit_bindgen_cabi.o b/crates/guest-rust/rt/src/wit_bindgen_cabi.o new file mode 100644 index 000000000..905870b49 Binary files /dev/null and b/crates/guest-rust/rt/src/wit_bindgen_cabi.o differ diff --git a/crates/guest-rust/rt/src/cabi_realloc.rs b/crates/guest-rust/rt/src/wit_bindgen_cabi.rs similarity index 78% rename from crates/guest-rust/rt/src/cabi_realloc.rs rename to crates/guest-rust/rt/src/wit_bindgen_cabi.rs index cc738191e..126cd2142 100644 --- a/crates/guest-rust/rt/src/cabi_realloc.rs +++ b/crates/guest-rust/rt/src/wit_bindgen_cabi.rs @@ -1,4 +1,4 @@ -// This file is generated by ./ci/rebuild-libcabi-realloc.sh +// This file is generated by ./ci/rebuild-libwit-bindgen-cabi.sh #[unsafe(no_mangle)] pub unsafe extern "C" fn cabi_realloc_wit_bindgen_0_41_0( diff --git a/crates/guest-rust/rt/src/cabi_realloc.c b/crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.c similarity index 84% rename from crates/guest-rust/rt/src/cabi_realloc.c rename to crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.c index 9847aef29..4fa88e67e 100644 --- a/crates/guest-rust/rt/src/cabi_realloc.c +++ b/crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.c @@ -1,4 +1,4 @@ -// This file is generated by ./ci/rebuild-libcabi-realloc.sh +// This file is generated by ./ci/rebuild-libwit-bindgen-cabi.sh #include diff --git a/crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.o b/crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.o new file mode 100644 index 000000000..c02415fd3 Binary files /dev/null and b/crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.o differ diff --git a/crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.rs b/crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.rs new file mode 100644 index 000000000..126cd2142 --- /dev/null +++ b/crates/guest-rust/rt/src/wit_bindgen_cabi_realloc.rs @@ -0,0 +1,11 @@ +// This file is generated by ./ci/rebuild-libwit-bindgen-cabi.sh + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn cabi_realloc_wit_bindgen_0_41_0( + old_ptr: *mut u8, + old_len: usize, + align: usize, + new_len: usize, +) -> *mut u8 { + crate::cabi_realloc(old_ptr, old_len, align, new_len) +} diff --git a/crates/guest-rust/rt/src/wit_bindgen_cabi_wasip3.c b/crates/guest-rust/rt/src/wit_bindgen_cabi_wasip3.c new file mode 100644 index 000000000..2e4a50617 --- /dev/null +++ b/crates/guest-rust/rt/src/wit_bindgen_cabi_wasip3.c @@ -0,0 +1,12 @@ +// This file is generated by ./ci/rebuild-libwit-bindgen-cabi.sh + +#include + +static void *WASIP3_TASK = NULL; + +__attribute__((__weak__)) +void *wasip3_task_set(void *ptr) { + void *ret = WASIP3_TASK; + WASIP3_TASK = ptr; + return ret; +} diff --git a/crates/guest-rust/rt/src/wit_bindgen_cabi_wasip3.o b/crates/guest-rust/rt/src/wit_bindgen_cabi_wasip3.o new file mode 100644 index 000000000..41f77bd73 Binary files /dev/null and b/crates/guest-rust/rt/src/wit_bindgen_cabi_wasip3.o differ