Skip to content

Commit

Permalink
doc: add documents of some modules
Browse files Browse the repository at this point in the history
  • Loading branch information
equation314 committed Apr 19, 2023
1 parent 7aed483 commit e1666c7
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 3 deletions.
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ name = "axalloc"
version = "0.1.0"
edition = "2021"
authors = ["Yuekai Jia <[email protected]>"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
description = "ArceOS global memory allocator"
license = "GPL-3.0-or-later OR Apache-2.0"
homepage = "https://github.com/rcore-os/arceos"
repository = "https://github.com/rcore-os/arceos/tree/main/modules/axalloc"
documentation = "https://rcore-os.github.io/arceos/axalloc/index.html"

[dependencies]
log = "0.4"
Expand Down
73 changes: 73 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
//! [ArceOS](https://github.com/rcore-os/arceos) global memory allocator.
//!
//! It provides [`GlobalAllocator`], which implements the trait
//! [`core::alloc::GlobalAlloc`]. A static global variable of type
//! [`GlobalAllocator`] is defined with the `#[global_allocator]` attribute, to
//! be registered as the standard library’s default allocator.
#![no_std]
#![feature(alloc_error_handler)]

Expand All @@ -17,19 +24,34 @@ const MIN_HEAP_SIZE: usize = 0x8000; // 32 K

pub use page::GlobalPage;

/// The global allocator used by ArceOS.
///
/// It combines a [`ByteAllocator`] and a [`PageAllocator`] into a simple
/// two-level allocator: firstly tries allocate from the byte allocator, if
/// there is no memory, asks the page allocator for more memory and adds it to
/// the byte allocator.
///
/// Currently, [`SlabByteAllocator`] is used as the byte allocator, while
/// [`BitmapPageAllocator`] is used as the page allocator.
pub struct GlobalAllocator {
balloc: SpinNoIrq<SlabByteAllocator>,
palloc: SpinNoIrq<BitmapPageAllocator<PAGE_SIZE>>,
}

impl GlobalAllocator {
/// Creates an empty [`GlobalAllocator`].
pub const fn new() -> Self {
Self {
balloc: SpinNoIrq::new(SlabByteAllocator::new()),
palloc: SpinNoIrq::new(BitmapPageAllocator::new()),
}
}

/// Initializes the allocator with the given region.
///
/// It firstly adds the whole region to the page allocator, then allocates
/// a small region (32 KB) to initialize the byte allocator. Therefore,
/// the given region must be larger than 32 KB.
pub fn init(&self, start_vaddr: usize, size: usize) {
assert!(size > MIN_HEAP_SIZE);
let init_heap_size = MIN_HEAP_SIZE;
Expand All @@ -40,10 +62,22 @@ impl GlobalAllocator {
self.balloc.lock().init(heap_ptr, init_heap_size);
}

/// Add the given region to the allocator.
///
/// It will add the whole region to the byte allocator.
pub fn add_memory(&self, start_vaddr: usize, size: usize) -> AllocResult {
self.balloc.lock().add_memory(start_vaddr, size)
}

/// Allocate arbitrary number of bytes. Returns the left bound of the
/// allocated region.
///
/// It firstly tries to allocate from the byte allocator. If there is no
/// memory, it asks the page allocator for more memory and adds it to the
/// byte allocator.
///
/// `align_pow2` must be a power of 2, and the returned region bound will be
/// aligned to it.
pub fn alloc(&self, size: usize, align_pow2: usize) -> AllocResult<usize> {
// simple two-level allocator: if no heap memory, allocate from the page allocator.
let mut balloc = self.balloc.lock();
Expand All @@ -64,30 +98,54 @@ impl GlobalAllocator {
}
}

/// Gives back the allocated region to the byte allocator.
///
/// The region should be allocated by [`alloc`], and `align_pow2` should be
/// the same as the one used in [`alloc`]. Otherwise, the behavior is
/// undefined.
///
/// [`alloc`]: GlobalAllocator::alloc
pub fn dealloc(&self, pos: usize, size: usize, align_pow2: usize) {
self.balloc.lock().dealloc(pos, size, align_pow2)
}

/// Allocates contiguous pages.
///
/// It allocates `num_pages` pages from the page allocator.
///
/// `align_pow2` must be a power of 2, and the returned region bound will be
/// aligned to it.
pub fn alloc_pages(&self, num_pages: usize, align_pow2: usize) -> AllocResult<usize> {
self.palloc.lock().alloc_pages(num_pages, align_pow2)
}

/// Gives back the allocated pages starts from `pos` to the page allocator.
///
/// The pages should be allocated by [`alloc_pages`], and `align_pow2`
/// should be the same as the one used in [`alloc_pages`]. Otherwise, the
/// behavior is undefined.
///
/// [`alloc_pages`]: GlobalAllocator::alloc_pages
pub fn dealloc_pages(&self, pos: usize, num_pages: usize) {
self.palloc.lock().dealloc_pages(pos, num_pages)
}

/// Returns the number of allocated bytes in the byte allocator.
pub fn used_bytes(&self) -> usize {
self.balloc.lock().used_bytes()
}

/// Returns the number of available bytes in the byte allocator.
pub fn available_bytes(&self) -> usize {
self.balloc.lock().available_bytes()
}

/// Returns the number of allocated pages in the page allocator.
pub fn used_pages(&self) -> usize {
self.palloc.lock().used_pages()
}

/// Returns the number of available pages in the page allocator.
pub fn available_pages(&self) -> usize {
self.palloc.lock().available_pages()
}
Expand Down Expand Up @@ -120,10 +178,19 @@ fn handle_alloc_error(layout: Layout) -> ! {
);
}

/// Returns the reference to the global allocator.
pub fn global_allocator() -> &'static GlobalAllocator {
&GLOBAL_ALLOCATOR
}

/// Initializes the global allocator with the given memory region.
///
/// Note that the memory region bounds are just numbers, and the allocator
/// does not actually access the region. Users should ensure that the region
/// is valid and not being used by others, so that the allocated memory is also
/// valid.
///
/// This function should be called only once, and before any allocation.
pub fn global_init(start_vaddr: usize, size: usize) {
debug!(
"initialize global allocator at: [{:#x}, {:#x})",
Expand All @@ -133,6 +200,12 @@ pub fn global_init(start_vaddr: usize, size: usize) {
GLOBAL_ALLOCATOR.init(start_vaddr, size);
}

/// Add the given memory region to the global allocator.
///
/// Users should ensure that the region is valid and not being used by others,
/// so that the allocated memory is also valid.
///
/// It's similar to [`global_init`], but can be called multiple times.
pub fn global_add_memory(start_vaddr: usize, size: usize) -> AllocResult {
debug!(
"add a memory region to global allocator: [{:#x}, {:#x})",
Expand Down
4 changes: 3 additions & 1 deletion src/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use memory_addr::{PhysAddr, VirtAddr};

use crate::{global_allocator, PAGE_SIZE};

/// A safe wrapper of contiguous 4K-sized pages.
/// A RAII wrapper of contiguous 4K-sized pages.
///
/// It will automatically deallocate the pages when dropped.
#[derive(Debug)]
pub struct GlobalPage {
start_vaddr: VirtAddr,
Expand Down

0 comments on commit e1666c7

Please sign in to comment.