Skip to content

Commit bb571a2

Browse files
committed
Use OnceCell to prevent duplicate initialization
1 parent eb87f1a commit bb571a2

File tree

4 files changed

+46
-28
lines changed

4 files changed

+46
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1010
### Added
1111

1212
- Added a `init` macro to make initialization easier.
13+
- Use `OnceCell` to prevent duplicate initialization.
1314

1415
## [v0.6.0] - 2024-09-01
1516

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ 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+
/// Calling this macro multiple times or with `size == 0` will cause a panic.
36+
///
3337
/// # Example
3438
///
3539
/// ```rust

src/llff.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use core::alloc::{GlobalAlloc, Layout};
2-
use core::cell::RefCell;
2+
use core::cell::{OnceCell, RefCell};
33
use core::ptr::{self, NonNull};
44

55
use critical_section::Mutex;
66
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<OnceCell<LLHeap>>>,
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(OnceCell::new())),
2121
}
2222
}
2323

@@ -41,34 +41,37 @@ impl Heap {
4141
///
4242
/// # Safety
4343
///
44-
/// Obey these or Bad Stuff will happen.
44+
/// This function will panic if either of the following are true:
4545
///
46-
/// - This function must be called exactly ONCE.
47-
/// - `size > 0`
46+
/// - this function is called more than ONCE.
47+
/// - `size == 0`.
4848
pub unsafe fn init(&self, start_addr: usize, size: usize) {
49+
assert!(size > 0);
4950
critical_section::with(|cs| {
50-
self.heap
51-
.borrow(cs)
52-
.borrow_mut()
53-
.init(start_addr as *mut u8, size);
51+
assert!(self
52+
.heap
53+
.borrow_ref_mut(cs)
54+
.set(LLHeap::new(start_addr as *mut u8, size))
55+
.is_ok());
5456
});
5557
}
5658

5759
/// Returns an estimate of the amount of bytes in use.
5860
pub fn used(&self) -> usize {
59-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().used())
61+
critical_section::with(|cs| self.heap.borrow_ref_mut(cs).get_mut().unwrap().used())
6062
}
6163

6264
/// Returns an estimate of the amount of bytes available.
6365
pub fn free(&self) -> usize {
64-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().free())
66+
critical_section::with(|cs| self.heap.borrow_ref_mut(cs).get_mut().unwrap().free())
6567
}
6668

6769
fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
6870
critical_section::with(|cs| {
6971
self.heap
70-
.borrow(cs)
71-
.borrow_mut()
72+
.borrow_ref_mut(cs)
73+
.get_mut()
74+
.unwrap()
7275
.allocate_first_fit(layout)
7376
.ok()
7477
})
@@ -77,8 +80,9 @@ impl Heap {
7780
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
7881
critical_section::with(|cs| {
7982
self.heap
80-
.borrow(cs)
81-
.borrow_mut()
83+
.borrow_ref_mut(cs)
84+
.get_mut()
85+
.unwrap()
8286
.deallocate(NonNull::new_unchecked(ptr), layout)
8387
});
8488
}

src/tlsf.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
use core::alloc::{GlobalAlloc, Layout};
2-
use core::cell::RefCell;
2+
use core::cell::{OnceCell, RefCell};
33
use core::ptr::{self, NonNull};
44

5-
use const_default::ConstDefault;
65
use critical_section::Mutex;
76
use rlsf::Tlsf;
87

98
type TlsfHeap = Tlsf<'static, usize, usize, { usize::BITS as usize }, { usize::BITS as usize }>;
109

1110
/// A two-Level segregated fit heap.
1211
pub struct Heap {
13-
heap: Mutex<RefCell<TlsfHeap>>,
12+
heap: Mutex<RefCell<OnceCell<TlsfHeap>>>,
1413
}
1514

1615
impl Heap {
@@ -20,7 +19,7 @@ impl Heap {
2019
/// [`init`](Self::init) method before using the allocator.
2120
pub const fn empty() -> Heap {
2221
Heap {
23-
heap: Mutex::new(RefCell::new(ConstDefault::DEFAULT)),
22+
heap: Mutex::new(RefCell::new(OnceCell::new())),
2423
}
2524
}
2625

@@ -44,29 +43,39 @@ impl Heap {
4443
///
4544
/// # Safety
4645
///
47-
/// Obey these or Bad Stuff will happen.
46+
/// This function will panic if either of the following are true:
4847
///
49-
/// - This function must be called exactly ONCE.
50-
/// - `size > 0`
48+
/// - this function is called more than ONCE.
49+
/// - `size == 0`.
5150
pub unsafe fn init(&self, start_addr: usize, size: usize) {
51+
assert!(size > 0);
5252
critical_section::with(|cs| {
5353
let block: &[u8] = core::slice::from_raw_parts(start_addr as *const u8, size);
54+
self.heap.borrow_ref_mut(cs).set(TlsfHeap::new()).unwrap();
5455
self.heap
55-
.borrow(cs)
56-
.borrow_mut()
56+
.borrow_ref_mut(cs)
57+
.get_mut()
58+
.unwrap()
5759
.insert_free_block_ptr(block.into());
5860
});
5961
}
6062

6163
fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
62-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().allocate(layout))
64+
critical_section::with(|cs| {
65+
self.heap
66+
.borrow_ref_mut(cs)
67+
.get_mut()
68+
.unwrap()
69+
.allocate(layout)
70+
})
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+
.get_mut()
78+
.unwrap()
7079
.deallocate(NonNull::new_unchecked(ptr), layout.align())
7180
})
7281
}

0 commit comments

Comments
 (0)