parent
c0d83ef75b
commit
733c102836
@ -0,0 +1,135 @@
|
||||
use alloc::vec_deque::VecDeque;
|
||||
use super::*;
|
||||
|
||||
pub struct EnhancedClockSwapManager<T: 'static + SwappablePageTable> {
|
||||
page_table: &'static mut T,
|
||||
clock_ptr: usize,
|
||||
deque: VecDeque<VirtAddr>,
|
||||
}
|
||||
|
||||
impl<T: 'static + SwappablePageTable> SwapManager for EnhancedClockSwapManager<T> {
|
||||
fn tick(&mut self) {
|
||||
}
|
||||
|
||||
fn push(&mut self, addr: usize) {
|
||||
let pos = if self.clock_ptr == 0 {self.deque.len()} else {self.clock_ptr};
|
||||
self.deque.insert(pos, addr);
|
||||
}
|
||||
|
||||
fn remove(&mut self, addr: usize) {
|
||||
let id = self.deque.iter()
|
||||
.position(|&x| x == addr)
|
||||
.expect("address not found");
|
||||
if id < self.clock_ptr {
|
||||
self.clock_ptr -= 1;
|
||||
}
|
||||
self.deque.remove(id);
|
||||
}
|
||||
|
||||
fn pop(&mut self) -> Option<usize> {
|
||||
loop {
|
||||
let addr = self.deque[self.clock_ptr];
|
||||
let accessed = self.page_table.accessed(addr);
|
||||
let dirty = self.page_table.dirty(addr);
|
||||
|
||||
match (accessed, dirty) {
|
||||
(true, _) => {
|
||||
self.page_table.clear_accessed(addr);
|
||||
|
||||
},
|
||||
(false, true) => {
|
||||
if self.page_table.swap_out(addr).is_ok() {
|
||||
self.page_table.clear_dirty(addr);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return self.remove_current();
|
||||
}
|
||||
}
|
||||
self.move_next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<T: 'static + SwappablePageTable> EnhancedClockSwapManager<T> {
|
||||
pub fn new(page_table: &'static mut T) -> Self {
|
||||
EnhancedClockSwapManager {
|
||||
page_table,
|
||||
clock_ptr: 0,
|
||||
deque: VecDeque::<VirtAddr>::new()
|
||||
}
|
||||
}
|
||||
fn remove_current(&mut self) -> Option<VirtAddr> {
|
||||
let addr = self.deque.remove(self.clock_ptr);
|
||||
if self.clock_ptr == self.deque.len() {
|
||||
self.clock_ptr = 0;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
fn move_next(&mut self) {
|
||||
self.clock_ptr += 1;
|
||||
if self.clock_ptr == self.deque.len() {
|
||||
self.clock_ptr = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use alloc::{arc::Arc, boxed::Box};
|
||||
use core::mem::uninitialized;
|
||||
use core::cell::RefCell;
|
||||
use page_table::mock_page_table::MockPageTable;
|
||||
|
||||
impl SwappablePageTable for MockPageTable {
|
||||
fn swap_out(&mut self, addr: usize) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
enum MemOp {
|
||||
R(usize), W(usize)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use self::MemOp::{R, W};
|
||||
let page_fault_count = Arc::new(RefCell::new(0usize));
|
||||
|
||||
let mut pt = Box::new(MockPageTable::new(4));
|
||||
let static_pt = unsafe{ &mut *(pt.as_mut() as *mut MockPageTable) };
|
||||
pt.set_handler(Box::new({
|
||||
let page_fault_count1 = page_fault_count.clone();
|
||||
let mut clock = EnhancedClockSwapManager::new(static_pt);
|
||||
|
||||
move |pt: &mut MockPageTable, addr: VirtAddr| {
|
||||
*page_fault_count1.borrow_mut() += 1;
|
||||
|
||||
if !pt.map(addr) { // is full?
|
||||
pt.unmap(clock.pop().unwrap());
|
||||
pt.map(addr);
|
||||
}
|
||||
clock.push(addr);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
let op_seq = [
|
||||
R(1), R(2), R(3), R(4),
|
||||
R(3), W(1), R(4), W(2), R(5),
|
||||
R(2), W(1), R(2), R(3), R(4)];
|
||||
let pgfault_count = [
|
||||
1, 2, 3, 4,
|
||||
4, 4, 4, 4, 5,
|
||||
5, 5, 5, 6, 7];
|
||||
for (op, &count) in op_seq.iter().zip(pgfault_count.iter()) {
|
||||
match op {
|
||||
R(addr) => pt.read(*addr),
|
||||
W(addr) => pt.write(*addr),
|
||||
}
|
||||
assert_eq!(*(*page_fault_count).borrow(), count);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue