ruspiro_allocator/lib.rs
1/***********************************************************************************************************************
2 * Copyright (c) 2020 by the authors
3 *
4 * Author: André Borrmann <pspwizard@gmx.de>
5 * License: Apache License 2.0 / MIT
6 **********************************************************************************************************************/
7#![doc(html_root_url = "https://docs.rs/ruspiro-allocator/0.4.6")]
8#![cfg_attr(not(any(test, doctest)), no_std)]
9#![feature(alloc_error_handler)]
10//! # Custom Allocator for HEAP memory allocations
11//!
12//! This crate provides a custom allocator for heap memory. If any baremetal crate uses functions and structures from
13//! the ``alloc`` crate an allocator need to be provided as well. However, this crate does not export any public
14//! API to be used. It only encapsulates the memeory allocator that shall be linked into the binary.
15//!
16//! # Prerequisit
17//!
18//! The lock free memory allocations use atomic operations. Thus to properly work on a Raspberry Pi the MMU is required
19//! to be configured and enabled. Otherwise memory allocations will just hang the cores.
20//!
21//! # Usage
22//!
23//! To link the custom allocator with your project just add the usage to your main crate rust file like so:
24//! ```ignore
25//! extern crate ruspiro_allocator;
26//! ```
27//! Wherever you define the usage of the ``ruspiro-allocator`` crate within your project does not matter. But as soon
28//! as this is done the dynamic structures requiring heap memory allocations from the ``alloc`` crate could be used like
29//! so:
30//! ```
31//! #[macro_use]
32//! extern crate alloc;
33//! use alloc::{boxed::Box, vec::Vec};
34//!
35//! fn main() {
36//! let mut v: Vec<u32> = vec![10, 20];
37//! let b: Box<u16> = Box::new(10);
38//! v.push(12);
39//! }
40//! ```
41//!
42
43// this is crate is required to bring the core memory functions like memset, memcpy etc. into the link process
44#[doc(hidden)]
45extern crate rlibc;
46
47/// this specifies the custom memory allocator to use whenever heap memory need to be allocated or freed
48#[cfg_attr(not(any(test, doctest)), global_allocator)]
49static ALLOCATOR: RusPiRoAllocator = RusPiRoAllocator;
50
51use core::alloc::{GlobalAlloc, Layout};
52
53mod memory;
54
55struct RusPiRoAllocator;
56
57unsafe impl GlobalAlloc for RusPiRoAllocator {
58 #[inline]
59 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
60 memory::alloc(layout.size(), layout.align())
61 }
62
63 #[inline]
64 unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
65 memory::free(ptr)
66 }
67
68 #[inline]
69 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
70 let ptr = memory::alloc(layout.size(), layout.align());
71 memset(ptr, 0x0, layout.size());
72 ptr
73 }
74}
75
76#[cfg(not(any(test, doctest)))]
77#[alloc_error_handler]
78#[allow(clippy::empty_loop)]
79fn alloc_error_handler(_: Layout) -> ! {
80 // TODO: how to handle memory allocation errors?
81 loop {}
82}
83
84extern "C" {
85 // reference to the compiler built-in function
86 fn memset(ptr: *mut u8, value: i32, size: usize) -> *mut u8;
87}