Skip to content

Commit 8412048

Browse files
authored
Simplify page allocator interface with AllocationRequest enum (theseus-os#974)
* A page allocation request can choose one of 3 conditions: 1. Allocate N pages at any address, anywhere. 2. Allocate N pages within a specified range of addresses. 3. Allocate N pages starting at a specific address.
1 parent e2806aa commit 8412048

File tree

2 files changed

+38
-23
lines changed

2 files changed

+38
-23
lines changed

kernel/multiple_heaps/src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,10 @@ fn create_heap_mapping(
126126
size_in_bytes: usize
127127
) -> Result<(MappedPages, DeferredAllocAction<'static>), &'static str> {
128128
let kernel_mmi_ref = get_kernel_mmi_ref().ok_or("create_heap_mapping(): KERNEL_MMI was not yet initialized!")?;
129-
let (pages, action) = allocate_pages_by_bytes_deferred(Some(starting_address), size_in_bytes)
130-
.map_err(|_e| "create_heap_mapping(): failed to allocate pages at the starting address")?;
129+
let (pages, action) = allocate_pages_by_bytes_deferred(
130+
page_allocator::AllocationRequest::AtVirtualAddress(starting_address),
131+
size_in_bytes,
132+
).map_err(|_e| "create_heap_mapping(): failed to allocate pages at the starting address")?;
131133
if pages.start_address().value() % HEAP_MAPPED_PAGES_SIZE_IN_BYTES != 0 {
132134
return Err("multiple_heaps: the allocated pages for the heap wasn't properly aligned");
133135
}

kernel/page_allocator/src/lib.rs

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,16 @@ fn adjust_chosen_chunk(
649649
}
650650

651651

652+
/// Possible options when requested pages from the page allocator.
653+
pub enum AllocationRequest<'r> {
654+
/// The allocated pages can be located at any virtual address.
655+
Any,
656+
/// The allocated pages must start exactly at the given `VirtualAddress`.
657+
AtVirtualAddress(VirtualAddress),
658+
/// The allocated pages can be located anywhere within the given range.
659+
WithinRange(&'r PageRange),
660+
}
661+
652662
/// The core page allocation routine that allocates the given number of virtual pages,
653663
/// optionally at the requested starting `VirtualAddress`.
654664
///
@@ -660,9 +670,8 @@ fn adjust_chosen_chunk(
660670
/// Fragmentation isn't cleaned up until we're out of address space, but that's not really a big deal.
661671
///
662672
/// # Arguments
663-
/// * `requested_vaddr`: if `Some`, the returned `AllocatedPages` will start at the `Page`
664-
/// containing this `VirtualAddress`.
665-
/// If `None`, the first available `Page` range will be used, starting at any random virtual address.
673+
/// * `request`: whether to allocate `num_pages` pages at any address,
674+
/// at a specific virtual address, or withing a specified range.
666675
/// * `num_pages`: the number of `Page`s to be allocated.
667676
///
668677
/// # Return
@@ -672,9 +681,8 @@ fn adjust_chosen_chunk(
672681
/// Those actions are deferred until this returned `DeferredAllocAction` struct object is dropped,
673682
/// allowing the caller (such as the heap implementation itself) to control when heap allocation may occur.
674683
pub fn allocate_pages_deferred(
675-
requested_vaddr: Option<VirtualAddress>,
684+
request: AllocationRequest,
676685
num_pages: usize,
677-
within_range: Option<&PageRange>,
678686
) -> Result<(AllocatedPages, DeferredAllocAction<'static>), &'static str> {
679687
if num_pages == 0 {
680688
warn!("PageAllocator: requested an allocation of 0 pages... stupid!");
@@ -688,12 +696,18 @@ pub fn allocate_pages_deferred(
688696
// - Can fit the requested size (starting at the requested address) within the chunk.
689697
// - The chunk can only be within in a designated region if a specific address was requested,
690698
// or all other non-designated chunks are already in use.
691-
if let Some(vaddr) = requested_vaddr {
692-
find_specific_chunk(&mut locked_list, Page::containing_address(vaddr), num_pages)
693-
} else {
694-
find_any_chunk(&mut locked_list, num_pages, within_range)
695-
}
696-
.map_err(From::from) // convert from AllocationError to &str
699+
let res = match request {
700+
AllocationRequest::AtVirtualAddress(vaddr) => {
701+
find_specific_chunk(&mut locked_list, Page::containing_address(vaddr), num_pages)
702+
}
703+
AllocationRequest::Any => {
704+
find_any_chunk(&mut locked_list, num_pages, None)
705+
}
706+
AllocationRequest::WithinRange(range) => {
707+
find_any_chunk(&mut locked_list, num_pages, Some(range))
708+
}
709+
};
710+
res.map_err(From::from) // convert from AllocationError to &str
697711
}
698712

699713

@@ -702,24 +716,24 @@ pub fn allocate_pages_deferred(
702716
///
703717
/// This function still allocates whole pages by rounding up the number of bytes.
704718
pub fn allocate_pages_by_bytes_deferred(
705-
requested_vaddr: Option<VirtualAddress>,
719+
request: AllocationRequest,
706720
num_bytes: usize,
707721
) -> Result<(AllocatedPages, DeferredAllocAction<'static>), &'static str> {
708-
let actual_num_bytes = if let Some(vaddr) = requested_vaddr {
722+
let actual_num_bytes = if let AllocationRequest::AtVirtualAddress(vaddr) = request {
709723
num_bytes + (vaddr.value() % PAGE_SIZE)
710724
} else {
711725
num_bytes
712726
};
713727
let num_pages = (actual_num_bytes + PAGE_SIZE - 1) / PAGE_SIZE; // round up
714-
allocate_pages_deferred(requested_vaddr, num_pages, None)
728+
allocate_pages_deferred(request, num_pages)
715729
}
716730

717731

718732
/// Allocates the given number of pages with no constraints on the starting virtual address.
719733
///
720734
/// See [`allocate_pages_deferred()`](fn.allocate_pages_deferred.html) for more details.
721735
pub fn allocate_pages(num_pages: usize) -> Option<AllocatedPages> {
722-
allocate_pages_deferred(None, num_pages, None)
736+
allocate_pages_deferred(AllocationRequest::Any, num_pages)
723737
.map(|(ap, _action)| ap)
724738
.ok()
725739
}
@@ -731,7 +745,7 @@ pub fn allocate_pages(num_pages: usize) -> Option<AllocatedPages> {
731745
/// This function still allocates whole pages by rounding up the number of bytes.
732746
/// See [`allocate_pages_deferred()`](fn.allocate_pages_deferred.html) for more details.
733747
pub fn allocate_pages_by_bytes(num_bytes: usize) -> Option<AllocatedPages> {
734-
allocate_pages_by_bytes_deferred(None, num_bytes)
748+
allocate_pages_by_bytes_deferred(AllocationRequest::Any, num_bytes)
735749
.map(|(ap, _action)| ap)
736750
.ok()
737751
}
@@ -742,7 +756,7 @@ pub fn allocate_pages_by_bytes(num_bytes: usize) -> Option<AllocatedPages> {
742756
/// This function still allocates whole pages by rounding up the number of bytes.
743757
/// See [`allocate_pages_deferred()`](fn.allocate_pages_deferred.html) for more details.
744758
pub fn allocate_pages_by_bytes_at(vaddr: VirtualAddress, num_bytes: usize) -> Result<AllocatedPages, &'static str> {
745-
allocate_pages_by_bytes_deferred(Some(vaddr), num_bytes)
759+
allocate_pages_by_bytes_deferred(AllocationRequest::AtVirtualAddress(vaddr), num_bytes)
746760
.map(|(ap, _action)| ap)
747761
}
748762

@@ -751,7 +765,7 @@ pub fn allocate_pages_by_bytes_at(vaddr: VirtualAddress, num_bytes: usize) -> Re
751765
///
752766
/// See [`allocate_pages_deferred()`](fn.allocate_pages_deferred.html) for more details.
753767
pub fn allocate_pages_at(vaddr: VirtualAddress, num_pages: usize) -> Result<AllocatedPages, &'static str> {
754-
allocate_pages_deferred(Some(vaddr), num_pages, None)
768+
allocate_pages_deferred(AllocationRequest::AtVirtualAddress(vaddr), num_pages)
755769
.map(|(ap, _action)| ap)
756770
}
757771

@@ -762,7 +776,7 @@ pub fn allocate_pages_in_range(
762776
num_pages: usize,
763777
range: &PageRange,
764778
) -> Result<AllocatedPages, &'static str> {
765-
allocate_pages_deferred(None, num_pages, Some(range))
779+
allocate_pages_deferred(AllocationRequest::WithinRange(range), num_pages)
766780
.map(|(ap, _action)| ap)
767781
}
768782

@@ -773,8 +787,7 @@ pub fn allocate_pages_by_bytes_in_range(
773787
num_bytes: usize,
774788
range: &PageRange,
775789
) -> Result<AllocatedPages, &'static str> {
776-
let num_pages = (num_bytes + PAGE_SIZE - 1) / PAGE_SIZE; // round up
777-
allocate_pages_deferred(None, num_pages, Some(range))
790+
allocate_pages_by_bytes_deferred(AllocationRequest::WithinRange(range), num_bytes)
778791
.map(|(ap, _action)| ap)
779792
}
780793

0 commit comments

Comments
 (0)