Skip to content

Commit a3e1259

Browse files
authored
Rollup merge of #81864 - ijackson:globalalloc-example, r=Amanieu
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
2 parents 05f2326 + 03d7001 commit a3e1259

File tree

1 file changed

+56
-11
lines changed

1 file changed

+56
-11
lines changed

library/core/src/alloc/global.rs

+56-11
Original file line numberDiff line numberDiff line change
@@ -20,24 +20,69 @@ use crate::ptr;
2020
///
2121
/// # Example
2222
///
23-
/// ```no_run
24-
/// use std::alloc::{GlobalAlloc, Layout, alloc};
23+
/// ```
24+
/// use std::alloc::{GlobalAlloc, Layout};
25+
/// use std::cell::UnsafeCell;
2526
/// use std::ptr::null_mut;
27+
/// use std::sync::atomic::{
28+
/// AtomicUsize,
29+
/// Ordering::{Acquire, SeqCst},
30+
/// };
2631
///
27-
/// struct MyAllocator;
28-
///
29-
/// unsafe impl GlobalAlloc for MyAllocator {
30-
/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
31-
/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
32+
/// const ARENA_SIZE: usize = 128 * 1024;
33+
/// const MAX_SUPPORTED_ALIGN: usize = 4096;
34+
/// #[repr(C, align(4096))] // 4096 == MAX_SUPPORTED_ALIGN
35+
/// struct SimpleAllocator {
36+
/// arena: UnsafeCell<[u8; ARENA_SIZE]>,
37+
/// remaining: AtomicUsize, // we allocate from the top, counting down
3238
/// }
3339
///
3440
/// #[global_allocator]
35-
/// static A: MyAllocator = MyAllocator;
41+
/// static ALLOCATOR: SimpleAllocator = SimpleAllocator {
42+
/// arena: UnsafeCell::new([0x55; ARENA_SIZE]),
43+
/// remaining: AtomicUsize::new(ARENA_SIZE),
44+
/// };
3645
///
37-
/// fn main() {
38-
/// unsafe {
39-
/// assert!(alloc(Layout::new::<u32>()).is_null())
46+
/// unsafe impl Sync for SimpleAllocator {}
47+
///
48+
/// unsafe impl GlobalAlloc for SimpleAllocator {
49+
/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
50+
/// let size = layout.size();
51+
/// let align = layout.align();
52+
///
53+
/// // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2.
54+
/// // So we can safely use a mask to ensure alignment without worrying about UB.
55+
/// let align_mask_to_round_down = !(align - 1);
56+
///
57+
/// if align > MAX_SUPPORTED_ALIGN {
58+
/// return null_mut();
59+
/// }
60+
///
61+
/// let mut allocated = 0;
62+
/// if self
63+
/// .remaining
64+
/// .fetch_update(SeqCst, SeqCst, |mut remaining| {
65+
/// if size > remaining {
66+
/// return None;
67+
/// }
68+
/// remaining -= size;
69+
/// remaining &= align_mask_to_round_down;
70+
/// allocated = remaining;
71+
/// Some(remaining)
72+
/// })
73+
/// .is_err()
74+
/// {
75+
/// return null_mut();
76+
/// };
77+
/// (self.arena.get() as *mut u8).add(allocated)
4078
/// }
79+
/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
80+
/// }
81+
///
82+
/// fn main() {
83+
/// let _s = format!("allocating a string!");
84+
/// let currently = ALLOCATOR.remaining.load(Acquire);
85+
/// println!("allocated so far: {}", ARENA_SIZE - currently);
4186
/// }
4287
/// ```
4388
///

0 commit comments

Comments
 (0)