Skip to content

Commit 7d96042

Browse files
committed
Add a flag to prevent duplicate initialization
1 parent eb87f1a commit 7d96042

File tree

4 files changed

+54
-27
lines changed

4 files changed

+54
-27
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111

1212
- Added a `init` macro to make initialization easier.
1313

14+
### Changed
15+
16+
- The `init` function will panic if it's called more than once or with `size == 0`.
17+
1418
## [v0.6.0] - 2024-09-01
1519

1620
### Added

src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ pub use tlsf::Heap as TlsfHeap;
3030
/// It internally calls `Heap::init(...)` on the heap,
3131
/// so `Heap::init(...)` should not be called directly if this macro is used.
3232
///
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+
///
3340
/// # Example
3441
///
3542
/// ```rust

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)