mirror of
https://github.com/microsoft/edit.git
synced 2026-06-17 00:19:58 -05:00
The main change is adding multithreading support in order to make JSON unit tests work properly. The TLS overhead is not _that bad. Other changes: * Switch to `io::Result`, because `AllocError` doesn't transmit error codes (meh!) * Reduce x86 commit chunk size to 32KiB * Improved performance slightly by inlining harder (`alloc_uninit`) and outlining the result unwrap (`alloc_raw_bump`)
74 lines
2.3 KiB
Rust
74 lines
2.3 KiB
Rust
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
use std::ffi::c_int;
|
|
use std::io;
|
|
use std::ptr::{self, NonNull, null_mut};
|
|
|
|
/// Reserves a virtual memory region of the given size.
|
|
/// To commit the memory, use `virtual_commit`.
|
|
/// To release the memory, use `virtual_release`.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This function is unsafe because it uses raw pointers.
|
|
/// Don't forget to release the memory when you're done with it or you'll leak it.
|
|
pub unsafe fn virtual_reserve(size: usize) -> io::Result<NonNull<u8>> {
|
|
unsafe {
|
|
let ptr = libc::mmap(
|
|
null_mut(),
|
|
size,
|
|
desired_mprotect(libc::PROT_READ | libc::PROT_WRITE),
|
|
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
|
|
-1,
|
|
0,
|
|
);
|
|
if ptr.is_null() || ptr::eq(ptr, libc::MAP_FAILED) {
|
|
Err(io::Error::last_os_error())
|
|
} else {
|
|
Ok(NonNull::new_unchecked(ptr as *mut u8))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(target_os = "netbsd")]
|
|
const fn desired_mprotect(flags: c_int) -> c_int {
|
|
// NetBSD allows an mmap(2) caller to specify what protection flags they
|
|
// will use later via mprotect. It does not allow a caller to move from
|
|
// PROT_NONE to PROT_READ | PROT_WRITE.
|
|
//
|
|
// see PROT_MPROTECT in man 2 mmap
|
|
flags << 3
|
|
}
|
|
|
|
#[cfg(not(target_os = "netbsd"))]
|
|
const fn desired_mprotect(_: c_int) -> c_int {
|
|
libc::PROT_NONE
|
|
}
|
|
|
|
/// Releases a virtual memory region of the given size.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This function is unsafe because it uses raw pointers.
|
|
/// Make sure to only pass pointers acquired from `virtual_reserve`.
|
|
pub unsafe fn virtual_release(base: NonNull<u8>, size: usize) {
|
|
unsafe {
|
|
libc::munmap(base.cast().as_ptr(), size);
|
|
}
|
|
}
|
|
|
|
/// Commits a virtual memory region of the given size.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This function is unsafe because it uses raw pointers.
|
|
/// Make sure to only pass pointers acquired from `virtual_reserve`
|
|
/// and to pass a size less than or equal to the size passed to `virtual_reserve`.
|
|
pub unsafe fn virtual_commit(base: NonNull<u8>, size: usize) -> io::Result<()> {
|
|
unsafe {
|
|
let status = libc::mprotect(base.cast().as_ptr(), size, libc::PROT_READ | libc::PROT_WRITE);
|
|
if status != 0 { Err(io::Error::last_os_error()) } else { Ok(()) }
|
|
}
|
|
}
|