Skip to content

Replace linked-list allocator with TLSF #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 23 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,31 @@ name = "alloc-cortex-m"
version = "0.4.0"

[dependencies]
tlsf = { git = "https://github.com/FluenTech/tlsf" }
cortex-m = "0.6.2"

[dependencies.linked_list_allocator]
default-features = false
version = "0.8.1"
[features]
FLI6 = ["tlsf/FLI6"]
FLI7 = ["tlsf/FLI7"]
FLI8 = ["tlsf/FLI8"]
FLI9 = ["tlsf/FLI9"]
FLI10 = ["tlsf/FLI10"]
FLI11 = ["tlsf/FLI11"]
FLI12 = ["tlsf/FLI12"]
FLI13 = ["tlsf/FLI13"]
FLI14 = ["tlsf/FLI14"]
FLI15 = ["tlsf/FLI15"]

#[dependencies.linked_list_allocator]
#default-features = false
#version = "0.8.1"


[dev-dependencies]
nrf52832-hal = { version = "0.10.0", default-features = false, features = ["rt", "xxAA-package"] }
cortex-m = "0.6.2"
panic-halt = "0.2.0"
spin = "0.5.2"
jlink_rtt = "0.2.0"
panic_rtt = "0.3.0"
cortex-m-rt = "0.6.12"
14 changes: 14 additions & 0 deletions examples/.cargo/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
rustflags = [
# LLD (shipped with the Rust toolchain) is used as the default linker
"-C", "link-arg=-Tlink.x",
]

[build]
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)

