Path: blob/main/examples/min-platform/embedding/src/allocator.rs
2450 views
//! An allocator definition for this embedding.1//!2//! The Rust standard library and Wasmtime require a memory allocator to be3//! configured. For custom embeddings of Wasmtime this might likely already be4//! defined elsewhere in the system in which case that should be used. This file5//! contains an example implementation using the Rust `dlmalloc` crate using6//! memory created by `wasmtime_*` platform symbols. This provides a file that7//! manages memory without any extra runtime dependencies, but this is just an8//! example.9//!10//! Allocators in Rust are configured with the `#[global_allocator]` attribute11//! and the `GlobalAlloc for T` trait impl. This should be used when hooking12//! up to an allocator elsewhere in the system.1314use alloc::alloc::{GlobalAlloc, Layout};15use core::cell::UnsafeCell;16use core::ops::{Deref, DerefMut};17use core::ptr;18use core::sync::atomic::{19AtomicBool,20Ordering::{Acquire, Release},21};22use dlmalloc::Dlmalloc;2324#[global_allocator]25static MALLOC: MyGlobalDmalloc = MyGlobalDmalloc {26dlmalloc: Mutex::new(Dlmalloc::new_with_allocator(MyAllocator)),27};2829struct MyGlobalDmalloc {30dlmalloc: Mutex<Dlmalloc<MyAllocator>>,31}3233struct MyAllocator;3435unsafe impl GlobalAlloc for MyGlobalDmalloc {36unsafe fn alloc(&self, layout: Layout) -> *mut u8 {37unsafe {38self.dlmalloc39.try_lock()40.unwrap()41.malloc(layout.size(), layout.align())42}43}4445unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {46unsafe {47self.dlmalloc48.try_lock()49.unwrap()50.calloc(layout.size(), layout.align())51}52}5354unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {55unsafe {56self.dlmalloc57.try_lock()58.unwrap()59.realloc(ptr, layout.size(), layout.align(), new_size)60}61}6263unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {64unsafe {65self.dlmalloc66.try_lock()67.unwrap()68.free(ptr, layout.size(), layout.align())69}70}71}7273#[cfg(not(feature = "wasi"))]74const INITIAL_HEAP_SIZE: usize = 64 * 1024;75// The wasi component requires a larger heap than the module tests76#[cfg(feature = "wasi")]77const INITIAL_HEAP_SIZE: usize = 4 * 1024 * 1024;7879static mut INITIAL_HEAP: [u8; INITIAL_HEAP_SIZE] = [0; INITIAL_HEAP_SIZE];80static mut INITIAL_HEAP_ALLOCATED: bool = false;8182unsafe impl dlmalloc::Allocator for MyAllocator {83fn alloc(&self, _size: usize) -> (*mut u8, usize, u32) {84unsafe {85if INITIAL_HEAP_ALLOCATED {86(ptr::null_mut(), 0, 0)87} else {88INITIAL_HEAP_ALLOCATED = true;89((&raw mut INITIAL_HEAP).cast(), INITIAL_HEAP_SIZE, 0)90}91}92}9394fn remap(&self, _ptr: *mut u8, _old: usize, _new: usize, _can_move: bool) -> *mut u8 {95core::ptr::null_mut()96}9798fn free_part(&self, _ptr: *mut u8, _old: usize, _new: usize) -> bool {99false100}101102fn free(&self, _ptr: *mut u8, _size: usize) -> bool {103false104}105106fn can_release_part(&self, _flags: u32) -> bool {107false108}109110fn allocates_zeros(&self) -> bool {111true112}113114fn page_size(&self) -> usize {1154096116}117}118119// Simple mutex which only supports `try_lock` at this time. This would probably120// be replaced with a "real" mutex in a "real" embedding.121struct Mutex<T> {122data: UnsafeCell<T>,123locked: AtomicBool,124}125126unsafe impl<T: Send> Send for Mutex<T> {}127unsafe impl<T: Send> Sync for Mutex<T> {}128129impl<T> Mutex<T> {130const fn new(val: T) -> Mutex<T> {131Mutex {132data: UnsafeCell::new(val),133locked: AtomicBool::new(false),134}135}136137fn try_lock(&self) -> Option<impl DerefMut<Target = T> + '_> {138if self.locked.swap(true, Acquire) {139None140} else {141Some(MutexGuard { lock: self })142}143}144}145146struct MutexGuard<'a, T> {147lock: &'a Mutex<T>,148}149150impl<T> Deref for MutexGuard<'_, T> {151type Target = T;152153fn deref(&self) -> &T {154unsafe { &*self.lock.data.get() }155}156}157158impl<T> DerefMut for MutexGuard<'_, T> {159fn deref_mut(&mut self) -> &mut T {160unsafe { &mut *self.lock.data.get() }161}162}163164impl<T> Drop for MutexGuard<'_, T> {165fn drop(&mut self) {166self.lock.locked.store(false, Release);167}168}169170171