0.3.0: converge relibc to upstream 0.6.0 + Red Bear patches
This commit is contained in:
@@ -1,65 +0,0 @@
|
||||
use crate::ALLOCATOR;
|
||||
use core::{
|
||||
alloc::{GlobalAlloc, Layout},
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use super::types::*;
|
||||
|
||||
extern "C" {
|
||||
fn create_mspace(capacity: size_t, locked: c_int) -> usize;
|
||||
fn mspace_malloc(msp: usize, bytes: size_t) -> *mut c_void;
|
||||
fn mspace_memalign(msp: usize, alignment: size_t, bytes: size_t) -> *mut c_void;
|
||||
fn mspace_realloc(msp: usize, oldmem: *mut c_void, bytes: size_t) -> *mut c_void;
|
||||
fn mspace_free(msp: usize, mem: *mut c_void);
|
||||
//fn dlmalloc(bytes: size_t) -> *mut c_void;
|
||||
//fn dlmemalign(alignment: size_t, bytes: size_t) -> *mut c_void;
|
||||
//fn dlrealloc(oldmem: *mut c_void, bytes: size_t) -> *mut c_void;
|
||||
//fn dlfree(mem: *mut c_void);
|
||||
}
|
||||
|
||||
pub struct Allocator {
|
||||
mstate: AtomicUsize,
|
||||
}
|
||||
|
||||
pub const NEWALLOCATOR: Allocator = Allocator {
|
||||
mstate: AtomicUsize::new(0),
|
||||
};
|
||||
|
||||
impl Allocator {
|
||||
pub fn set_book_keeper(&self, mstate: usize) {
|
||||
self.mstate.store(mstate, Ordering::Relaxed);
|
||||
}
|
||||
pub fn get_book_keeper(&self) -> usize {
|
||||
self.mstate.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
unsafe impl<'a> GlobalAlloc for Allocator {
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
alloc_align(layout.size(), layout.align()) as *mut u8
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
free(ptr as *mut c_void)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn alloc(size: usize) -> *mut c_void {
|
||||
mspace_malloc(ALLOCATOR.get_book_keeper(), size)
|
||||
}
|
||||
|
||||
pub unsafe fn alloc_align(size: usize, alignment: usize) -> *mut c_void {
|
||||
mspace_memalign(ALLOCATOR.get_book_keeper(), alignment, size)
|
||||
}
|
||||
|
||||
pub unsafe fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
|
||||
mspace_realloc(ALLOCATOR.get_book_keeper(), ptr, size)
|
||||
}
|
||||
|
||||
pub unsafe fn free(ptr: *mut c_void) {
|
||||
mspace_free(ALLOCATOR.get_book_keeper(), ptr)
|
||||
}
|
||||
|
||||
pub fn new_mspace() -> usize {
|
||||
unsafe { create_mspace(0, 0) }
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
use core::{
|
||||
alloc::{GlobalAlloc, Layout},
|
||||
cell::SyncUnsafeCell,
|
||||
cmp,
|
||||
mem::align_of,
|
||||
ptr::{self, copy_nonoverlapping, write_bytes},
|
||||
sync::atomic::{AtomicPtr, Ordering},
|
||||
};
|
||||
|
||||
mod sys;
|
||||
use super::types::*;
|
||||
use crate::{ALLOCATOR, sync::Mutex};
|
||||
use dlmalloc::DlmallocCApi;
|
||||
|
||||
pub type Dlmalloc = DlmallocCApi<sys::System>;
|
||||
|
||||
#[allow(clippy::declare_interior_mutable_const)]
|
||||
pub const NEWALLOCATOR: Allocator = Allocator::new();
|
||||
|
||||
pub struct Allocator {
|
||||
inner: SyncUnsafeCell<Mutex<Dlmalloc>>,
|
||||
pub ptr: AtomicPtr<Mutex<Dlmalloc>>,
|
||||
}
|
||||
|
||||
impl Allocator {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub const fn new() -> Self {
|
||||
Allocator {
|
||||
inner: SyncUnsafeCell::new(Mutex::new(Dlmalloc::new(sys::System::new()))),
|
||||
ptr: AtomicPtr::new(ptr::null_mut()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self) -> *const Mutex<Dlmalloc> {
|
||||
let ptr = self.ptr.load(Ordering::Acquire);
|
||||
if !ptr.is_null() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
self.inner.get()
|
||||
}
|
||||
|
||||
pub fn set(&self, mspace: *const Mutex<Dlmalloc>) {
|
||||
self.ptr.store(mspace.cast_mut(), Ordering::Release);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl GlobalAlloc for Allocator {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() <= align_of::<max_align_t>() {
|
||||
unsafe { (*self.get()).lock().malloc(layout.size()) }
|
||||
} else {
|
||||
unsafe { (*self.get()).lock().memalign(layout.align(), layout.size()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
unsafe { (*self.get()).lock().free(ptr) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
let ptr = unsafe { self.alloc(layout) };
|
||||
if !ptr.is_null() && unsafe { (*self.get()).lock().calloc_must_clear(ptr) } {
|
||||
unsafe { write_bytes(ptr, 0, layout.size()) };
|
||||
}
|
||||
ptr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
if layout.align() <= align_of::<max_align_t>() {
|
||||
unsafe { (*self.get()).lock().realloc(ptr, new_size) }
|
||||
} else {
|
||||
let new =
|
||||
unsafe { self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())) };
|
||||
let old_size = layout.size();
|
||||
|
||||
if !new.is_null() {
|
||||
let size = cmp::min(old_size, new_size);
|
||||
unsafe { copy_nonoverlapping(ptr, new, size) };
|
||||
}
|
||||
|
||||
unsafe { (*self.get()).lock().free(ptr) };
|
||||
|
||||
new
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn alloc(size: size_t) -> *mut c_void {
|
||||
unsafe { (*ALLOCATOR.get()).lock().malloc(size) }.cast()
|
||||
}
|
||||
|
||||
pub unsafe fn alloc_align(size: size_t, alignment: size_t) -> *mut c_void {
|
||||
unsafe { (*ALLOCATOR.get()).lock().memalign(alignment, size) }.cast()
|
||||
}
|
||||
|
||||
pub unsafe fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
|
||||
if ptr.is_null() {
|
||||
unsafe { (*ALLOCATOR.get()).lock().malloc(size) }.cast()
|
||||
} else {
|
||||
unsafe { (*ALLOCATOR.get()).lock().realloc(ptr.cast(), size) }.cast()
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn free(ptr: *mut c_void) {
|
||||
if ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
unsafe { (*ALLOCATOR.get()).lock().free(ptr.cast()) }
|
||||
}
|
||||
|
||||
pub unsafe fn alloc_usable_size(ptr: *mut c_void) -> size_t {
|
||||
if ptr.is_null() {
|
||||
return 0;
|
||||
}
|
||||
unsafe { (*ALLOCATOR.get()).lock().usable_size(ptr.cast()) }
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
extern crate ralloc;
|
||||
|
||||
pub use ralloc::Allocator;
|
||||
|
||||
unsafe fn alloc_inner(size: usize, offset: usize, align: usize) -> *mut c_void {
|
||||
let ptr = ralloc::alloc(size + offset, align);
|
||||
if !ptr.is_null() {
|
||||
*(ptr as *mut u64) = (size + offset) as u64;
|
||||
*(ptr as *mut u64).offset(1) = align as u64;
|
||||
ptr.offset(offset as isize) as *mut c_void
|
||||
} else {
|
||||
ptr as *mut c_void
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn alloc(size: usize) -> *mut c_void {
|
||||
alloc_inner(size, 16, 8)
|
||||
}
|
||||
|
||||
pub unsafe fn alloc_align(size: usize, alignment: usize) -> *mut c_void {
|
||||
let mut align = 32;
|
||||
while align <= alignment {
|
||||
align *= 2;
|
||||
}
|
||||
|
||||
alloc_inner(size, align / 2, align)
|
||||
}
|
||||
|
||||
pub unsafe fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
|
||||
let old_ptr = (ptr as *mut u8).offset(-16);
|
||||
let old_size = *(old_ptr as *mut u64);
|
||||
let align = *(old_ptr as *mut u64).offset(1);
|
||||
let ptr = ralloc::realloc(old_ptr, old_size as usize, size + 16, align as usize);
|
||||
if !ptr.is_null() {
|
||||
*(ptr as *mut u64) = (size + 16) as u64;
|
||||
*(ptr as *mut u64).offset(1) = align;
|
||||
ptr.offset(16) as *mut c_void
|
||||
} else {
|
||||
ptr as *mut c_void
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn free(ptr: *mut c_void) {
|
||||
let ptr = (ptr as *mut u8).offset(-16);
|
||||
let size = *(ptr as *mut u64);
|
||||
let _align = *(ptr as *mut u64).offset(1);
|
||||
ralloc::free(ptr, size as usize);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
use crate::{
|
||||
header::{
|
||||
pthread::pthread_atfork,
|
||||
sys_mman::{self, MREMAP_MAYMOVE},
|
||||
},
|
||||
platform::{Pal, Sys},
|
||||
sync::Mutex,
|
||||
};
|
||||
use core::ptr;
|
||||
|
||||
use dlmalloc::Allocator;
|
||||
|
||||
/// System setting for Redox/Linux
|
||||
pub struct System {
|
||||
_priv: (),
|
||||
}
|
||||
|
||||
impl System {
|
||||
pub const fn new() -> System {
|
||||
System { _priv: () }
|
||||
}
|
||||
}
|
||||
|
||||
static LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
unsafe impl Allocator for System {
|
||||
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
|
||||
let Ok(addr) = (unsafe {
|
||||
Sys::mmap(
|
||||
ptr::null_mut(),
|
||||
size,
|
||||
sys_mman::PROT_WRITE | sys_mman::PROT_READ,
|
||||
sys_mman::MAP_ANON | sys_mman::MAP_PRIVATE,
|
||||
-1,
|
||||
0,
|
||||
)
|
||||
}) else {
|
||||
return (ptr::null_mut(), 0, 0);
|
||||
};
|
||||
(addr.cast::<u8>(), size, 0)
|
||||
}
|
||||
|
||||
fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 {
|
||||
let flags = if can_move { MREMAP_MAYMOVE } else { 0 };
|
||||
let Ok(ptr) =
|
||||
(unsafe { Sys::mremap(ptr.cast(), oldsize, newsize, flags, ptr::null_mut()) })
|
||||
else {
|
||||
return ptr::null_mut();
|
||||
};
|
||||
ptr.cast::<u8>()
|
||||
}
|
||||
|
||||
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool {
|
||||
unsafe {
|
||||
if Sys::mremap(ptr.cast(), oldsize, newsize, 0, ptr::null_mut()).is_ok() {
|
||||
return true;
|
||||
}
|
||||
Sys::munmap(ptr.add(newsize).cast(), oldsize - newsize).is_ok()
|
||||
}
|
||||
}
|
||||
|
||||
fn free(&self, ptr: *mut u8, size: usize) -> bool {
|
||||
unsafe { Sys::munmap(ptr.cast(), size).is_ok() }
|
||||
}
|
||||
|
||||
fn can_release_part(&self, _flags: u32) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn allocates_zeros(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn page_size(&self) -> usize {
|
||||
4096
|
||||
}
|
||||
}
|
||||
|
||||
pub fn acquire_global_lock() {
|
||||
unsafe {
|
||||
// SAFETY: No data inside
|
||||
LOCK.manual_lock();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn release_global_lock() {
|
||||
unsafe {
|
||||
// SAFETY: No data inside
|
||||
LOCK.manual_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/// Allows the allocator to remain unsable in the child process,
|
||||
/// after a call to `fork(2)`
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// if used, this function must be called,
|
||||
/// before any allocations are made with the global allocator.
|
||||
pub unsafe fn enable_alloc_after_fork() {
|
||||
// atfork must only be called once, to avoid a deadlock,
|
||||
// where the handler attempts to acquire the global lock twice
|
||||
static mut FORK_PROTECTED: bool = false;
|
||||
|
||||
extern "C" fn _acquire_global_lock() {
|
||||
acquire_global_lock()
|
||||
}
|
||||
|
||||
extern "C" fn _release_global_lock() {
|
||||
release_global_lock()
|
||||
}
|
||||
|
||||
acquire_global_lock();
|
||||
// if a process forks,
|
||||
// it will acquire the lock before any other thread,
|
||||
// protecting it from deadlock,
|
||||
// due to the child being created with only the calling thread.
|
||||
unsafe {
|
||||
if !FORK_PROTECTED {
|
||||
pthread_atfork(
|
||||
Some(_acquire_global_lock),
|
||||
Some(_release_global_lock),
|
||||
Some(_release_global_lock),
|
||||
);
|
||||
FORK_PROTECTED = true;
|
||||
}
|
||||
}
|
||||
release_global_lock();
|
||||
}
|
||||
Reference in New Issue
Block a user