[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations
opt-level = "z"
16 changes: 10 additions & 6 deletions examples/global_alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,25 @@

extern crate alloc;

use core::panic::PanicInfo;
use core::alloc::Layout;
use alloc::vec::Vec;
use alloc_cortex_m::CortexMHeap;
use core::alloc::Layout;
use core::fmt::Write;
use core::panic::PanicInfo;
use cortex_m_rt::entry;

#[global_allocator]
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();

#[repr(align(4))]
struct Aligned<T>(T);

#[entry]
fn main() -> ! {
// Initialize the allocator BEFORE you use it
let start = cortex_m_rt::heap_start() as usize;
let size = 1024; // in bytes
unsafe { ALLOCATOR.init(start, size) }
static mut M: Aligned<[u8; tlsf::MAX_BLOCK_SIZE as usize]> =
Aligned([0; tlsf::MAX_BLOCK_SIZE as usize]);

ALLOCATOR.extend(&mut M.0);

let mut xs = Vec::new();
xs.push(1);
Expand Down
48 changes: 48 additions & 0 deletions examples/nrf52_dk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#![no_main]
#![no_std]
#![feature(alloc_prelude)]
#![feature(alloc_error_handler)]

extern crate alloc;
extern crate nrf52832_hal;
extern crate panic_rtt;

use alloc::vec::Vec;
use alloc_cortex_m::CortexMHeap;
use core::alloc::Layout;
use core::fmt::Write;
use cortex_m_rt::entry;
use jlink_rtt::NonBlockingOutput;

#[global_allocator]
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();

#[repr(align(4))]
struct Aligned<T>(T);

#[entry]
fn main() -> ! {
static mut M: Aligned<[u8; tlsf::MAX_BLOCK_SIZE as usize]> =
Aligned([0; tlsf::MAX_BLOCK_SIZE as usize]);

let mut log = NonBlockingOutput::new();
writeln!(log, "Output stream opened").ok().unwrap();

ALLOCATOR.extend(&mut M.0);

writeln!(log, "Heap extended").ok().unwrap();

let mut xs = Vec::new();
xs.push(1);

writeln!(log, "Vector instantiated").ok().unwrap();

loop {
xs.push(1);
}
}

#[alloc_error_handler]
fn oom(_: Layout) -> ! {
panic!("alloc error");
}
94 changes: 55 additions & 39 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,78 +5,94 @@
//! # Example
//!
//! For a usage example, see `examples/global_alloc.rs`.
//!
//! # Features
//!
//! The First Level Index (FLI) must be specified. The FLI determines the tlsf overhead required,
//! the largest object that can be stored on the heap, and the largest block that can be used to
//! _extend_ the memory pool.
//!
//! The FLI can be specified by setting one of the FLIx features in the range of FLI6..=FLI15.
//!
//! |FLI|`size_of(Tlsf)`|`MAX_REQUEST_SIZE`|`MAX_BLOCK_SIZE`|
//! |---|---------------|------------------|----------------|
//! |6 |36 |60 |60 |
//! |7 |70 |120 |124 |
//! |8 |104 |240 |252 |
//! |9 |138 |480 |508 |
//! |10 |172 |960 |1,020 |
//! |11 |206 |1,920 |2,044 |
//! |12 |240 |3,840 |4,092 |
//! |13 |274 |7,680 |8,188 |
//! |14 |308 |15,360 |16,380 |
//! |15 |342 |30,720 |32,764 |
//!
//! *All sizes are in bytes*

#![no_std]

use core::cell::RefCell;
use core::alloc::{GlobalAlloc, Layout};
use core::cell::RefCell;
use core::ptr::NonNull;

use cortex_m::interrupt::Mutex;
use linked_list_allocator::Heap;
use tlsf::Tlsf as Heap;

pub struct CortexMHeap {
heap: Mutex<RefCell<Heap>>,
}

impl CortexMHeap {
/// Crate a new UNINITIALIZED heap allocator
/// Create a new heap allocator, with an empty memory pool
///
/// You must initialize this heap using the
/// [`init`](struct.CortexMHeap.html#method.init) method before using the allocator.
/// The allocator's memory pool must be extended using the
/// [`extend`](struct.CortexMHeap.html#method.extend) method before using the allocator.
pub const fn empty() -> CortexMHeap {
CortexMHeap {
heap: Mutex::new(RefCell::new(Heap::empty())),
heap: Mutex::new(RefCell::new(Heap::new())),
}
}

/// Initializes the heap
/// Adds a memory _chunk_ to the allocator's memory pool
///
/// This function must be called BEFORE you run any code that makes use of the
/// This function must be called at least once BEFORE any code makes use of the
/// allocator.
///
/// `start_addr` is the address where the heap will be located.
/// # Examples
///
/// `size` is the size of the heap in bytes.
/// ```rust
/// use alloc_cortex_m::CortexMHeap;
///
/// Note that:
/// static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
///
/// - The heap grows "upwards", towards larger addresses. Thus `end_addr` must
/// be larger than `start_addr`
/// static mut CHUNK: [u8; tlsf::MAX_BLOCK_SIZE as usize] =
/// [0; tlsf::MAX_BLOCK_SIZE as usize];
///
/// - The size of the heap is `(end_addr as usize) - (start_addr as usize)`. The
/// allocator won't use the byte at `end_addr`.
///
/// # Unsafety
///
/// Obey these or Bad Stuff will happen.
///
/// - This function must be called exactly ONCE.
/// - `size > 0`
pub unsafe fn init(&self, start_addr: usize, size: usize) {
cortex_m::interrupt::free(|cs| {
self.heap
.borrow(cs)
.borrow_mut()
.init(start_addr, size);
/// unsafe { ALLOCATOR.extend(&mut CHUNK) }
/// ```
pub fn extend(&self, block: &'static mut [u8]) {
cortex_m::interrupt::free(move |cs| {
self.heap.borrow(cs).borrow_mut().extend(block);
});
}
}

unsafe impl GlobalAlloc for CortexMHeap {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
cortex_m::interrupt::free(|cs| self.heap
.borrow(cs)
.borrow_mut()
.allocate_first_fit(layout)
.ok()
.map_or(0 as *mut u8, |allocation| allocation.as_ptr()))
cortex_m::interrupt::free(|cs| {
let returned_mem = self.heap.borrow(cs).borrow_mut().alloc(layout);
match returned_mem {
Ok(mem_ptr) => mem_ptr.as_ptr(),
Err(_) => 0_usize as *mut u8,
}
})
}

unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
cortex_m::interrupt::free(|cs| self.heap
.borrow(cs)
.borrow_mut()
.deallocate(NonNull::new_unchecked(ptr), layout));
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
if let Some(mem_ptr) = NonNull::new(ptr) {
cortex_m::interrupt::free(|cs| {
self.heap.borrow(cs).borrow_mut().dealloc(mem_ptr);
});
}
}
}