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::*;
pub struct MockPageTable {
@ -9,7 +9,7 @@ pub struct MockPageTable {
capacity: usize,
}
type PageFaultHandler = fn(&mut MockPageTable, VirtAddr);
type PageFaultHandler = Box<FnMut(&mut MockPageTable, VirtAddr)>;
impl PageTable for MockPageTable {
fn accessed(&self, addr: VirtAddr) -> bool {
@ -44,7 +44,8 @@ impl MockPageTable {
/// Read memory, mark accessed, trigger page fault if not present
pub fn read(&mut self, addr: VirtAddr) {
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);
@ -52,7 +53,8 @@ impl MockPageTable {
/// Write memory, mark accessed and dirty, trigger page fault if not present
pub fn write(&mut self, addr: VirtAddr) {
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.dirty_set.insert(addr);
@ -62,29 +64,29 @@ impl MockPageTable {
#[cfg(test)]
mod test {
use super::*;
static mut PGFAULT_COUNT: usize = 0;
fn assert_pgfault_eq(x: usize) {
assert_eq!(unsafe{ PGFAULT_COUNT }, x);
}
use alloc::arc::Arc;
use core::cell::RefCell;
#[test]
fn test() {
fn page_fault_handler(pt: &mut MockPageTable, addr: VirtAddr) {
unsafe{ PGFAULT_COUNT += 1; }
pt.map(addr);
}
let mut pt = MockPageTable::new(2, page_fault_handler);
let page_fault_count = Arc::new(RefCell::new(0usize));
let mut pt = MockPageTable::new(2, Box::new({
let page_fault_count1 = page_fault_count.clone();
move |pt: &mut MockPageTable, addr: VirtAddr| {
*page_fault_count1.borrow_mut() += 1;
pt.map(addr);
}
}));
pt.map(0);
pt.read(0);
assert_pgfault_eq(0);
assert_eq!(*page_fault_count.borrow(), 0);
assert!(pt.accessed(0));
assert!(!pt.dirty(0));
pt.write(1);
assert_pgfault_eq(1);
assert_eq!(*page_fault_count.borrow(), 1);
assert!(pt.accessed(1));
assert!(pt.dirty(1));
@ -92,6 +94,6 @@ mod test {
pt.unmap(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 super::*;
struct FifoSwapManager<T: 'static + PageTable> {
page_table: &'static T,
struct FifoSwapManager {
deque: VecDeque<VirtAddr>,
}
impl<T: 'static + PageTable> SwapManager<T> for FifoSwapManager<T> {
fn new(page_table: &'static T) -> Self {
FifoSwapManager {
page_table,
deque: VecDeque::<VirtAddr>::new()
}
}
impl SwapManager for FifoSwapManager {
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)]
mod test {
use super::*;
use alloc::{arc::Arc, boxed::Box};
use core::cell::RefCell;
use page_table::mock_page_table::MockPageTable;
enum MemOp {
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]
fn test() {
use self::MemOp::{R, W};
let mut pt = MockPageTable::new(4, page_fault_handler);
let mut fifo = FifoSwapManager::<MockPageTable>::new(
unsafe{ &*(&pt as *const _) });
unsafe {
PAGE = &mut pt as *mut _;
FIFO = &mut fifo as *mut _;
}
let page_fault_count = Arc::new(RefCell::new(0usize));
let mut pt = MockPageTable::new(4, Box::new({
let page_fault_count1 = page_fault_count.clone();
let mut fifo = FifoSwapManager::new();
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 = [
R(1), R(2), R(3), R(4),
W(3), W(1), W(4), W(2), W(5),
@ -87,7 +80,7 @@ mod test {
R(addr) => pt.read(*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;
mod mock_swapper;
trait SwapManager<T: PageTable> {
/// Create and initialize for the swap manager
fn new(page_table: &'static T) -> Self;
trait SwapManager {
/// Called when tick interrupt occured
fn tick(&mut self);
/// Called when map a swappable page into the memory

Loading…
Cancel
Save