use super::{Frame, Segment};
use crate::{
mm::{
page::{self, meta::FrameMeta},
PAGE_SIZE,
},
prelude::*,
Error,
};
pub struct FrameAllocOptions {
nframes: usize,
is_contiguous: bool,
uninit: bool,
}
impl FrameAllocOptions {
pub fn new(nframes: usize) -> Self {
Self {
nframes,
is_contiguous: false,
uninit: false,
}
}
pub fn is_contiguous(&mut self, is_contiguous: bool) -> &mut Self {
self.is_contiguous = is_contiguous;
self
}
pub fn uninit(&mut self, uninit: bool) -> &mut Self {
self.uninit = uninit;
self
}
pub fn alloc(&self) -> Result<Vec<Frame>> {
let pages = if self.is_contiguous {
page::allocator::alloc(self.nframes * PAGE_SIZE, |_| FrameMeta::default())
.ok_or(Error::NoMemory)?
} else {
page::allocator::alloc_contiguous(self.nframes * PAGE_SIZE, |_| FrameMeta::default())
.ok_or(Error::NoMemory)?
.into()
};
let frames: Vec<_> = pages.into_iter().map(|page| Frame { page }).collect();
if !self.uninit {
for frame in frames.iter() {
frame.writer().fill(0);
}
}
Ok(frames)
}
pub fn alloc_single(&self) -> Result<Frame> {
if self.nframes != 1 {
return Err(Error::InvalidArgs);
}
let page = page::allocator::alloc_single(FrameMeta::default()).ok_or(Error::NoMemory)?;
let frame = Frame { page };
if !self.uninit {
frame.writer().fill(0);
}
Ok(frame)
}
pub fn alloc_contiguous(&self) -> Result<Segment> {
if self.nframes == 0 {
return Err(Error::InvalidArgs);
}
let segment: Segment =
page::allocator::alloc_contiguous(self.nframes * PAGE_SIZE, |_| FrameMeta::default())
.ok_or(Error::NoMemory)?
.into();
if !self.uninit {
segment.writer().fill(0);
}
Ok(segment)
}
}
#[cfg(ktest)]
#[ktest]
fn test_alloc_dealloc() {
let single_options = FrameAllocOptions::new(1);
let multi_options = FrameAllocOptions::new(10);
let mut contiguous_options = FrameAllocOptions::new(10);
contiguous_options.is_contiguous(true);
let mut remember_vec = Vec::new();
for _ in 0..10 {
for i in 0..10 {
let single_frame = single_options.alloc_single().unwrap();
if i % 3 == 0 {
remember_vec.push(single_frame);
}
}
let contiguous_segment = contiguous_options.alloc_contiguous().unwrap();
drop(contiguous_segment);
let multi_frames = multi_options.alloc().unwrap();
remember_vec.extend(multi_frames.into_iter());
remember_vec.pop();
}
}