Skip to content

Commit 2514be0

Browse files
committed
Add a simple heap
1 parent 8437c09 commit 2514be0

File tree

4 files changed

+124
-2
lines changed

4 files changed

+124
-2
lines changed

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ name = "embedded-alloc"
2424
version = "0.6.0"
2525

2626
[features]
27-
default = ["llff", "tlsf"]
27+
default = ["llff", "tlsf", "simplest"]
2828
allocator_api = []
2929

3030
# Use the Two-Level Segregated Fit allocator
3131
tlsf = ["rlsf", "const-default"]
32-
# Use the LinkedList first-fit allocator
32+
# Use the LinkedList first-fit allocator
3333
llff = ["linked_list_allocator"]
34+
# Use the simplest allocator
35+
simplest = []
3436

3537
[dependencies]
3638
critical-section = "1.0"

examples/global_alloc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use cortex_m_rt::entry;
1010
use embedded_alloc::LlffHeap as Heap;
1111
// Two-Level Segregated Fit Heap allocator (feature = "tlsf")
1212
// use embedded_alloc::TlsfHeap as Heap;
13+
// use embedded_alloc::SimplestHeap as Heap;
1314

1415
#[global_allocator]
1516
static HEAP: Heap = Heap::empty();

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
#![cfg_attr(feature = "allocator_api", feature(allocator_api, alloc_layout_extra))]
44
#![warn(missing_docs)]
55

6+
#[cfg(feature = "simplest")]
7+
mod simplest;
68
#[cfg(feature = "llff")]
79
mod llff;
810
#[cfg(feature = "tlsf")]
911
mod tlsf;
1012

13+
#[cfg(feature = "simplest")]
14+
pub use simplest::Heap as SimplestHeap;
1115
#[cfg(feature = "llff")]
1216
pub use llff::Heap as LlffHeap;
1317
#[cfg(feature = "tlsf")]

src/simplest.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
use core::alloc::{GlobalAlloc, Layout};
2+
use core::cell::RefCell;
3+
use core::ptr;
4+
use critical_section::Mutex;
5+
6+
/// The simplest possible heap.
7+
///
8+
/// # Safety
9+
///
10+
/// This heap does **NOT** free allocated memory.
11+
pub struct Heap {
12+
heap: Mutex<RefCell<SimplestHeap>>,
13+
}
14+
15+
impl Heap {
16+
/// Create a new UNINITIALIZED heap allocator
17+
///
18+
/// You must initialize this heap using the
19+
/// [`init`](Self::init) method before using the allocator.
20+
pub const fn empty() -> Heap {
21+
Heap {
22+
heap: Mutex::new(RefCell::new(SimplestHeap::empty())),
23+
}
24+
}
25+
26+
/// Initializes the heap
27+
///
28+
/// This function must be called BEFORE you run any code that makes use of the
29+
/// allocator.
30+
///
31+
/// `start_addr` is the address where the heap will be located.
32+
///
33+
/// `size` is the size of the heap in bytes.
34+
///
35+
/// # Safety
36+
///
37+
/// Obey these or Bad Stuff will happen.
38+
///
39+
/// - This function must be called exactly ONCE.
40+
/// - `size > 0`
41+
pub unsafe fn init(&self, start_addr: usize, size: usize) {
42+
critical_section::with(|cs| {
43+
self.heap
44+
.borrow(cs)
45+
.borrow_mut()
46+
.init(start_addr as *mut u8, size);
47+
});
48+
}
49+
50+
/// Returns an estimate of the amount of bytes in use.
51+
pub fn used(&self) -> usize {
52+
critical_section::with(|cs| self.heap.borrow(cs).borrow().used())
53+
}
54+
55+
/// Returns an estimate of the amount of bytes available.
56+
pub fn free(&self) -> usize {
57+
critical_section::with(|cs| self.heap.borrow(cs).borrow().free())
58+
}
59+
}
60+
61+
unsafe impl GlobalAlloc for Heap {
62+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
63+
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().alloc(layout))
64+
}
65+
66+
unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
67+
}
68+
69+
struct SimplestHeap {
70+
arena: *mut u8,
71+
remaining: usize,
72+
size: usize,
73+
}
74+
75+
unsafe impl Send for SimplestHeap {}
76+
77+
impl SimplestHeap {
78+
const fn empty() -> Self {
79+
Self {
80+
arena: ptr::null_mut(),
81+
remaining: 0,
82+
size: 0,
83+
}
84+
}
85+
86+
fn init(&mut self, start_addr: *mut u8, size: usize) -> Self {
87+
Self {
88+
arena: start_addr,
89+
remaining: size,
90+
size,
91+
}
92+
}
93+
94+
fn free(&self) -> usize {
95+
self.remaining
96+
}
97+
98+
fn used(&self) -> usize {
99+
self.size - self.remaining
100+
}
101+
102+
fn alloc(&mut self, layout: Layout) -> *mut u8 {
103+
if layout.size() > self.remaining {
104+
return ptr::null_mut();
105+
}
106+
107+
// `Layout` contract forbids making a `Layout` with align=0, or align not power of 2.
108+
// So we can safely use a mask to ensure alignment without worrying about UB.
109+
let align_mask_to_round_down = !(layout.align() - 1);
110+
111+
self.remaining -= layout.size();
112+
self.remaining &= align_mask_to_round_down;
113+
self.arena.wrapping_add(self.remaining)
114+
}
115+
}

0 commit comments

Comments
 (0)