Skip to content

Commit

Permalink
c-api: Expose host memory creation (#7115)
Browse files Browse the repository at this point in the history
* c-api: Expose host memory creation

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>

* c-api: Review feedback

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>

* c-api: Fix invalid reference in docs

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>

* c-api: Fix doxygen documentation

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>

---------

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
  • Loading branch information
rockwotj authored Oct 2, 2023
1 parent d8ca357 commit 80c4542
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 3 deletions.
93 changes: 93 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,99 @@ 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);


/**
* Return the data from a LinearMemory instance.
*
* 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 see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html
*/
typedef uint8_t *(*wasmtime_memory_get_callback_t)(
void *env,
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 *env,
size_t new_size);

/**
* A LinearMemory instance created from a #wasmtime_new_memory_callback_t.
*
* For more information see the Rust documentation at
* https://docs.wasmtime.dev/api/wasmtime/trait.LinearMemory.html
*/
typedef struct {
/// User provided value to be passed to get_memory and grow_memory
void *env;
/// Callback to get the memory and size of this LinearMemory
wasmtime_memory_get_callback_t get_memory;
/// Callback to request growing the memory
wasmtime_memory_grow_callback_t grow_memory;
/// An optional finalizer for env
void (*finalizer)(void*);
} wasmtime_linear_memory_t;

/**
* A callback to create a new LinearMemory from the specified parameters.
*
* The result should be written to `memory_ret` and wasmtime will own the values written
* into that struct.
*
* This callback must be thread-safe.
*
* 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)(
void *env,
const wasm_memorytype_t *ty,
size_t minimum,
size_t maximum,
size_t reserved_size_in_bytes,
size_t guard_size_in_bytes,
wasmtime_linear_memory_t *memory_ret);

/**
* 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 {
/// User provided value to be passed to new_memory
void* env;
/// The callback to create new memory, must be thread safe
wasmtime_new_memory_callback_t new_memory;
/// An optional finalizer for env.
void (*finalizer)(void*);
} 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.
*
* The config does **not** take ownership of the #wasmtime_memory_creator_t passed in, but
* instead copies all the values in the struct.
*
* 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
158 changes: 155 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::mem::MaybeUninit;
use std::ops::Range;
use std::os::raw::c_char;
use wasmtime::{Config, OptLevel, ProfilingStrategy, Strategy};
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,151 @@ 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_memory_get_callback_t = extern "C" fn(
env: *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(env: *mut std::ffi::c_void, new_size: usize) -> Option<Box<wasmtime_error_t>>;

#[repr(C)]
pub struct wasmtime_linear_memory_t {
env: *mut std::ffi::c_void,
get_memory: wasmtime_memory_get_callback_t,
grow_memory: wasmtime_memory_grow_callback_t,
finalizer: Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
}

pub type wasmtime_new_memory_callback_t = extern "C" fn(
env: *mut std::ffi::c_void,
ty: &wasm_memorytype_t,
minimum: usize,
maximum: usize,
reserved_size_in_bytes: usize,
guard_size_in_bytes: usize,
memory_ret: *mut wasmtime_linear_memory_t,
) -> Option<Box<wasmtime_error_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(())
}
}
}

#[repr(C)]
pub struct wasmtime_memory_creator_t {
env: *mut std::ffi::c_void,
new_memory: wasmtime_new_memory_callback_t,
finalizer: Option<extern "C" fn(arg1: *mut std::ffi::c_void)>,
}

struct CHostMemoryCreator {
foreign: crate::ForeignData,
new_memory: wasmtime_new_memory_callback_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 = MaybeUninit::uninit();
let cb = self.new_memory;
let error = cb(
self.foreign.data,
&wasm_memorytype_t::new(ty),
minimum,
maximum.unwrap_or(usize::MAX),
reserved_size_in_bytes.unwrap_or(0),
guard_size_in_bytes,
memory.as_mut_ptr(),
);
match error {
None => {
let memory = unsafe { memory.assume_init() };
let foreign = crate::ForeignData {
data: memory.env,
finalizer: memory.finalizer,
};
Ok(Box::new(CHostLinearMemory {
foreign,
get_memory: memory.get_memory,
grow_memory: memory.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: &wasmtime_memory_creator_t,
) {
c.config.with_host_memory(Arc::new(CHostMemoryCreator {
foreign: crate::ForeignData {
data: creator.env,
finalizer: creator.finalizer,
},
new_memory: creator.new_memory,
}));
}

0 comments on commit 80c4542

Please sign in to comment.