about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--library/core/src/alloc/global.rs67
1 files 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 @@ use crate::ptr;
 ///
 /// # 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),
+/// };
 ///
-/// fn main() {
-///     unsafe {
-///         assert!(alloc(Layout::new::<u32>()).is_null())
+/// 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() {
+///     let _s = format!("allocating a string!");
+///     let currently = ALLOCATOR.remaining.load(Acquire);
+///     println!("allocated so far: {}", ARENA_SIZE - currently);
 /// }
 /// ```
 ///