Skip to content

Commit 83157f6

Browse files
authored
Merge pull request #103 from JalonWong/master
Add a macro to make initialization easier
2 parents 8437c09 + 61a2685 commit 83157f6

File tree

9 files changed

+116
-40
lines changed

9 files changed

+116
-40
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## [Unreleased]
9+
10+
### Added
11+
12+
- Added a `init` macro to make initialization easier.
13+
14+
### Changed
15+
16+
- The `Heap::init` methods now panic if they're called more than once or with `size == 0`.
17+
818
## [v0.6.0] - 2024-09-01
919

1020
### Added

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ 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"]
3434

3535
[dependencies]

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ static HEAP: Heap = Heap::empty();
3131
#[entry]
3232
fn main() -> ! {
3333
// Initialize the allocator BEFORE you use it
34+
unsafe {
35+
embedded_alloc::init!(HEAP, 1024);
36+
}
37+
// Alternatively, you can write the code directly to meet specific requirements.
3438
{
3539
use core::mem::MaybeUninit;
3640
const HEAP_SIZE: usize = 1024;

examples/global_alloc.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,8 @@ static HEAP: Heap = Heap::empty();
1717
#[entry]
1818
fn main() -> ! {
1919
// Initialize the allocator BEFORE you use it
20-
{
21-
use core::mem::MaybeUninit;
22-
const HEAP_SIZE: usize = 1024;
23-
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
24-
unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) }
20+
unsafe {
21+
embedded_alloc::init!(HEAP, 1024);
2522
}
2623

2724
let mut xs = Vec::new();

examples/llff_integration_test.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,8 @@ fn test_allocator_api() {
6363

6464
#[entry]
6565
fn main() -> ! {
66-
{
67-
const HEAP_SIZE: usize = 1024;
68-
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
69-
unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) }
66+
unsafe {
67+
embedded_alloc::init!(HEAP, 1024);
7068
}
7169

7270
#[allow(clippy::type_complexity)]

examples/tlsf_integration_test.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,8 @@ fn test_allocator_api() {
8181

8282
#[entry]
8383
fn main() -> ! {
84-
{
85-
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
86-
unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) }
84+
unsafe {
85+
embedded_alloc::init!(HEAP, HEAP_SIZE);
8786
}
8887

8988
#[allow(clippy::type_complexity)]

src/lib.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,55 @@ mod tlsf;
1212
pub use llff::Heap as LlffHeap;
1313
#[cfg(feature = "tlsf")]
1414
pub use tlsf::Heap as TlsfHeap;
15+
16+
/// Initialize the global heap.
17+
///
18+
/// This macro creates a static, uninitialized memory buffer of the specified size and
19+
/// initializes the heap instance with that buffer.
20+
///
21+
/// # Parameters
22+
///
23+
/// - `$heap:ident`: The identifier of the global heap instance to initialize.
24+
/// - `$size:expr`: An expression evaluating to a `usize` that specifies the size of the
25+
/// static memory buffer in bytes. It must be **greater than zero**.
26+
///
27+
/// # Safety
28+
///
29+
/// This macro must be called first, before any operations on the heap, and **only once**.
30+
/// It internally calls `Heap::init(...)` on the heap,
31+
/// so `Heap::init(...)` should not be called directly if this macro is used.
32+
///
33+
/// # Panics
34+
///
35+
/// This macro will panic if either of the following are true:
36+
///
37+
/// - this function is called more than ONCE.
38+
/// - `size == 0`.
39+
///
40+
/// # Example
41+
///
42+
/// ```rust
43+
/// use cortex_m_rt::entry;
44+
/// use embedded_alloc::LlffHeap as Heap;
45+
///
46+
/// #[global_allocator]
47+
/// static HEAP: Heap = Heap::empty();
48+
///
49+
/// #[entry]
50+
/// fn main() -> ! {
51+
/// // Initialize the allocator BEFORE you use it
52+
/// unsafe {
53+
/// embedded_alloc::init!(HEAP, 1024);
54+
/// }
55+
/// let mut xs = Vec::new();
56+
/// // ...
57+
/// }
58+
/// ```
59+
#[macro_export]
60+
macro_rules! init {
61+
($heap:ident, $size:expr) => {
62+
static mut HEAP_MEM: [::core::mem::MaybeUninit<u8>; $size] =
63+
[::core::mem::MaybeUninit::uninit(); $size];
64+
$heap.init(&raw mut HEAP_MEM as usize, $size)
65+
};
66+
}

src/llff.rs

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use linked_list_allocator::Heap as LLHeap;
77

88
/// A linked list first fit heap.
99
pub struct Heap {
10-
heap: Mutex<RefCell<LLHeap>>,
10+
heap: Mutex<RefCell<(LLHeap, bool)>>,
1111
}
1212

1313
impl Heap {
@@ -17,7 +17,7 @@ impl Heap {
1717
/// [`init`](Self::init) method before using the allocator.
1818
pub const fn empty() -> Heap {
1919
Heap {
20-
heap: Mutex::new(RefCell::new(LLHeap::empty())),
20+
heap: Mutex::new(RefCell::new((LLHeap::empty(), false))),
2121
}
2222
}
2323

@@ -41,34 +41,42 @@ impl Heap {
4141
///
4242
/// # Safety
4343
///
44-
/// Obey these or Bad Stuff will happen.
44+
/// This function is safe if the following invariants hold:
4545
///
46-
/// - This function must be called exactly ONCE.
47-
/// - `size > 0`
46+
/// - `start_addr` points to valid memory.
47+
/// - `size` is correct.
48+
///
49+
/// # Panics
50+
///
51+
/// This function will panic if either of the following are true:
52+
///
53+
/// - this function is called more than ONCE.
54+
/// - `size == 0`.
4855
pub unsafe fn init(&self, start_addr: usize, size: usize) {
56+
assert!(size > 0);
4957
critical_section::with(|cs| {
50-
self.heap
51-
.borrow(cs)
52-
.borrow_mut()
53-
.init(start_addr as *mut u8, size);
58+
let mut heap = self.heap.borrow_ref_mut(cs);
59+
assert!(!heap.1);
60+
heap.1 = true;
61+
heap.0.init(start_addr as *mut u8, size);
5462
});
5563
}
5664

5765
/// Returns an estimate of the amount of bytes in use.
5866
pub fn used(&self) -> usize {
59-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().used())
67+
critical_section::with(|cs| self.heap.borrow_ref_mut(cs).0.used())
6068
}
6169

6270
/// Returns an estimate of the amount of bytes available.
6371
pub fn free(&self) -> usize {
64-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().free())
72+
critical_section::with(|cs| self.heap.borrow_ref_mut(cs).0.free())
6573
}
6674

6775
fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
6876
critical_section::with(|cs| {
6977
self.heap
70-
.borrow(cs)
71-
.borrow_mut()
78+
.borrow_ref_mut(cs)
79+
.0
7280
.allocate_first_fit(layout)
7381
.ok()
7482
})
@@ -77,8 +85,8 @@ impl Heap {
7785
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
7886
critical_section::with(|cs| {
7987
self.heap
80-
.borrow(cs)
81-
.borrow_mut()
88+
.borrow_ref_mut(cs)
89+
.0
8290
.deallocate(NonNull::new_unchecked(ptr), layout)
8391
});
8492
}

src/tlsf.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ type TlsfHeap = Tlsf<'static, usize, usize, { usize::BITS as usize }, { usize::B
1010

1111
/// A two-Level segregated fit heap.
1212
pub struct Heap {
13-
heap: Mutex<RefCell<TlsfHeap>>,
13+
heap: Mutex<RefCell<(TlsfHeap, bool)>>,
1414
}
1515

1616
impl Heap {
@@ -20,7 +20,7 @@ impl Heap {
2020
/// [`init`](Self::init) method before using the allocator.
2121
pub const fn empty() -> Heap {
2222
Heap {
23-
heap: Mutex::new(RefCell::new(ConstDefault::DEFAULT)),
23+
heap: Mutex::new(RefCell::new((ConstDefault::DEFAULT, false))),
2424
}
2525
}
2626

@@ -44,29 +44,37 @@ impl Heap {
4444
///
4545
/// # Safety
4646
///
47-
/// Obey these or Bad Stuff will happen.
47+
/// This function is safe if the following invariants hold:
4848
///
49-
/// - This function must be called exactly ONCE.
50-
/// - `size > 0`
49+
/// - `start_addr` points to valid memory.
50+
/// - `size` is correct.
51+
///
52+
/// # Panics
53+
///
54+
/// This function will panic if either of the following are true:
55+
///
56+
/// - this function is called more than ONCE.
57+
/// - `size == 0`.
5158
pub unsafe fn init(&self, start_addr: usize, size: usize) {
59+
assert!(size > 0);
5260
critical_section::with(|cs| {
61+
let mut heap = self.heap.borrow_ref_mut(cs);
62+
assert!(!heap.1);
63+
heap.1 = true;
5364
let block: &[u8] = core::slice::from_raw_parts(start_addr as *const u8, size);
54-
self.heap
55-
.borrow(cs)
56-
.borrow_mut()
57-
.insert_free_block_ptr(block.into());
65+
heap.0.insert_free_block_ptr(block.into());
5866
});
5967
}
6068

6169
fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
62-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().allocate(layout))
70+
critical_section::with(|cs| self.heap.borrow_ref_mut(cs).0.allocate(layout))
6371
}
6472

6573
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
6674
critical_section::with(|cs| {
6775
self.heap
68-
.borrow(cs)
69-
.borrow_mut()
76+
.borrow_ref_mut(cs)
77+
.0
7078
.deallocate(NonNull::new_unchecked(ptr), layout.align())
7179
})
7280
}

0 commit comments

Comments
 (0)