0.3.0: converge relibc to upstream 0.6.0 + Red Bear patches

This commit is contained in:
2026-07-06 19:13:08 +03:00
parent 1a0edd8eeb
commit 4ef7e57571
1466 changed files with 75236 additions and 13644 deletions
-65
View File
@@ -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) }
}
+121
View File
@@ -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()) }
}
-48
View File
@@ -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);
}
+129
View File
@@ -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();
}