Skip to content

Commit

Permalink
c-api: Expose host memory creation
Browse files Browse the repository at this point in the history
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
  • Loading branch information
rockwotj committed Sep 29, 2023
1 parent b7c0eae commit 5926b1a
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 3 deletions.
67 changes: 67 additions & 0 deletions crates/c-api/include/wasmtime/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,73 @@ WASM_API_EXTERN void wasmtime_config_cranelift_flag_enable(wasm_config_t*, const
*/
WASM_API_EXTERN void wasmtime_config_cranelift_flag_set(wasm_config_t*, const char *key, const char *value);

/**
* A callback to create a new LinearMemory from the specified parameters.
*
* The result should be written to `memory_ret` and optionally a finalizer for the returned memory
* can be returned in the finalizer pointer.
*
* For more information about the parameters see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.MemoryCreator.html#tymethod.new_memory
*/
typedef wasmtime_error_t *(*wasmtime_new_memory_callback_t)(
wasm_memorytype_t *ty,
size_t minimum,
size_t maximum,
size_t reserved_size_in_bytes,
size_t guard_size_in_bytes,
void **memory_ret,
void (**finalizer)(void*));

/**
* Return the data from a LinearMemory instance created from a #wasmtime_new_memory_t callback.
*
* The size in bytes as well as the maximum number of bytes that can be allocated should be
* returned as well.
*
* For more information about the parameters see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html
*/
typedef void *(*wasmtime_memory_get_callback_t)(
void *memory_ptr,
size_t *byte_size,
size_t *maximum_byte_size);

/**
* Grow the memory to the `new_size` in bytes.
*
* For more information about the parameters see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html#tymethod.grow_to
*/
typedef wasmtime_error_t *(*wasmtime_memory_grow_callback_t)(
void *memory_ptr,
size_t new_size);

/**
* A representation of custom memory creator and methods for an instance of LinearMemory.
*
* For more information see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.MemoryCreator.html
*/
typedef struct {
wasmtime_new_memory_callback_t new_memory;
wasmtime_memory_get_callback_t get_memory;
wasmtime_memory_grow_callback_t grow_memory;
} wasmtime_memory_creator_t;

/**
* Sets a custom memory creator.
*
* Custom memory creators are used when creating host Memory objects or when creating instance
* linear memories for the on-demand instance allocation strategy.
*
* For more information see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/struct.Config.html#method.with_host_memory
*/
WASM_API_EXTERN void wasmtime_config_host_memory_creator_set(
wasm_config_t*,
wasmtime_memory_creator_t*);

#ifdef __cplusplus
} // extern "C"
#endif
Expand Down
146 changes: 143 additions & 3 deletions crates/c-api/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@
// them with the default set of features enabled.
#![cfg_attr(not(feature = "cache"), allow(unused_imports))]

use crate::{handle_result, wasmtime_error_t};
use std::ffi::CStr;
use crate::{handle_result, wasm_memorytype_t, wasmtime_error_t};
use std::ops::Range;
use std::os::raw::c_char;
use wasmtime::{Config, OptLevel, ProfilingStrategy, Strategy};
use std::ptr;
use std::{ffi::CStr, sync::Arc};
use wasmtime::{
Config, LinearMemory, MemoryCreator, OptLevel, ProfilingStrategy, Result, Strategy,
};

#[repr(C)]
#[derive(Clone)]
Expand Down Expand Up @@ -255,3 +259,139 @@ pub unsafe extern "C" fn wasmtime_config_cranelift_flag_set(
let value = CStr::from_ptr(value).to_str().expect("not valid utf-8");
c.config.cranelift_flag_set(flag, value);
}

pub type wasmtime_new_memory_callback_t = extern "C" fn(
ty: wasm_memorytype_t,
minimum: usize,
maximum: usize,
reserved_size_in_bytes: usize,
guard_size_in_bytes: usize,
memory_ret: &mut *mut std::ffi::c_void,
finalizer_ret: &mut Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
) -> Option<Box<wasmtime_error_t>>;

