diff --git a/Cargo.toml b/Cargo.toml index 3a274c0..997f17f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ tracking = [] bench = [] [dependencies] +axallocator = "0.2" cfg-if = "1.0" log = { version = "0.4", optional = true } diff --git a/src/lib.rs b/src/lib.rs index f34409b..157b6a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,9 +75,6 @@ extern crate alloc; -use core::alloc::Layout; -use core::ptr::NonNull; - // Logging support - conditionally import log crate #[cfg(feature = "log")] extern crate log; @@ -105,40 +102,13 @@ macro_rules! trace { ($($arg:tt)*) => {}; } +pub use axallocator::{ + AllocError, AllocResult, BaseAllocator, ByteAllocator, IdAllocator, PageAllocator, +}; + /// Default page size for backward compatibility (4KB) pub const DEFAULT_PAGE_SIZE: usize = 0x1000; -/// The error type used for allocation operations. -/// -/// # Examples -/// -/// ``` -/// use buddy_slab_allocator::AllocError; -/// -/// fn handle_error(error: AllocError) { -/// match error { -/// AllocError::InvalidParam => eprintln!("Invalid parameters"), -/// AllocError::MemoryOverlap => eprintln!("Memory regions overlap"), -/// AllocError::NoMemory => eprintln!("Out of memory"), -/// AllocError::NotAllocated => eprintln!("Double free detected"), -/// } -/// } -/// ``` -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AllocError { - /// Invalid `size` or alignment (e.g. unaligned) - InvalidParam, - /// Memory added by `add_memory` overlapped with existing memory - MemoryOverlap, - /// No enough memory to allocate - NoMemory, - /// Attempt to deallocate a memory region that was not allocated - NotAllocated, -} - -/// A [`Result`] type with [`AllocError`] as the error type. -pub type AllocResult = Result; - /// Address translator used by allocators to reason about physical addresses. /// /// Implementations should provide a stable virtual-to-physical mapping @@ -165,243 +135,6 @@ pub trait AddrTranslator: Sync { fn virt_to_phys(&self, va: usize) -> Option; } -/// The base allocator trait inherited by other allocator traits. -/// -/// Provides common initialization methods for all allocator types. -pub trait BaseAllocator { - /// Initialize the allocator with a free memory region. - /// - /// # Arguments - /// - /// * `start` - Starting address of the memory region - /// * `size` - Size of the memory region in bytes - /// - /// # Examples - /// - /// ``` - /// # use buddy_slab_allocator::BaseAllocator; - /// # struct MyAllocator; - /// # impl BaseAllocator for MyAllocator { - /// # fn init(&mut self, start: usize, size: usize) {} - /// # fn add_memory(&mut self, start: usize, size: usize) -> buddy_slab_allocator::AllocResult { Ok(()) } - /// # } - /// let mut alloc = MyAllocator; - /// alloc.init(0x8000_0000, 16 * 1024 * 1024); - /// ``` - fn init(&mut self, start: usize, size: usize); - - /// Add a free memory region to the allocator. - /// - /// # Arguments - /// - /// * `start` - Starting address of the memory region - /// * `size` - Size of the memory region in bytes - /// - /// # Returns - /// - /// Returns `Ok(())` on success, or an error if the region overlaps - /// with existing memory. - fn add_memory(&mut self, start: usize, size: usize) -> AllocResult; -} - -/// Byte-granularity allocator for arbitrary-size allocations. -/// -/// Provides methods for allocating and deallocating memory with -/// byte-level granularity. -pub trait ByteAllocator { - /// Allocate memory with the given size (in bytes) and alignment. - /// - /// # Arguments - /// - /// * `layout` - Memory layout specifying size and alignment requirements - /// - /// # Returns - /// - /// Returns a pointer to the allocated memory on success, or an error - /// if allocation fails. - /// - /// # Examples - /// - /// ``` - /// # use buddy_slab_allocator::ByteAllocator; - /// # use core::alloc::Layout; - /// # use core::ptr::NonNull; - /// # struct MyAllocator; - /// # impl ByteAllocator for MyAllocator { - /// # fn alloc(&mut self, layout: Layout) -> buddy_slab_allocator::AllocResult> { Ok(NonNull::dangling()) } - /// # fn dealloc(&mut self, pos: NonNull, layout: Layout) {} - /// # fn total_bytes(&self) -> usize { 0 } - /// # fn used_bytes(&self) -> usize { 0 } - /// # fn available_bytes(&self) -> usize { 0 } - /// # } - /// let mut alloc = MyAllocator; - /// let layout = Layout::from_size_align(64, 8).unwrap(); - /// let ptr = alloc.alloc(layout)?; - /// # Ok::<(), buddy_slab_allocator::AllocError>(()) - /// ``` - fn alloc(&mut self, layout: Layout) -> AllocResult>; - - /// Deallocate memory at the given position, size, and alignment. - /// - /// # Arguments - /// - /// * `pos` - Pointer to the memory to deallocate - /// * `layout` - Memory layout specifying size and alignment requirements - /// - /// # Safety - /// - /// The pointer must have been previously allocated from this allocator - /// with the same layout. - fn dealloc(&mut self, pos: NonNull, layout: Layout); - - /// Returns total memory size in bytes managed by this allocator. - fn total_bytes(&self) -> usize; - - /// Returns allocated memory size in bytes. - fn used_bytes(&self) -> usize; - - /// Returns available memory size in bytes. - fn available_bytes(&self) -> usize; -} - -/// Page-granularity allocator for managing memory in pages. -/// -/// Provides methods for allocating and deallocating contiguous pages -/// of memory with specific alignment requirements. -pub trait PageAllocator: BaseAllocator { - /// The size of a memory page in bytes (must be a power of two). - const PAGE_SIZE: usize; - - /// Allocate contiguous memory pages with given count and alignment (in bytes). - /// - /// # Arguments - /// - /// * `num_pages` - Number of pages to allocate - /// * `alignment` - Alignment requirement in bytes (must be power of two) - /// - /// # Returns - /// - /// Returns the starting address of the allocated pages on success, - /// or an error if allocation fails. - /// - /// # Examples - /// - /// ``` - /// # use buddy_slab_allocator::{PageAllocator, BaseAllocator}; - /// # struct MyAllocator; - /// # impl BaseAllocator for MyAllocator { - /// # fn init(&mut self, start: usize, size: usize) {} - /// # fn add_memory(&mut self, start: usize, size: usize) -> buddy_slab_allocator::AllocResult { Ok(()) } - /// # } - /// # impl PageAllocator for MyAllocator { - /// # const PAGE_SIZE: usize = 0x1000; - /// # fn alloc_pages(&mut self, num_pages: usize, alignment: usize) -> buddy_slab_allocator::AllocResult { Ok(0) } - /// # fn dealloc_pages(&mut self, pos: usize, num_pages: usize) {} - /// # fn alloc_pages_at(&mut self, base: usize, num_pages: usize, alignment: usize) -> buddy_slab_allocator::AllocResult { Ok(0) } - /// # fn total_pages(&self) -> usize { 0 } - /// # fn used_pages(&self) -> usize { 0 } - /// # fn available_pages(&self) -> usize { 0 } - /// # } - /// let mut alloc = MyAllocator; - /// let addr = alloc.alloc_pages(4, 0x1000)?; - /// # Ok::<(), buddy_slab_allocator::AllocError>(()) - /// ``` - fn alloc_pages(&mut self, num_pages: usize, alignment: usize) -> AllocResult; - - /// Deallocate contiguous memory pages with given position and count. - /// - /// # Arguments - /// - /// * `pos` - Starting address of the pages to deallocate - /// * `num_pages` - Number of pages to deallocate - /// - /// # Safety - /// - /// The address range must have been previously allocated from this allocator. - fn dealloc_pages(&mut self, pos: usize, num_pages: usize); - - /// Allocate contiguous memory pages with given base address, count and alignment (in bytes). - /// - /// # Arguments - /// - /// * `base` - Desired starting address for allocation - /// * `num_pages` - Number of pages to allocate - /// * `alignment` - Alignment requirement in bytes (must be power of two) - /// - /// # Returns - /// - /// Returns the starting address of the allocated pages on success, - /// or an error if the region cannot be allocated at the specified base. - fn alloc_pages_at( - &mut self, - base: usize, - num_pages: usize, - alignment: usize, - ) -> AllocResult; - - /// Returns the total number of memory pages managed by this allocator. - fn total_pages(&self) -> usize; - - /// Returns the number of allocated memory pages. - fn used_pages(&self) -> usize; - - /// Returns the number of available memory pages. - fn available_pages(&self) -> usize; -} - -/// ID allocator for managing unique identifiers (e.g., thread IDs). -/// -/// Provides methods for allocating and deallocating unique IDs with -/// alignment constraints. -pub trait IdAllocator: BaseAllocator { - /// Allocate contiguous IDs with given count and alignment. - /// - /// # Arguments - /// - /// * `count` - Number of IDs to allocate - /// * `alignment` - Alignment requirement for the starting ID - /// - /// # Returns - /// - /// Returns the starting ID on success, or an error if allocation fails. - fn alloc_id(&mut self, count: usize, alignment: usize) -> AllocResult; - - /// Deallocate contiguous IDs with given position and count. - /// - /// # Arguments - /// - /// * `start_id` - Starting ID of the range to deallocate - /// * `count` - Number of IDs to deallocate - /// - /// # Safety - /// - /// The ID range must have been previously allocated from this allocator. - fn dealloc_id(&mut self, start_id: usize, count: usize); - - /// Checks whether the given ID is currently allocated. - fn is_allocated(&self, id: usize) -> bool; - - /// Mark the given ID as allocated and prevent it from being reallocated. - /// - /// # Arguments - /// - /// * `id` - The ID to mark as permanently allocated - /// - /// # Returns - /// - /// Returns `Ok(())` on success, or an error if the ID is already allocated. - fn alloc_fixed_id(&mut self, id: usize) -> AllocResult; - - /// Returns the maximum number of IDs supported by this allocator. - fn size(&self) -> usize; - - /// Returns the number of currently allocated IDs. - fn used(&self) -> usize; - - /// Returns the number of available IDs. - fn available(&self) -> usize; -} - #[inline] #[allow(dead_code)] const fn align_down(pos: usize, align: usize) -> usize { diff --git a/src/slab/slab_byte_allocator.rs b/src/slab/slab_byte_allocator.rs index 23f8750..80d4a17 100644 --- a/src/slab/slab_byte_allocator.rs +++ b/src/slab/slab_byte_allocator.rs @@ -9,7 +9,7 @@ use core::ptr::NonNull; #[cfg(feature = "log")] use log::warn; -use crate::{AllocError, AllocResult, ByteAllocator}; +use crate::{AllocError, AllocResult, BaseAllocator, ByteAllocator}; // Re-export public types from sibling modules pub use super::slab_cache::SlabCache; @@ -151,6 +151,15 @@ impl Default for SlabByteAllocator { } } +// This implementation is never called, so no-op implementations are fine +impl BaseAllocator for SlabByteAllocator { + fn init(&mut self, _start: usize, _size: usize) {} + + fn add_memory(&mut self, _start: usize, _size: usize) -> AllocResult { + Ok(()) + } +} + impl ByteAllocator for SlabByteAllocator { fn alloc(&mut self, layout: Layout) -> AllocResult> { let size_class = SizeClass::from_layout(layout).ok_or(AllocError::InvalidParam)?; diff --git a/tests/dma32_pages_test.rs b/tests/dma32_pages_test.rs index a681d4a..2d4f24f 100644 --- a/tests/dma32_pages_test.rs +++ b/tests/dma32_pages_test.rs @@ -49,13 +49,8 @@ fn test_alloc_dma32_pages_uninitialized() { // Try to allocate pages - should fail because allocator is not initialized let result = allocator.alloc_dma32_pages(1, PAGE_SIZE); assert!( - result.is_err(), - "Expected error when allocating from uninitialized allocator" - ); - assert_eq!( - result.unwrap_err(), - AllocError::NoMemory, - "Expected NoMemory error" + matches!(result, Err(AllocError::NoMemory)), + "Expected NoMemory error when allocating from uninitialized allocator" ); } diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 91aeaea..a48b633 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -356,12 +356,12 @@ fn test_error_conditions() { // Test invalid parameter let result = allocator.alloc_pages(0, PAGE_SIZE); - assert_eq!(result, Err(AllocError::InvalidParam)); + assert!(matches!(result, Err(AllocError::InvalidParam))); // Test allocation too large let huge_pages = TEST_HEAP_SIZE / PAGE_SIZE + 1000; let result = allocator.alloc_pages(huge_pages, PAGE_SIZE); - assert_eq!(result, Err(AllocError::NoMemory)); + assert!(matches!(result, Err(AllocError::NoMemory))); dealloc_test_heap(heap_ptr, heap_layout); }