kernel: use rbtree in pmm

This commit is contained in:
janis 2026-08-03 00:31:28 +02:00
parent 9dcc22c7de
commit b069ee78a8
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
3 changed files with 262 additions and 568 deletions

View file

@ -7,6 +7,7 @@
allocator_api, allocator_api,
ptr_cast_slice, ptr_cast_slice,
likely_unlikely, likely_unlikely,
int_roundings,
never_type never_type
)] )]
#![cfg_attr(test, feature(custom_test_frameworks))] #![cfg_attr(test, feature(custom_test_frameworks))]

View file

@ -72,7 +72,7 @@ extern "C" fn _start() -> ! {
let leaf = kernel::x86_64::cpuid::Leaf8000008::get(); let leaf = kernel::x86_64::cpuid::Leaf8000008::get();
serial_println!("max phy: {:#?}", leaf); serial_println!("max phy: {:#?}", leaf);
// kernel::serial_println!("PMM: {pmm:#?}"); kernel::serial_println!("PMM: {pmm:#?}");
let fb = limine_requests::FRAMEBUFFER_REQUEST let fb = limine_requests::FRAMEBUFFER_REQUEST
.framebuffers() .framebuffers()

View file

@ -1,6 +1,9 @@
use core::{alloc::Allocator, fmt::Debug}; use core::{alloc::Allocator, cell::Cell, fmt::Debug, num::NonZeroUsize, ptr::NonNull};
use crate::{memory::page_tree::PageTree, serial_println, sync::OnceLock, x86_64::PAGE_SIZE}; use bit_field::BitField;
use rbtree::RBTree;
use crate::{serial_println, sync::OnceLock, x86_64::PAGE_SIZE};
pub static HHDM_BASE: OnceLock<u64> = OnceLock::new(); pub static HHDM_BASE: OnceLock<u64> = OnceLock::new();
@ -12,6 +15,12 @@ pub trait VirtAddrTranslationExt {
pub struct PhyAddr(pub u64); pub struct PhyAddr(pub u64);
impl PhyAddr { impl PhyAddr {
pub fn from_hhdm_virt(virt: impl Into<VirtAddr>) -> Option<Self> {
let hhdm_base = unsafe { *HHDM_BASE.get_unchecked() };
virt.into().0.checked_sub(hhdm_base).map(PhyAddr)
}
pub fn into_hhdm_virt(&self) -> VirtAddr { pub fn into_hhdm_virt(&self) -> VirtAddr {
VirtAddr(self.0 + unsafe { crate::memory::HHDM_BASE.get().unwrap_unchecked() }) VirtAddr(self.0 + unsafe { crate::memory::HHDM_BASE.get().unwrap_unchecked() })
} }
@ -21,6 +30,10 @@ impl PhyAddr {
pub fn byte_add(&self, offset: usize) -> PhyAddr { pub fn byte_add(&self, offset: usize) -> PhyAddr {
PhyAddr(self.0 + offset as u64) PhyAddr(self.0 + offset as u64)
} }
pub fn page_index(&self) -> u64 {
self.0.div_floor(PAGE_SIZE as u64)
}
} }
impl Debug for PhyAddr { impl Debug for PhyAddr {
@ -29,6 +42,36 @@ impl Debug for PhyAddr {
} }
} }
impl<T> From<&T> for VirtAddr {
fn from(ptr: &T) -> Self {
VirtAddr(ptr as *const T as u64)
}
}
impl<T> From<&mut T> for VirtAddr {
fn from(ptr: &mut T) -> Self {
VirtAddr(ptr as *mut T as u64)
}
}
impl<T> From<*const T> for VirtAddr {
fn from(ptr: *const T) -> Self {
VirtAddr(ptr as u64)
}
}
impl<T> From<*mut T> for VirtAddr {
fn from(ptr: *mut T) -> Self {
VirtAddr(ptr as u64)
}
}
impl<T> From<NonNull<T>> for VirtAddr {
fn from(ptr: NonNull<T>) -> Self {
VirtAddr(ptr.as_ptr() as u64)
}
}
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
pub struct VirtAddr(pub u64); pub struct VirtAddr(pub u64);
@ -69,7 +112,35 @@ pub struct PhysicalMemoryManager {
} }
pub struct PhysicalMemoryAllocator { pub struct PhysicalMemoryAllocator {
tree: PageTree, tree: RBTree<PhysicalPageNode>,
}
#[repr(C)]
#[derive(Debug)]
struct PageHeader {
node: PhysicalPageNode,
count: u64,
}
impl PageHeader {
fn phy(&self) -> Option<PhyAddr> {
PhyAddr::from_hhdm_virt(self)
}
fn new_from_page_idx_and_count(page_idx: usize, count: usize) -> NonNull<Self> {
let phy = PhyAddr(page_idx as u64 * PAGE_SIZE as u64);
let virt = phy.into_hhdm_virt();
let ptr = virt.as_mut::<Self>();
unsafe {
ptr.write(PageHeader {
node: PhysicalPageNode::new_red(),
count: count as u64,
});
}
NonNull::new(ptr).unwrap()
}
} }
impl Debug for PhysicalMemoryAllocator { impl Debug for PhysicalMemoryAllocator {
@ -78,8 +149,17 @@ impl Debug for PhysicalMemoryAllocator {
.field_with("tree", |f| { .field_with("tree", |f| {
let iter = self.tree.iter(); let iter = self.tree.iter();
write!(f, "[")?; write!(f, "[")?;
for info in iter { for key in iter {
writeln!(f, "({:?}..{:?}), ", info.phy, info.end())?; let header = unsafe { (&raw const *key).cast::<PageHeader>().read_volatile() };
if let Some(phy) = header.phy() {
writeln!(
f,
"({:?}..{:?}), ",
phy,
phy.page_add(header.count as usize)
)?;
}
} }
write!(f, "]") write!(f, "]")
}) })
@ -94,7 +174,7 @@ impl PhysicalMemoryAllocator {
.filter(|region| region.region_type.is_usable()); .filter(|region| region.region_type.is_usable());
let mut pmm = PhysicalMemoryAllocator { let mut pmm = PhysicalMemoryAllocator {
tree: PageTree::from_root(usize::MAX), tree: RBTree::new(),
}; };
usable_regions.for_each(|region| { usable_regions.for_each(|region| {
@ -113,7 +193,16 @@ impl PhysicalMemoryAllocator {
page_index, page_index,
count count
); );
self.tree.free_region(page_index, count);
let node_ptr =
PageHeader::new_from_page_idx_and_count(page_index, count).cast::<PhysicalPageNode>();
let None = self.tree.insert_node(node_ptr) else {
panic!(
"Failed to insert node for page_index = {}, count = {}",
page_index, count
);
};
} }
} }
@ -129,17 +218,14 @@ unsafe impl Allocator for PanicingAllocator {
fn allocate( fn allocate(
&self, &self,
layout: core::alloc::Layout, layout: core::alloc::Layout,
) -> Result<core::ptr::NonNull<[u8]>, core::alloc::AllocError> { ) -> Result<NonNull<[u8]>, core::alloc::AllocError> {
match layout.size() { match layout.size() {
0 => Ok(core::ptr::NonNull::slice_from_raw_parts( 0 => Ok(NonNull::slice_from_raw_parts(NonNull::dangling(), 0)),
core::ptr::NonNull::dangling(),
0,
)),
_ => panic!("PanicingAllocator cannot allocate memory"), _ => panic!("PanicingAllocator cannot allocate memory"),
} }
} }
unsafe fn deallocate(&self, _ptr: core::ptr::NonNull<u8>, _layout: core::alloc::Layout) {} unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: core::alloc::Layout) {}
} }
pub mod bump { pub mod bump {
@ -559,7 +645,7 @@ pub mod bump {
} }
} }
fn asdf(bump: &mut Bump<super::PanicingAllocator>) { fn _asdf(bump: &mut Bump<super::PanicingAllocator>) {
let mut bump = bump.as_scope(); let mut bump = bump.as_scope();
let x = bump.alloc_with(|| 3u64); let x = bump.alloc_with(|| 3u64);
bump.scope(|bump| { bump.scope(|bump| {
@ -571,558 +657,165 @@ pub mod bump {
} }
} }
mod page_tree { /// A node for a red-black tree of free physical page chunks.
use bit_field::BitField; ///
/// On amd64 platforms, the maximum physical address is 52 bits, the lower
use crate::{ /// 12 of which are zero for page aligned addresses.
memory::{PAGE_SIZE, PhyAddr}, /// Our Tree Node entry needs to store 3 page indices (parent, left, right) and a color bit.
serial_println, struct PhysicalPageNode(Cell<u128>);
};
impl Debug for PhysicalPageNode {
use core::ops::{Index, IndexMut}; fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use rbtree::UnsafeNode;
pub enum SearchResult<T> {
Found(T), f.debug_struct("PhysicalPageNode")
NotFound(T), .field("parent", &self.parent())
} .field("left", &self.left())
.field("right", &self.right())
/// On amd64 platforms, the maximum physical address is 52 bits, the lower .field("color", &self.color())
/// 12 of which are zero for page aligned addresses. .finish()
/// Our Tree Node entry needs to store 3 page indices (left, right, parent) and a color bit. }
struct CompactPage(u128); }
impl CompactPage { impl PhysicalPageNode {
fn parent(&self) -> usize { fn new_red() -> Self {
self.0.get_bits(0..40) as usize PhysicalPageNode(Cell::new(1 << 120))
} }
fn set_parent(&mut self, parent: usize) {
self.0.set_bits(0..40, parent as u128); fn bits(&self) -> u128 {
} self.0.get()
}
fn left_child(&self) -> usize {
self.0.get_bits(40..80) as usize fn parent_bits(&self) -> u64 {
} self.bits().get_bits(0..40) as u64
fn set_left_child(&mut self, left: usize) { }
self.0.set_bits(40..80, left as u128);
} fn set_parent_bits(&self, parent: u64) {
self.0.update(|mut bits| {
fn right_child(&self) -> usize { bits.set_bits(0..40, parent as u128);
self.0.get_bits(80..120) as usize bits
} });
fn set_right_child(&mut self, right: usize) { }
self.0.set_bits(80..120, right as u128);
} fn left_bits(&self) -> u64 {
self.bits().get_bits(40..80) as u64
fn color(&self) -> bool { }
self.0.get_bit(120)
} fn set_left_bits(&self, left: u64) {
fn set_color(&mut self, color: bool) { self.0.update(|mut bits| {
self.0.set_bit(120, color); bits.set_bits(40..80, left as u128);
} bits
});
fn data(&self) -> u8 { }
self.0.get_bits(121..128) as u8
} fn right_bits(&self) -> u64 {
fn set_data(&mut self, data: u8) { self.bits().get_bits(80..120) as u64
self.0.set_bits(121..128, data as u128); }
}
} fn set_right_bits(&self, right: u64) {
self.0.update(|mut bits| {
struct Page { bits.set_bits(80..120, right as u128);
left_idx: usize, bits
right_idx: usize, });
parent: usize, }
count: isize,
} fn color_bit(&self) -> bool {
self.bits().get_bit(120)
impl Page { }
fn new_red(_idx: usize, count: usize) -> Self {
Self { fn set_color_bit(&self, color: bool) {
left_idx: usize::MAX, self.0.update(|mut bits| {
right_idx: usize::MAX, bits.set_bit(120, color);
parent: usize::MAX, bits
count: -(count as isize), });
} }
} }
fn child(&self, left: bool) -> usize {
if left { self.left_idx } else { self.right_idx } /// A key for a red-black tree of free physical page chunks.
} /// The key uses the address of the node as the key, which is unique and means
fn red(&self) -> bool { /// the key does not require any additional bits.
self.count.is_negative() struct PhysicalPageNodeKey;
}
fn set_color(&mut self, red: bool) { impl Eq for PhysicalPageNodeKey {}
if red {
self.count = -(self.count.unsigned_abs() as isize); impl PartialEq for PhysicalPageNodeKey {
} else { fn eq(&self, _other: &Self) -> bool {
self.count = self.count.unsigned_abs() as isize; core::ptr::eq(self, _other)
} }
} }
fn count(&self) -> usize {
self.count.unsigned_abs() impl PartialOrd for PhysicalPageNodeKey {
} fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
fn set_count(&mut self, count: usize) { Some(self.cmp(other))
let red = self.red(); }
self.count = if red { }
-(count as isize)
} else { impl Ord for PhysicalPageNodeKey {
count as isize fn cmp(&self, other: &Self) -> core::cmp::Ordering {
}; (&raw const *self).cmp(&(&raw const *other))
} }
} }
#[repr(transparent)] unsafe impl rbtree::UnsafeNode for PhysicalPageNode {
pub struct PageTree { type Key = PhysicalPageNodeKey;
root: usize,
pages: Pages, fn left(&self) -> Option<NonNull<Self>> {
} NonZeroUsize::new((self.left_bits() << 12) as usize).map(NonNull::with_exposed_provenance)
}
struct Pages;
fn right(&self) -> Option<NonNull<Self>> {
impl Pages { NonZeroUsize::new((self.right_bits() << 12) as usize).map(NonNull::with_exposed_provenance)
fn get_disjoint_mut<const N: usize>(&mut self, indices: [usize; N]) -> [&mut Page; N] { }
indices.map(|idx| unsafe {
PhyAddr(idx as u64 * PAGE_SIZE as u64) fn parent(&self) -> Option<NonNull<Self>> {
.into_hhdm_virt() NonZeroUsize::new((self.parent_bits() << 12) as usize).map(NonNull::with_exposed_provenance)
.as_mut::<Page>() }
.as_mut_unchecked()
}) fn key(&self) -> &Self::Key {
} assert_eq!(
core::mem::size_of::<Self::Key>(),
fn get_ptr(&self, idx: usize) -> *const Page { 0,
PhyAddr(idx as u64 * PAGE_SIZE as u64) "PhysicalPageNodeKey must be zero-sized"
.into_hhdm_virt() );
.as_ptr::<Page>()
} // SAFETY: The key is a zero-sized type, so we can transmute the
// reference to the node to a reference to the key.
fn get_mut(&mut self, idx: usize) -> &mut Page { unsafe { core::mem::transmute_copy::<&PhysicalPageNode, &PhysicalPageNodeKey>(&self) }
unsafe { }
PhyAddr(idx as u64 * PAGE_SIZE as u64)
.into_hhdm_virt() fn color(&self) -> rbtree::Color {
.as_mut::<Page>() if self.color_bit() {
.as_mut_unchecked() rbtree::Color::Red
} } else {
} rbtree::Color::Black
} }
}
impl Index<usize> for Pages {
type Output = Page; fn set_left(&self, left: Option<NonNull<Self>>) {
fn index(&self, idx: usize) -> &Self::Output { self.set_left_bits(left.map_or(0, |ptr| {
unsafe { PhyAddr::from_hhdm_virt(VirtAddr::from(ptr))
PhyAddr(idx as u64 * PAGE_SIZE as u64) .expect("PhysicalPageNode left pointer is not in HHDM")
.into_hhdm_virt() .page_index()
.as_ptr::<Page>() }));
.as_ref_unchecked() }
}
} fn set_right(&self, right: Option<NonNull<Self>>) {
} self.set_right_bits(right.map_or(0, |ptr| {
PhyAddr::from_hhdm_virt(VirtAddr::from(ptr))
impl IndexMut<usize> for Pages { .expect("PhysicalPageNode right pointer is not in HHDM")
fn index_mut(&mut self, idx: usize) -> &mut Self::Output { .page_index()
unsafe { }));
PhyAddr(idx as u64 * PAGE_SIZE as u64) }
.into_hhdm_virt()
.as_mut::<Page>() fn set_parent(&self, parent: Option<NonNull<Self>>) {
.as_mut_unchecked() self.set_parent_bits(parent.map_or(0, |ptr| {
} PhyAddr::from_hhdm_virt(VirtAddr::from(ptr))
} .expect("PhysicalPageNode parentpointer is not in HHDM")
} .page_index()
}));
impl PageTree { }
pub fn from_root(root: usize) -> Self {
Self { root, pages: Pages } fn set_color(&self, color: rbtree::Color) {
} self.set_color_bit(color == rbtree::Color::Red);
pub fn free_region(&mut self, page_index: usize, count: usize) {
let pre = match self.find(page_index) {
SearchResult::Found(_) => panic!("Page index already exists in free list"),
SearchResult::NotFound(Self::INVALID_IDX) => Self::INVALID_IDX,
SearchResult::NotFound(idx) => {
if idx > page_index {
self.next_back_of(idx)
} else {
idx
}
}
};
match pre {
Self::INVALID_IDX => {
self.insert(page_index, count);
}
_ => {
if self.pages[pre].count() + pre == page_index {
serial_println!(
"Found previous page: pre = {}, pre_count = {}",
pre,
self.pages[pre].count()
);
let new_count = self.pages[pre].count() + count;
self.pages[pre].set_count(new_count);
} else {
self.insert(page_index, count);
}
}
}
}
// rb-tree impl
const INVALID_IDX: usize = usize::MAX;
fn rotate(&mut self, x: usize, left: bool) {
let (y, b, x_hole, y_hole) = if left {
let y = self.pages[x].right_idx;
let b = self.pages[y].left_idx;
let [x_page, y_page] = self.pages.get_disjoint_mut([x, y]);
let x_hole = &mut x_page.right_idx;
let y_hole = &mut y_page.left_idx;
(y, b, x_hole, y_hole)
} else {
let y = self.pages[x].left_idx;
let b = self.pages[y].right_idx;
let [x_page, y_page] = self.pages.get_disjoint_mut([x, y]);
let x_hole = &mut x_page.left_idx;
let y_hole = &mut y_page.right_idx;
(y, b, x_hole, y_hole)
};
*x_hole = b;
*y_hole = x;
if b != usize::MAX {
self.pages[b].parent = x;
}
let x_parent = self.pages[x].parent;
self.pages[y].parent = x_parent;
if self.pages[x].parent == usize::MAX {
self.root = y;
} else if x == self.pages[x_parent].left_idx {
self.pages[x_parent].left_idx = y;
} else {
self.pages[x_parent].right_idx = y;
}
self.pages[x].parent = y;
}
pub fn find(&self, idx: usize) -> SearchResult<usize> {
let mut node = self.root;
let mut parent = usize::MAX;
while node != usize::MAX {
parent = node;
if idx < node {
node = self.pages[node].left_idx;
} else if idx > node {
node = self.pages[node].right_idx;
} else {
return SearchResult::Found(node);
}
}
SearchResult::NotFound(parent)
}
pub fn insert(&mut self, idx: usize, count: usize) {
let SearchResult::NotFound(parent) = self.find(idx) else {
panic!("Page index already exists in free list");
};
let page = &mut self.pages[idx];
*page = Page::new_red(idx, count);
page.parent = parent;
if parent == usize::MAX {
self.root = idx;
} else if idx < parent {
self.set_left_child_of(parent, idx);
} else {
self.set_right_child_of(parent, idx);
}
self.fixup_insert(idx);
}
fn fixup_insert(&mut self, mut idx: usize) {
// idx is red; fixup the tree while the parent is red
loop {
let parent = self.parent_of(idx);
if parent == usize::MAX || !self.color_of(parent) {
break;
}
// gp is guaranteed to exist because the parent is red and the root is black
let gp = self.pages[parent].parent;
let (uncle, uncle_left) = if parent == self.pages[gp].left_idx {
(self.pages[gp].right_idx, false)
} else {
(self.pages[gp].left_idx, true)
};
if self.color_of(uncle) {
self.pages[parent].set_color(false);
self.pages[uncle].set_color(false);
self.pages[gp].set_color(true);
idx = gp;
} else {
// uncle is black
if idx == self.pages[parent].child(uncle_left) {
// idx is on the same side as uncle
self.rotate(parent, !uncle_left);
idx = parent;
}
self.pages[parent].set_color(false);
self.pages[gp].set_color(true);
self.rotate(gp, uncle_left);
}
}
self.pages[self.root].set_color(false);
}
/// replaces the node at `at_idx` with the node at `with_idx`.
fn replace(&mut self, at_idx: usize, with_idx: usize) {
let at_parent = self.parent_of(at_idx);
match at_parent {
Self::INVALID_IDX => {}
_ if at_idx == self.left_child_of(at_parent) => {
self.set_left_child_of(at_parent, with_idx);
}
_ => {
self.set_right_child_of(at_parent, with_idx);
}
}
if let Self::INVALID_IDX = with_idx {
} else {
self.set_parent_of(with_idx, at_parent);
}
}
/// returns the next node in the tree after `idx`, or usize::MAX if there is no next node.
fn minimum_of(&self, mut idx: usize) -> usize {
loop {
let next = self.left_child_of(idx);
if next == usize::MAX {
break;
}
idx = next;
}
idx
}
fn maximum_of(&self, mut idx: usize) -> usize {
loop {
let next = self.right_child_of(idx);
if next == usize::MAX {
break;
}
idx = next;
}
idx
}
fn next_back_of(&self, mut idx: usize) -> usize {
match self.left_child_of(idx) {
Self::INVALID_IDX => {
let mut p = self.parent_of(idx);
while p != Self::INVALID_IDX && idx == self.left_child_of(p) {
idx = p;
p = self.parent_of(idx);
}
p
}
left => self.maximum_of(left),
}
}
fn next_of(&self, mut idx: usize) -> usize {
match self.right_child_of(idx) {
Self::INVALID_IDX => {
let mut p = self.parent_of(idx);
while p != Self::INVALID_IDX && idx == self.right_child_of(p) {
idx = p;
p = self.parent_of(idx);
}
p
}
right => self.minimum_of(right),
}
}
fn left_child_of(&self, idx: usize) -> usize {
self.pages[idx].left_idx
}
fn right_child_of(&self, idx: usize) -> usize {
self.pages[idx].right_idx
}
fn child_of(&self, idx: usize, left: bool) -> usize {
if left {
self.pages[idx].left_idx
} else {
self.pages[idx].right_idx
}
}
fn children_of(&self, idx: usize) -> (usize, usize) {
(self.pages[idx].left_idx, self.pages[idx].right_idx)
}
fn parent_of(&self, idx: usize) -> usize {
self.pages[idx].parent
}
fn set_parent_of(&mut self, idx: usize, parent: usize) {
if idx != Self::INVALID_IDX {
self.pages[idx].parent = parent;
}
}
fn set_color_of(&mut self, idx: usize, red: bool) {
self.pages[idx].set_color(red);
}
fn color_of(&self, idx: usize) -> bool {
// leaves are implicitly black
idx != Self::INVALID_IDX && self.pages[idx].red()
}
fn set_left_child_of(&mut self, idx: usize, left: usize) {
self.pages[idx].left_idx = left;
}
fn set_right_child_of(&mut self, idx: usize, right: usize) {
self.pages[idx].right_idx = right;
}
pub fn remove(&mut self, z: usize) {
let y = match self.children_of(z) {
(Self::INVALID_IDX, _) | (_, Self::INVALID_IDX) => z,
_ => self.next_of(z),
};
let x = match self.left_child_of(y) {
Self::INVALID_IDX => self.right_child_of(y),
_ => self.left_child_of(y),
};
let p_y = self.parent_of(y);
self.set_parent_of(x, p_y);
match p_y {
Self::INVALID_IDX => {
self.root = x;
}
_ if y == self.left_child_of(p_y) => {
self.set_left_child_of(p_y, x);
}
_ => {
self.set_right_child_of(p_y, x);
}
}
let color = self.color_of(y);
if y != z {
self.replace(z, y);
}
if !color {
self.fixup_remove(x);
}
}
fn fixup_remove(&mut self, mut x: usize) {
loop {
if x == self.root || self.color_of(x) {
break;
}
let p_x = self.parent_of(x);
let (mut w, w_left) = if x == self.left_child_of(p_x) {
(self.right_child_of(p_x), false)
} else {
(self.left_child_of(p_x), true)
};
if self.color_of(w) {
self.set_color_of(w, false);
self.set_color_of(p_x, true);
self.rotate(p_x, !w_left);
w = self.child_of(p_x, w_left);
}
// w is now black
match (
self.color_of(self.left_child_of(w)),
self.color_of(self.right_child_of(w)),
) {
(false, false) => {
self.set_color_of(w, true);
x = p_x;
continue;
}
(left @ true, false) | (left @ false, true) => {
if left != w_left {
self.set_color_of(self.child_of(w, left), false);
self.set_color_of(w, true);
self.rotate(w, w_left);
}
self.set_color_of(w, self.color_of(p_x));
self.set_color_of(p_x, false);
self.set_color_of(self.child_of(w, w_left), false);
self.rotate(p_x, !w_left);
x = self.root;
}
(true, true) => {
x = self.root;
}
}
}
}
pub fn iter(&self) -> PageTreeIter<'_> {
PageTreeIter {
tree: self,
next: self.minimum_of(self.root),
}
}
}
pub struct PageTreeIter<'a> {
tree: &'a PageTree,
next: usize,
}
pub struct PageInfo {
pub phy: PhyAddr,
pub count: usize,
}
impl PageInfo {
pub fn end(&self) -> PhyAddr {
self.phy.page_add(self.count)
}
}
impl<'a> Iterator for PageTreeIter<'a> {
type Item = PageInfo;
fn next(&mut self) -> Option<Self::Item> {
if self.next == usize::MAX {
return None;
}
let page_info = PageInfo {
phy: PhyAddr(self.next as u64 * PAGE_SIZE as u64),
count: self.tree.pages[self.next].count(),
};
self.next = self.tree.next_of(self.next);
Some(page_info)
}
} }
} }