pub type wasmtime_memory_get_callback_t = extern "C" fn(
memory_ptr: *mut std::ffi::c_void,
byte_size: &mut usize,
maximum_byte_size: &mut usize,
) -> *mut u8;

pub type wasmtime_memory_grow_callback_t = extern "C" fn(
memory_ptr: *mut std::ffi::c_void,
new_size: usize,
) -> Option<Box<wasmtime_error_t>>;

#[repr(C)]
pub struct wasmtime_memory_creator_t {
new_memory: wasmtime_new_memory_callback_t,
get_memory: wasmtime_memory_get_callback_t,
grow_memory: wasmtime_memory_grow_callback_t,
}

struct CHostLinearMemory {
foreign: crate::ForeignData,
get_memory: wasmtime_memory_get_callback_t,
grow_memory: wasmtime_memory_grow_callback_t,
}

unsafe impl LinearMemory for CHostLinearMemory {
fn byte_size(&self) -> usize {
let mut byte_size = 0;
let mut maximum_byte_size = 0;
let cb = self.get_memory;
cb(self.foreign.data, &mut byte_size, &mut maximum_byte_size);
return byte_size;
}
fn maximum_byte_size(&self) -> Option<usize> {
let mut byte_size = 0;
let mut maximum_byte_size = 0;
let cb = self.get_memory;
cb(self.foreign.data, &mut byte_size, &mut maximum_byte_size);
if maximum_byte_size == 0 {
None
} else {
Some(maximum_byte_size)
}
}
fn as_ptr(&self) -> *mut u8 {
let mut byte_size = 0;
let mut maximum_byte_size = 0;
let cb = self.get_memory;
cb(self.foreign.data, &mut byte_size, &mut maximum_byte_size)
}
fn wasm_accessible(&self) -> Range<usize> {
let mut byte_size = 0;
let mut maximum_byte_size = 0;
let cb = self.get_memory;
let ptr = cb(self.foreign.data, &mut byte_size, &mut maximum_byte_size);
Range {
start: ptr as usize,
end: ptr as usize + byte_size,
}
}
fn grow_to(&mut self, new_size: usize) -> Result<()> {
let cb = self.grow_memory;
let error = cb(self.foreign.data, new_size);
if let Some(err) = error {
Err((*err).into())
} else {
Ok(())
}
}
}

struct CHostMemoryCreator {
creator: Box<wasmtime_memory_creator_t>,
}
unsafe impl Send for CHostMemoryCreator {}
unsafe impl Sync for CHostMemoryCreator {}

unsafe impl MemoryCreator for CHostMemoryCreator {
fn new_memory(
&self,
ty: wasmtime::MemoryType,
minimum: usize,
maximum: Option<usize>,
reserved_size_in_bytes: Option<usize>,
guard_size_in_bytes: usize,
) -> Result<Box<dyn wasmtime::LinearMemory>, String> {
let mut memory = ptr::null_mut();
let mut finalizer = None;
let cb = self.creator.new_memory;
let error = cb(
wasm_memorytype_t::new(ty),
minimum,
maximum.unwrap_or(usize::MAX),
reserved_size_in_bytes.unwrap_or(0),
guard_size_in_bytes,
&mut memory,
&mut finalizer,
);
match error {
None => {
let foreign = crate::ForeignData {
data: memory,
finalizer,
};
Ok(Box::new(CHostLinearMemory {
foreign,
get_memory: self.creator.get_memory,
grow_memory: self.creator.grow_memory,
}))
}
Some(err) => {
let err: anyhow::Error = (*err).into();
Err(format!("{}", err))
}
}
}
}

#[no_mangle]
pub unsafe extern "C" fn wasmtime_config_host_memory_creator_set(
c: &mut wasm_config_t,
creator: Box<wasmtime_memory_creator_t>,
) {
c.config
.with_host_memory(Arc::new(CHostMemoryCreator { creator }));
}

0 comments on commit 5926b1a

Please sign in to comment.