Implement frame recycler
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
//! # Area frame allocator
|
||||
//! # Bump frame allocator
|
||||
//! Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/allocating-frames.html)
|
||||
|
||||
use paging::PhysicalAddress;
|
||||
@@ -15,8 +15,8 @@ pub struct BumpAllocator {
|
||||
}
|
||||
|
||||
impl BumpAllocator {
|
||||
pub fn new(kernel_start: usize, kernel_end: usize, memory_areas: MemoryAreaIter) -> BumpAllocator {
|
||||
let mut allocator = BumpAllocator {
|
||||
pub fn new(kernel_start: usize, kernel_end: usize, memory_areas: MemoryAreaIter) -> Self {
|
||||
let mut allocator = Self {
|
||||
next_free_frame: Frame::containing_address(PhysicalAddress::new(0)),
|
||||
current_area: None,
|
||||
areas: memory_areas,
|
||||
@@ -43,6 +43,8 @@ impl BumpAllocator {
|
||||
}
|
||||
|
||||
impl FrameAllocator for BumpAllocator {
|
||||
fn set_noncore(&mut self, noncore: bool) {}
|
||||
|
||||
fn free_frames(&self) -> usize {
|
||||
let mut count = 0;
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
pub use paging::{PAGE_SIZE, PhysicalAddress};
|
||||
|
||||
use self::bump::BumpAllocator;
|
||||
use self::recycle::RecycleAllocator;
|
||||
|
||||
use spin::Mutex;
|
||||
|
||||
pub mod bump;
|
||||
pub mod recycle;
|
||||
|
||||
/// The current memory map. It's size is maxed out to 512 entries, due to it being
|
||||
/// from 0x500 to 0x5000 (800 is the absolute total)
|
||||
@@ -64,7 +66,7 @@ impl Iterator for MemoryAreaIter {
|
||||
}
|
||||
}
|
||||
|
||||
static ALLOCATOR: Mutex<Option<BumpAllocator>> = Mutex::new(None);
|
||||
static ALLOCATOR: Mutex<Option<RecycleAllocator<BumpAllocator>>> = Mutex::new(None);
|
||||
|
||||
/// Init memory module
|
||||
/// Must be called once, and only once,
|
||||
@@ -77,7 +79,17 @@ pub unsafe fn init(kernel_start: usize, kernel_end: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
*ALLOCATOR.lock() = Some(BumpAllocator::new(kernel_start, kernel_end, MemoryAreaIter::new(MEMORY_AREA_FREE)));
|
||||
*ALLOCATOR.lock() = Some(RecycleAllocator::new(BumpAllocator::new(kernel_start, kernel_end, MemoryAreaIter::new(MEMORY_AREA_FREE))));
|
||||
}
|
||||
|
||||
/// Init memory module after core
|
||||
/// Must be called once, and only once,
|
||||
pub unsafe fn init_noncore() {
|
||||
if let Some(ref mut allocator) = *ALLOCATOR.lock() {
|
||||
allocator.set_noncore(true)
|
||||
} else {
|
||||
panic!("frame allocator not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of frames available
|
||||
@@ -172,6 +184,7 @@ impl Iterator for FrameIter {
|
||||
}
|
||||
|
||||
pub trait FrameAllocator {
|
||||
fn set_noncore(&mut self, noncore: bool);
|
||||
fn free_frames(&self) -> usize;
|
||||
fn used_frames(&self) -> usize;
|
||||
fn allocate_frames(&mut self, size: usize) -> Option<Frame>;
|
||||
|
||||
126
src/memory/recycle.rs
Normal file
126
src/memory/recycle.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
//! Recycle allocator
|
||||
//! Uses freed frames if possible, then uses inner allocator
|
||||
|
||||
use collections::Vec;
|
||||
|
||||
use paging::PhysicalAddress;
|
||||
|
||||
use super::{Frame, FrameAllocator, MemoryArea, MemoryAreaIter};
|
||||
|
||||
pub struct RecycleAllocator<T: FrameAllocator> {
|
||||
inner: T,
|
||||
noncore: bool,
|
||||
free: Vec<(usize, usize)>,
|
||||
}
|
||||
|
||||
impl<T: FrameAllocator> RecycleAllocator<T> {
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self {
|
||||
inner: inner,
|
||||
noncore: false,
|
||||
free: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn free_count(&self) -> usize {
|
||||
let mut count = 0;
|
||||
for free in self.free.iter() {
|
||||
count += free.1;
|
||||
}
|
||||
println!("Free count: {} in {} entries", count, self.free.len());
|
||||
count
|
||||
}
|
||||
|
||||
fn merge(&mut self, address: usize, count: usize) -> bool {
|
||||
for i in 0 .. self.free.len() {
|
||||
let changed = {
|
||||
let mut free = &mut self.free[i];
|
||||
if address + count * 4096 == free.0 {
|
||||
free.0 = address;
|
||||
free.1 += count;
|
||||
true
|
||||
} else if free.0 + free.1 * 4096 == address {
|
||||
free.1 += count;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
if changed {
|
||||
//TODO: Use do not use recursion
|
||||
let (address, count) = self.free[i];
|
||||
if self.merge(address, count) {
|
||||
self.free.remove(i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FrameAllocator> FrameAllocator for RecycleAllocator<T> {
|
||||
fn set_noncore(&mut self, noncore: bool) {
|
||||
self.noncore = noncore;
|
||||
}
|
||||
|
||||
fn free_frames(&self) -> usize {
|
||||
self.inner.free_frames() + self.free_count()
|
||||
}
|
||||
|
||||
fn used_frames(&self) -> usize {
|
||||
self.inner.used_frames() - self.free_count()
|
||||
}
|
||||
|
||||
fn allocate_frames(&mut self, count: usize) -> Option<Frame> {
|
||||
if count == 1 {
|
||||
if ! self.free.is_empty() {
|
||||
let mut i = 0;
|
||||
{
|
||||
let mut small = self.free[i];
|
||||
for j in 1..self.free.len() {
|
||||
let free = self.free[j];
|
||||
// Later entries can be removed faster
|
||||
if free.1 <= small.1 {
|
||||
i = j;
|
||||
small = free;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let (address, remove) = {
|
||||
let free = &mut self.free[i];
|
||||
free.1 -= 1;
|
||||
(free.0 + free.1 * 4096, free.1 == 0)
|
||||
};
|
||||
|
||||
if remove {
|
||||
self.free.remove(i);
|
||||
}
|
||||
|
||||
//println!("Restoring frame {:?}, {}", frame, count);
|
||||
Some(Frame::containing_address(PhysicalAddress::new(address)))
|
||||
} else {
|
||||
//println!("No saved frames {}", count);
|
||||
self.inner.allocate_frames(count)
|
||||
}
|
||||
} else {
|
||||
println!("Could not restore frame {}", count);
|
||||
self.inner.allocate_frames(count)
|
||||
}
|
||||
}
|
||||
|
||||
fn deallocate_frames(&mut self, frame: Frame, count: usize) {
|
||||
if self.noncore {
|
||||
let address = frame.start_address().get();
|
||||
if ! self.merge(address, count) {
|
||||
self.free.push((address, count));
|
||||
}
|
||||
} else {
|
||||
println!("Could not save frame {:?}, {}", frame, count);
|
||||
self.inner.deallocate_frames(frame, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,9 @@ pub unsafe extern fn kstart() -> ! {
|
||||
// Initialize all of the non-core devices not otherwise needed to complete initialization
|
||||
device::init_noncore();
|
||||
|
||||
// Initialize memory functions after core has loaded
|
||||
memory::init_noncore();
|
||||
|
||||
BSP_READY.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user