Skip to content

Commit 07e11e8

Browse files
ijacksonAmanieu
andcommitted
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 rust-lang#81847 Signed-off-by: Ian Jackson <[email protected]> Co-authored-by: Amanieu d'Antras <[email protected]>
1 parent 8df945c commit 07e11e8

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+
/// #[repr(C, align(131072))] // 131072 == ARENA_SIZE.
34+
/// struct SimpleAllocator {
35+
/// arena: UnsafeCell<[u8; ARENA_SIZE]>,
36+
/// remaining: AtomicUsize, // we allocate from the top, counting down
3237
/// }
3338
///
3439
/// #[global_allocator]
35-
/// static A: MyAllocator = MyAllocator;
40+
/// static ALLOCATOR: SimpleAllocator = SimpleAllocator {
41+
/// arena: UnsafeCell::new([0x55; ARENA_SIZE]),
42+
/// remaining: AtomicUsize::new(ARENA_SIZE),
43+
/// };
3644
///
37-
/// fn main() {
38-
/// unsafe {
39-
/// assert!(alloc(Layout::new::<u32>()).is_null())
45+
/// unsafe impl Sync for SimpleAllocator {}
46+
///
47+
/// unsafe impl GlobalAlloc for SimpleAllocator {
48+
/// unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
49+
/// let size = layout.size();
50+
/// let align = layout.align();
51+
///
52+
/// // `Layout` contract forbids making a `Layout` with align=0, or align not power of 2.
53+
/// // So we can safely use a mask to ensure alignment without worrying about UB.
54+
/// let align_mask_to_round_down = !(align - 1);
55+
///
56+
/// if align > ARENA_SIZE {
57+
/// // align may be > size !
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)