Refactor shared memory internals, expose embedder methods (#5311)
This commit refactors the internals of `wasmtime_runtime::SharedMemory` a bit to expose the necessary functions to invoke from the `wasmtime::SharedMemory` layer. Notably some items are moved out of the `RwLock` from prior, such as the type and the `VMMemoryDefinition`. Additionally the organization around the `atomic_*` methods has been redone to ensure that the `wasmtime`-layer abstraction has a single method to call into which everything else uses as well.
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
use crate::store::{StoreData, StoreOpaque, Stored};
|
||||
use crate::trampoline::generate_memory_export;
|
||||
use crate::Trap;
|
||||
use crate::{AsContext, AsContextMut, Engine, MemoryType, StoreContext, StoreContextMut};
|
||||
use anyhow::{bail, Result};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::convert::TryFrom;
|
||||
use std::slice;
|
||||
use std::time::Instant;
|
||||
use wasmtime_environ::MemoryPlan;
|
||||
use wasmtime_runtime::{RuntimeLinearMemory, VMMemoryImport};
|
||||
|
||||
pub use wasmtime_runtime::WaitResult;
|
||||
|
||||
/// Error for out of bounds [`Memory`] access.
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
@@ -780,7 +784,7 @@ impl SharedMemory {
|
||||
/// the maximum limits of this memory. A
|
||||
/// [`ResourceLimiter`](crate::ResourceLimiter) is another example of
|
||||
/// preventing a memory to grow.
|
||||
pub fn grow(&mut self, delta: u64) -> Result<u64> {
|
||||
pub fn grow(&self, delta: u64) -> Result<u64> {
|
||||
match self.0.grow(delta, None)? {
|
||||
Some((old_size, _new_size)) => {
|
||||
// For shared memory, the `VMMemoryDefinition` is updated inside
|
||||
@@ -791,6 +795,87 @@ impl SharedMemory {
|
||||
}
|
||||
}
|
||||
|
||||
/// Equivalent of the WebAssembly `memory.atomic.notify` instruction for
|
||||
/// this shared memory.
|
||||
///
|
||||
/// This method allows embedders to notify threads blocked on the specified
|
||||
/// `addr`, an index into wasm linear memory. Threads could include
|
||||
/// wasm threads blocked on a `memory.atomic.wait*` instruction or embedder
|
||||
/// threads blocked on [`SharedMemory::atomic_wait32`], for example.
|
||||
///
|
||||
/// The `count` argument is the number of threads to wake up.
|
||||
///
|
||||
/// This function returns the number of threads awoken.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if `addr` is not within bounds or
|
||||
/// not aligned to a 4-byte boundary.
|
||||
pub fn atomic_notify(&self, addr: u64, count: u32) -> Result<u32, Trap> {
|
||||
self.0.atomic_notify(addr, count)
|
||||
}
|
||||
|
||||
/// Equivalent of the WebAssembly `memory.atomic.wait32` instruction for
|
||||
/// this shared memory.
|
||||
///
|
||||
/// This method allows embedders to block the current thread until notified
|
||||
/// via the `memory.atomic.notify` instruction or the
|
||||
/// [`SharedMemory::atomic_notify`] method, enabling synchronization with
|
||||
/// the wasm guest as desired.
|
||||
///
|
||||
/// The `expected` argument is the expected 32-bit value to be stored at
|
||||
/// the byte address `addr` specified. The `addr` specified is an index
|
||||
/// into this linear memory.
|
||||
///
|
||||
/// The optional `timeout` argument is the point in time after which the
|
||||
/// calling thread is guaranteed to be woken up. Blocking will not occur
|
||||
/// past this point.
|
||||
///
|
||||
/// This function returns one of three possible values:
|
||||
///
|
||||
/// * `WaitResult::Ok` - this function, loaded the value at `addr`, found
|
||||
/// it was equal to `expected`, and then blocked (all as one atomic
|
||||
/// operation). The thread was then awoken with a `memory.atomic.notify`
|
||||
/// instruction or the [`SharedMemory::atomic_notify`] method.
|
||||
/// * `WaitResult::Mismatch` - the value at `addr` was loaded but was not
|
||||
/// equal to `expected` so the thread did not block and immediately
|
||||
/// returned.
|
||||
/// * `WaitResult::TimedOut` - all the steps of `Ok` happened, except this
|
||||
/// thread was woken up due to a timeout.
|
||||
///
|
||||
/// This function will not return due to spurious wakeups.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if `addr` is not within bounds or
|
||||
/// not aligned to a 4-byte boundary.
|
||||
pub fn atomic_wait32(
|
||||
&self,
|
||||
addr: u64,
|
||||
expected: u32,
|
||||
timeout: Option<Instant>,
|
||||
) -> Result<WaitResult, Trap> {
|
||||
self.0.atomic_wait32(addr, expected, timeout)
|
||||
}
|
||||
|
||||
/// Equivalent of the WebAssembly `memory.atomic.wait64` instruction for
|
||||
/// this shared memory.
|
||||
///
|
||||
/// For more information see [`SharedMemory::atomic_wait32`].
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns the same error as [`SharedMemory::atomic_wait32`] except that
|
||||
/// the specified address must be 8-byte aligned instead of 4-byte aligned.
|
||||
pub fn atomic_wait64(
|
||||
&self,
|
||||
addr: u64,
|
||||
expected: u64,
|
||||
timeout: Option<Instant>,
|
||||
) -> Result<WaitResult, Trap> {
|
||||
self.0.atomic_wait64(addr, expected, timeout)
|
||||
}
|
||||
|
||||
/// Return a reference to the [`Engine`] used to configure the shared
|
||||
/// memory.
|
||||
pub(crate) fn engine(&self) -> &Engine {
|
||||
@@ -824,7 +909,8 @@ impl SharedMemory {
|
||||
.unwrap();
|
||||
let shared_memory = memory
|
||||
.as_shared_memory()
|
||||
.expect("unable to convert from a shared memory");
|
||||
.expect("unable to convert from a shared memory")
|
||||
.clone();
|
||||
Self(shared_memory, store.engine().clone())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user