Skip to content

Commit 036f4a3

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

File tree

4 files changed

+44
-32
lines changed

4 files changed

+44
-32
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: 19 additions & 18 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

@@ -39,36 +39,36 @@ impl Heap {
3939
/// `0x1000` and `size` is `0x30000` then the allocator won't use memory at
4040
/// addresses `0x31000` and larger.
4141
///
42-
/// # Safety
42+
/// # Panics
4343
///
44-
/// Obey these or Bad Stuff will happen.
45-
///
46-
/// - This function must be called exactly ONCE.
47-
/// - `size > 0`
44+
/// Calling this function multiple times or with `size == 0` will cause a panic.
4845
pub unsafe fn init(&self, start_addr: usize, size: usize) {
46+
assert!(size > 0);
4947
critical_section::with(|cs| {
50-
self.heap
51-
.borrow(cs)
52-
.borrow_mut()
53-
.init(start_addr as *mut u8, size);
48+
assert!(self
49+
.heap
50+
.borrow_ref_mut(cs)
51+
.set(LLHeap::new(start_addr as *mut u8, size))
52+
.is_ok());
5453
});
5554
}
5655

5756
/// Returns an estimate of the amount of bytes in use.
5857
pub fn used(&self) -> usize {
59-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().used())
58+
critical_section::with(|cs| self.heap.borrow_ref_mut(cs).get_mut().unwrap().used())
6059
}
6160

6261
/// Returns an estimate of the amount of bytes available.
6362
pub fn free(&self) -> usize {
64-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().free())
63+
critical_section::with(|cs| self.heap.borrow_ref_mut(cs).get_mut().unwrap().free())
6564
}
6665

6766
fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
6867
critical_section::with(|cs| {
6968
self.heap
70-
.borrow(cs)
71-
.borrow_mut()
69+
.borrow_ref_mut(cs)
70+
.get_mut()
71+
.unwrap()
7272
.allocate_first_fit(layout)
7373
.ok()
7474
})
@@ -77,8 +77,9 @@ impl Heap {
7777
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
7878
critical_section::with(|cs| {
7979
self.heap
80-
.borrow(cs)
81-
.borrow_mut()
80+
.borrow_ref_mut(cs)
81+
.get_mut()
82+
.unwrap()
8283
.deallocate(NonNull::new_unchecked(ptr), layout)
8384
});
8485
}

src/tlsf.rs

Lines changed: 20 additions & 14 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

@@ -42,31 +41,38 @@ impl Heap {
4241
/// `0x1000` and `size` is `0x30000` then the allocator won't use memory at
4342
/// addresses `0x31000` and larger.
4443
///
45-
/// # Safety
44+
/// # Panics
4645
///
47-
/// Obey these or Bad Stuff will happen.
48-
///
49-
/// - This function must be called exactly ONCE.
50-
/// - `size > 0`
46+
/// Calling this function multiple times or with `size == 0` will cause a panic.
5147
pub unsafe fn init(&self, start_addr: usize, size: usize) {
48+
assert!(size > 0);
5249
critical_section::with(|cs| {
5350
let block: &[u8] = core::slice::from_raw_parts(start_addr as *const u8, size);
51+
self.heap.borrow_ref_mut(cs).set(TlsfHeap::new()).unwrap();
5452
self.heap
55-
.borrow(cs)
56-
.borrow_mut()
53+
.borrow_ref_mut(cs)
54+
.get_mut()
55+
.unwrap()
5756
.insert_free_block_ptr(block.into());
5857
});
5958
}
6059

6160
fn alloc(&self, layout: Layout) -> Option<NonNull<u8>> {
62-
critical_section::with(|cs| self.heap.borrow(cs).borrow_mut().allocate(layout))
61+
critical_section::with(|cs| {
62+
self.heap
63+
.borrow_ref_mut(cs)
64+
.get_mut()
65+
.unwrap()
66+
.allocate(layout)
67+
})
6368
}
6469

6570
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
6671
critical_section::with(|cs| {
6772
self.heap
68-
.borrow(cs)
69-
.borrow_mut()
73+
.borrow_ref_mut(cs)
74+
.get_mut()
75+
.unwrap()
7076
.deallocate(NonNull::new_unchecked(ptr), layout.align())
7177
})
7278
}

0 commit comments

Comments
 (0)