♻️ Remove Mutex from mem buffer (#9479)

This commit is contained in:
Aitor Moreno 2026-05-14 12:57:10 +02:00 committed by GitHub
parent f62ee7d1ae
commit 64f73ef23b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 59 additions and 40 deletions

View File

@ -1,61 +1,73 @@
use std::sync::Mutex;
use crate::error::{Error, Result, CRITICAL_ERROR};
use crate::{error::Result, performance};
pub const LAYOUT_ALIGN: usize = 4;
pub static BUFFERU8: Mutex<Option<Vec<u8>>> = Mutex::new(None);
pub static BUFFER_ERROR: Mutex<u8> = Mutex::new(0x00);
// Please, read about the #[allow(static_mut_refs)]
//
// If we don't put this allow, the compiler shows a warning like this:
//
// shared references to mutable statics are dangerous; it's undefined behavior
// if the static is mutated or if a mutable reference is created for it while
// the shared reference lives
//
// https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html
//
// But this isn't a problem in a single-threaded environment like WebAssembly
// because access/modification is always sequential, not parallel.
pub static mut BUFFERU8: Option<Vec<u8>> = None;
pub static mut BUFFER_ERROR: u8 = 0x00;
pub fn clear_error_code() {
let mut guard = BUFFER_ERROR.lock().unwrap();
*guard = 0x00;
unsafe {
BUFFER_ERROR = 0x00;
}
}
/// Sets the error buffer from a byte. Used by #[wasm_error] when E: Into<u8>.
pub fn set_error_code(code: u8) {
let mut guard = BUFFER_ERROR.lock().unwrap();
*guard = code;
unsafe {
BUFFER_ERROR = code;
}
}
#[no_mangle]
pub extern "C" fn read_error_code() -> u8 {
if let Ok(guard) = BUFFER_ERROR.lock() {
*guard
} else {
CRITICAL_ERROR
}
unsafe { BUFFER_ERROR }
}
pub fn write_bytes(mut bytes: Vec<u8>) -> *mut u8 {
let mut guard = BUFFERU8.lock().unwrap();
unsafe {
performance::begin_measure!("write_bytes");
#[allow(static_mut_refs)]
if BUFFERU8.is_some() {
panic!("Bytes already allocated");
}
if guard.is_some() {
panic!("Bytes already allocated");
let ptr = bytes.as_mut_ptr();
BUFFERU8 = Some(bytes);
performance::end_measure!("write_bytes");
ptr
}
let ptr = bytes.as_mut_ptr();
*guard = Some(bytes);
ptr
}
pub fn bytes() -> Vec<u8> {
let mut guard = BUFFERU8.lock().unwrap();
guard.take().expect("Buffer is not initialized")
unsafe {
#[allow(static_mut_refs)]
BUFFERU8.take().expect("Buffer is not initialized")
}
}
pub fn bytes_or_empty() -> Vec<u8> {
let mut guard = BUFFERU8.lock().unwrap();
guard.take().unwrap_or_default()
unsafe {
#[allow(static_mut_refs)]
BUFFERU8.take().unwrap_or_default()
}
}
pub fn free_bytes() -> Result<()> {
let mut guard = BUFFERU8
.lock()
.map_err(|_| Error::CriticalError("Failed to lock buffer".to_string()))?;
*guard = None;
std::mem::drop(guard);
unsafe {
BUFFERU8 = None;
}
Ok(())
}

View File

@ -9,15 +9,22 @@ use macros::wasm_error;
#[no_mangle]
#[wasm_error]
pub extern "C" fn alloc_bytes(len: usize) -> Result<*mut u8> {
let mut guard = BUFFERU8
.lock()
.map_err(|_| Error::CriticalError("Failed to lock buffer".to_string()))?;
if guard.is_some() {
return Err(Error::CriticalError("Bytes already allocated".to_string()));
}
unsafe {
// If we don't put this allow, the compiler shows a warning like this:
//
// shared references to mutable statics are dangerous; it's undefined behavior
// if the static is mutated or if a mutable reference is created for it while
// the shared reference lives
//
// https://doc.rust-lang.org/edition-guide/rust-2024/static-mut-references.html
//
// But this isn't a problem in a single-threaded environment like WebAssembly
// because access/modification is always sequential, not parallel.
#[allow(static_mut_refs)]
if BUFFERU8.is_some() {
return Err(Error::CriticalError("Bytes already allocated".to_string()));
}
let layout = Layout::from_size_align_unchecked(len, LAYOUT_ALIGN);
let ptr = alloc(layout);
if ptr.is_null() {
@ -25,7 +32,7 @@ pub extern "C" fn alloc_bytes(len: usize) -> Result<*mut u8> {
}
// TODO: Maybe this could be removed.
ptr::write_bytes(ptr, 0, len);
*guard = Some(Vec::from_raw_parts(ptr, len, len));
BUFFERU8 = Some(Vec::from_raw_parts(ptr, len, len));
Ok(ptr)
}
}