buddy_alloc/
non_threadsafe_alloc.rs

1//! NonThreadSafeAlloc
2//! An allocator that does not support thread-safe
3
4use crate::buddy_alloc::{BuddyAlloc, BuddyAllocParam};
5use crate::fast_alloc::{FastAlloc, FastAllocParam, BLOCK_SIZE};
6use core::alloc::{GlobalAlloc, Layout};
7use core::cell::RefCell;
8
9/// Use buddy allocator if request bytes is large than this,
10/// otherwise use fast allocator
11const MAX_FAST_ALLOC_SIZE: usize = BLOCK_SIZE;
12
13/// NonThreadsafeAlloc
14/// perfect for single threaded devices
15pub struct NonThreadsafeAlloc {
16    fast_alloc_param: FastAllocParam,
17    inner_fast_alloc: RefCell<Option<FastAlloc>>,
18    buddy_alloc_param: BuddyAllocParam,
19    inner_buddy_alloc: RefCell<Option<BuddyAlloc>>,
20}
21
22impl NonThreadsafeAlloc {
23    /// see BuddyAlloc::new
24    pub const fn new(fast_alloc_param: FastAllocParam, buddy_alloc_param: BuddyAllocParam) -> Self {
25        NonThreadsafeAlloc {
26            inner_fast_alloc: RefCell::new(None),
27            inner_buddy_alloc: RefCell::new(None),
28            fast_alloc_param,
29            buddy_alloc_param,
30        }
31    }
32
33    unsafe fn with_fast_alloc<R, F: FnOnce(&mut FastAlloc) -> R>(&self, f: F) -> R {
34        let mut inner = self.inner_fast_alloc.borrow_mut();
35        let alloc = inner.get_or_insert_with(|| FastAlloc::new(self.fast_alloc_param));
36        f(alloc)
37    }
38
39    unsafe fn with_buddy_alloc<R, F: FnOnce(&mut BuddyAlloc) -> R>(&self, f: F) -> R {
40        let mut inner = self.inner_buddy_alloc.borrow_mut();
41        let alloc = inner.get_or_insert_with(|| BuddyAlloc::new(self.buddy_alloc_param));
42        f(alloc)
43    }
44}
45
46unsafe impl GlobalAlloc for NonThreadsafeAlloc {
47    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
48        let bytes = layout.size();
49        // use BuddyAlloc if size is larger than MAX_FAST_ALLOC_SIZE
50        if bytes > MAX_FAST_ALLOC_SIZE {
51            self.with_buddy_alloc(|alloc| alloc.malloc(bytes))
52        } else {
53            // try fast alloc, fallback to BuddyAlloc if failed
54            let mut p = self.with_fast_alloc(|alloc| alloc.malloc(bytes));
55            if p.is_null() {
56                p = self.with_buddy_alloc(|alloc| alloc.malloc(bytes));
57            }
58            p
59        }
60    }
61    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
62        let freed = self.with_fast_alloc(|alloc| {
63            if alloc.contains_ptr(ptr) {
64                alloc.free(ptr);
65                true
66            } else {
67                false
68            }
69        });
70        if !freed {
71            self.with_buddy_alloc(|alloc| alloc.free(ptr));
72        }
73    }
74}
75
76unsafe impl Sync for NonThreadsafeAlloc {}