Make tests safe, by using Arc & RefCell.

master
WangRunji 7 years ago
parent e5e27db4ec
commit c0d83ef75b

@ -1,4 +1,4 @@
use alloc::btree_set::BTreeSet; use alloc::{boxed::Box, btree_set::BTreeSet};
use super::*; use super::*;
pub struct MockPageTable { pub struct MockPageTable {
@ -9,7 +9,7 @@ pub struct MockPageTable {
capacity: usize, capacity: usize,
} }
type PageFaultHandler = fn(&mut MockPageTable, VirtAddr); type PageFaultHandler = Box<FnMut(&mut MockPageTable, VirtAddr)>;
impl PageTable for MockPageTable { impl PageTable for MockPageTable {
fn accessed(&self, addr: VirtAddr) -> bool { fn accessed(&self, addr: VirtAddr) -> bool {
@ -44,7 +44,8 @@ impl MockPageTable {
/// Read memory, mark accessed, trigger page fault if not present /// Read memory, mark accessed, trigger page fault if not present
pub fn read(&mut self, addr: VirtAddr) { pub fn read(&mut self, addr: VirtAddr) {
while !self.mapped_set.contains(&addr) { while !self.mapped_set.contains(&addr) {
(self.page_fault_handler)(self, addr); let self_mut = unsafe{ &mut *(self as *mut Self) };
(self.page_fault_handler)(self_mut, addr);
} }
self.accessed_set.insert(addr); self.accessed_set.insert(addr);
@ -52,7 +53,8 @@ impl MockPageTable {
/// Write memory, mark accessed and dirty, trigger page fault if not present /// Write memory, mark accessed and dirty, trigger page fault if not present
pub fn write(&mut self, addr: VirtAddr) { pub fn write(&mut self, addr: VirtAddr) {
while !self.mapped_set.contains(&addr) { while !self.mapped_set.contains(&addr) {
(self.page_fault_handler)(self, addr); let self_mut = unsafe{ &mut *(self as *mut Self) };
(self.page_fault_handler)(self_mut, addr);
} }
self.accessed_set.insert(addr); self.accessed_set.insert(addr);
self.dirty_set.insert(addr); self.dirty_set.insert(addr);
@ -62,29 +64,29 @@ impl MockPageTable {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use alloc::arc::Arc;
static mut PGFAULT_COUNT: usize = 0; use core::cell::RefCell;
fn assert_pgfault_eq(x: usize) {
assert_eq!(unsafe{ PGFAULT_COUNT }, x);
}
#[test] #[test]
fn test() { fn test() {
fn page_fault_handler(pt: &mut MockPageTable, addr: VirtAddr) { let page_fault_count = Arc::new(RefCell::new(0usize));
unsafe{ PGFAULT_COUNT += 1; }
pt.map(addr); let mut pt = MockPageTable::new(2, Box::new({
} let page_fault_count1 = page_fault_count.clone();
let mut pt = MockPageTable::new(2, page_fault_handler); move |pt: &mut MockPageTable, addr: VirtAddr| {
*page_fault_count1.borrow_mut() += 1;
pt.map(addr);
}
}));
pt.map(0); pt.map(0);
pt.read(0); pt.read(0);
assert_pgfault_eq(0); assert_eq!(*page_fault_count.borrow(), 0);
assert!(pt.accessed(0)); assert!(pt.accessed(0));
assert!(!pt.dirty(0)); assert!(!pt.dirty(0));
pt.write(1); pt.write(1);
assert_pgfault_eq(1); assert_eq!(*page_fault_count.borrow(), 1);
assert!(pt.accessed(1)); assert!(pt.accessed(1));
assert!(pt.dirty(1)); assert!(pt.dirty(1));
@ -92,6 +94,6 @@ mod test {
pt.unmap(0); pt.unmap(0);
pt.read(0); pt.read(0);
assert_pgfault_eq(2); assert_eq!(*page_fault_count.borrow(), 2);
} }
} }

@ -1,19 +1,11 @@
use alloc::vec_deque::VecDeque; use alloc::vec_deque::VecDeque;
use super::*; use super::*;
struct FifoSwapManager<T: 'static + PageTable> { struct FifoSwapManager {
page_table: &'static T,
deque: VecDeque<VirtAddr>, deque: VecDeque<VirtAddr>,
} }
impl<T: 'static + PageTable> SwapManager<T> for FifoSwapManager<T> { impl SwapManager for FifoSwapManager {
fn new(page_table: &'static T) -> Self {
FifoSwapManager {
page_table,
deque: VecDeque::<VirtAddr>::new()
}
}
fn tick(&mut self) { fn tick(&mut self) {
} }
@ -34,44 +26,45 @@ impl<T: 'static + PageTable> SwapManager<T> for FifoSwapManager<T> {
} }
} }
impl FifoSwapManager {
fn new() -> Self {
FifoSwapManager {
deque: VecDeque::<VirtAddr>::new()
}
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use alloc::{arc::Arc, boxed::Box};
use core::cell::RefCell;
use page_table::mock_page_table::MockPageTable; use page_table::mock_page_table::MockPageTable;
enum MemOp { enum MemOp {
R(usize), W(usize) R(usize), W(usize)
} }
fn assert_pgfault_eq(x: usize) {
assert_eq!(unsafe{ PGFAULT_COUNT }, x);
}
// For pgfault_handler:
static mut PGFAULT_COUNT: usize = 0;
static mut PAGE: *mut MockPageTable = 0 as *mut _;
static mut FIFO: *mut FifoSwapManager<MockPageTable> = 0 as *mut _;
fn page_fault_handler(pt: &mut MockPageTable, addr: VirtAddr) {
unsafe{ PGFAULT_COUNT += 1; }
let fifo = unsafe{ &mut *FIFO };
if !pt.map(addr) { // is full?
pt.unmap(fifo.pop().unwrap());
pt.map(addr);
}
fifo.push(addr);
}
#[test] #[test]
fn test() { fn test() {
use self::MemOp::{R, W}; use self::MemOp::{R, W};
let mut pt = MockPageTable::new(4, page_fault_handler); let page_fault_count = Arc::new(RefCell::new(0usize));
let mut fifo = FifoSwapManager::<MockPageTable>::new(
unsafe{ &*(&pt as *const _) }); let mut pt = MockPageTable::new(4, Box::new({
unsafe { let page_fault_count1 = page_fault_count.clone();
PAGE = &mut pt as *mut _; let mut fifo = FifoSwapManager::new();
FIFO = &mut fifo as *mut _;
} move |pt: &mut MockPageTable, addr: VirtAddr| {
*page_fault_count1.borrow_mut() += 1;
if !pt.map(addr) { // is full?
pt.unmap(fifo.pop().unwrap());
pt.map(addr);
}
fifo.push(addr);
}
}));
let op_seq = [ let op_seq = [
R(1), R(2), R(3), R(4), R(1), R(2), R(3), R(4),
W(3), W(1), W(4), W(2), W(5), W(3), W(1), W(4), W(2), W(5),
@ -87,7 +80,7 @@ mod test {
R(addr) => pt.read(*addr), R(addr) => pt.read(*addr),
W(addr) => pt.write(*addr), W(addr) => pt.write(*addr),
} }
assert_pgfault_eq(count); assert_eq!(*(*page_fault_count).borrow(), count);
} }
} }
} }

@ -4,9 +4,7 @@ use super::page_table::PageTable;
pub mod fifo; pub mod fifo;
mod mock_swapper; mod mock_swapper;
trait SwapManager<T: PageTable> { trait SwapManager {
/// Create and initialize for the swap manager
fn new(page_table: &'static T) -> Self;
/// Called when tick interrupt occured /// Called when tick interrupt occured
fn tick(&mut self); fn tick(&mut self);
/// Called when map a swappable page into the memory /// Called when map a swappable page into the memory

Loading…
Cancel
Save