Implement frame recycler

This commit is contained in:
Jeremy Soller
2017-04-14 20:59:27 -06:00
parent 903432f057
commit a9d92df5fa
4 changed files with 149 additions and 5 deletions

View File

@@ -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;

View File

@@ -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
View 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);
}
}
}

View File

@@ -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);
}