From 07e11e849586c30540dfd784f56438dc7af11900 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 7 Feb 2021 21:50:56 +0000 Subject: [PATCH] docs: GlobalAlloc: completely replace example with one that works Since this is an example, this could really do with some review from someone familiar with unsafe stuff ! I made the example no longer `no_run` since it works for me. Fixes #81847 Signed-off-by: Ian Jackson Co-authored-by: Amanieu d'Antras --- library/core/src/alloc/global.rs | 67 ++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 6dcc110f153..a8e76c2982d 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -20,24 +20,69 @@ /// /// # Example /// -/// ```no_run -/// use std::alloc::{GlobalAlloc, Layout, alloc}; +/// ``` +/// use std::alloc::{GlobalAlloc, Layout}; +/// use std::cell::UnsafeCell; /// use std::ptr::null_mut; +/// use std::sync::atomic::{ +/// AtomicUsize, +/// Ordering::{Acquire, SeqCst}, +/// }; /// -/// struct MyAllocator; -/// -/// unsafe impl GlobalAlloc for MyAllocator { -/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() } -/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// const ARENA_SIZE: usize = 128 * 1024; +/// #[repr(C, align(131072))] // 131072 == ARENA_SIZE. +/// struct SimpleAllocator { +/// arena: UnsafeCell<[u8; ARENA_SIZE]>, +/// remaining: AtomicUsize, // we allocate from the top, counting down /// } /// /// #[global_allocator] -/// static A: MyAllocator = MyAllocator; +/// static ALLOCATOR: SimpleAllocator = SimpleAllocator { +/// arena: UnsafeCell::new([0x55; ARENA_SIZE]), +/// remaining: AtomicUsize::new(ARENA_SIZE), +/// }; +/// +/// unsafe impl Sync for SimpleAllocator {} +/// +/// unsafe impl GlobalAlloc for SimpleAllocator { +/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 { +/// let size = layout.size(); +/// let align = layout.align(); +/// +/// // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2. +/// // So we can safely use a mask to ensure alignment without worrying about UB. +/// let align_mask_to_round_down = !(align - 1); +/// +/// if align > ARENA_SIZE { +/// // align may be > size ! +/// return null_mut(); +/// } +/// +/// let mut allocated = 0; +/// if self +/// .remaining +/// .fetch_update(SeqCst, SeqCst, |mut remaining| { +/// if size > remaining { +/// return None; +/// } +/// remaining -= size; +/// remaining &= align_mask_to_round_down; +/// allocated = remaining; +/// Some(remaining) +/// }) +/// .is_err() +/// { +/// return null_mut(); +/// }; +/// (self.arena.get() as *mut u8).add(allocated) +/// } +/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// } /// /// fn main() { -/// unsafe { -/// assert!(alloc(Layout::new::()).is_null()) -/// } +/// let _s = format!("allocating a string!"); +/// let currently = ALLOCATOR.remaining.load(Acquire); +/// println!("allocated so far: {}", ARENA_SIZE - currently); /// } /// ``` ///