Improve MockPageTable. Fix tests.

master
WangRunji 7 years ago
parent 733c102836
commit e2e9ead17c

@ -1,10 +1,14 @@
use alloc::{boxed::Box, btree_set::BTreeSet};
use alloc::boxed::Box;
use super::*;
const PAGE_COUNT: usize = 16;
const PAGE_SIZE: usize = 4096;
pub struct MockPageTable {
mapped_set: BTreeSet<VirtAddr>,
accessed_set: BTreeSet<VirtAddr>,
dirty_set: BTreeSet<VirtAddr>,
mapped: [bool; PAGE_COUNT],
accessed: [bool; PAGE_COUNT],
dirty: [bool; PAGE_COUNT],
data: [u8; PAGE_SIZE * PAGE_COUNT],
page_fault_handler: Option<PageFaultHandler>,
capacity: usize,
}
@ -13,36 +17,38 @@ type PageFaultHandler = Box<FnMut(&mut MockPageTable, VirtAddr)>;
impl PageTable for MockPageTable {
fn accessed(&self, addr: VirtAddr) -> bool {
self.accessed_set.contains(&addr)
self.accessed[addr / PAGE_SIZE]
}
fn dirty(&self, addr: VirtAddr) -> bool {
self.dirty_set.contains(&addr)
self.dirty[addr / PAGE_SIZE]
}
fn clear_accessed(&mut self, addr: usize) {
self.accessed_set.remove(&addr);
self.accessed[addr / PAGE_SIZE] = false;
}
fn clear_dirty(&mut self, addr: usize) {
self.dirty_set.remove(&addr);
self.dirty[addr / PAGE_SIZE] = false;
}
/// Map a page, return false if no more space
fn map(&mut self, addr: VirtAddr) -> bool {
if self.mapped_set.len() == self.capacity {
if self.mapped.iter().filter(|&&b| b).count() == self.capacity {
return false;
}
self.mapped_set.insert(addr);
self.mapped[addr / PAGE_SIZE] = true;
true
}
fn unmap(&mut self, addr: VirtAddr) {
self.mapped_set.remove(&addr);
self.mapped[addr / PAGE_SIZE] = false;
}
}
impl MockPageTable {
pub fn new(capacity: usize) -> Self {
use core::mem::uninitialized;
MockPageTable {
mapped_set: BTreeSet::<VirtAddr>::new(),
accessed_set: BTreeSet::<VirtAddr>::new(),
dirty_set: BTreeSet::<VirtAddr>::new(),
mapped: [false; PAGE_COUNT],
accessed: [false; PAGE_COUNT],
dirty: [false; PAGE_COUNT],
data: unsafe{ uninitialized() },
page_fault_handler: None,
capacity,
}
@ -51,22 +57,26 @@ impl MockPageTable {
self.page_fault_handler = Some(page_fault_handler);
}
fn trigger_page_fault_if_not_present(&mut self, addr: VirtAddr) {
while !self.mapped_set.contains(&addr) {
let page_id = addr / PAGE_SIZE;
while !self.mapped[page_id] {
let self_mut = unsafe{ &mut *(self as *mut Self) };
(self.page_fault_handler.as_mut().unwrap())(self_mut, addr);
}
}
/// Read memory, mark accessed, trigger page fault if not present
pub fn read(&mut self, addr: VirtAddr) {
pub fn read(&mut self, addr: VirtAddr) -> u8 {
let page_id = addr / PAGE_SIZE;
self.trigger_page_fault_if_not_present(addr);
self.accessed_set.insert(addr);
self.accessed[page_id] = true;
self.data[addr]
}
/// 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, data: u8) {
let page_id = addr / PAGE_SIZE;
self.trigger_page_fault_if_not_present(addr);
self.accessed_set.insert(addr);
self.dirty_set.insert(addr);
self.accessed[page_id] = true;
self.dirty[page_id] = true;
self.data[addr] = data;
}
}
@ -98,15 +108,20 @@ mod test {
pt.clear_accessed(0);
assert!(!pt.accessed(0));
pt.write(1);
pt.read(1);
assert_eq!(*page_fault_count.borrow(), 0);
assert!(pt.accessed(0));
pt.write(0x1000, 0xff);
assert_eq!(*page_fault_count.borrow(), 1);
assert!(pt.accessed(1));
assert!(pt.dirty(1));
assert!(pt.accessed(0x1000));
assert!(pt.dirty(0x1000));
assert_eq!(pt.read(0x1000), 0xff);
pt.clear_dirty(1);
assert!(!pt.dirty(1));
pt.clear_dirty(0x1000);
assert!(!pt.dirty(0x1000));
assert_eq!(pt.map(2), false);
assert_eq!(pt.map(0x2000), false);
pt.unmap(0);
pt.read(0);

@ -117,17 +117,17 @@ mod test {
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)];
R(0x1000), R(0x2000), R(0x3000), R(0x4000),
R(0x3000), W(0x1000), R(0x4000), W(0x2000), R(0x5000),
R(0x2000), W(0x1000), R(0x2000), R(0x3000), R(0x4000)];
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),
R(addr) => {pt.read(*addr);},
W(addr) => pt.write(*addr, 0),
}
assert_eq!(*(*page_fault_count).borrow(), count);
}

@ -67,10 +67,10 @@ mod test {
}));
let op_seq = [
R(1), R(2), R(3), R(4),
W(3), W(1), W(4), W(2), W(5),
W(2), W(1), W(2), W(3), W(4),
W(5), R(1), W(1)];
R(0x1000), R(0x2000), R(0x3000), R(0x4000),
W(0x3000), W(0x1000), W(0x4000), W(0x2000), W(0x5000),
W(0x2000), W(0x1000), W(0x2000), W(0x3000), W(0x4000),
W(0x5000), R(0x1000), W(0x1000)];
let pgfault_count = [
1, 2, 3, 4,
4, 4, 4, 4, 5,
@ -78,8 +78,8 @@ mod test {
10, 11, 11];
for (op, &count) in op_seq.iter().zip(pgfault_count.iter()) {
match op {
R(addr) => pt.read(*addr),
W(addr) => pt.write(*addr),
R(addr) => {pt.read(*addr);},
W(addr) => pt.write(*addr, 0),
}
assert_eq!(*(*page_fault_count).borrow(), count);
}

@ -49,25 +49,31 @@ mod test {
}
#[test]
fn test() {
fn swap_out_in() {
let mut swapper = MockSwapper::new();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
let data1: [u8; 4096] = unsafe{ uninitialized() };
let token = swapper.swap_out(&data1).unwrap();
swapper.swap_in(token, &mut data);
swapper.swap_in(token, &mut data).unwrap();
assert_data_eq(&data, &data1);
}
#[test]
fn swap_update() {
let mut swapper = MockSwapper::new();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
let data1: [u8; 4096] = unsafe{ uninitialized() };
let data2: [u8; 4096] = unsafe{ uninitialized() };
swapper.swap_update(token, &data2);
swapper.swap_in(token, &mut data);
let token = swapper.swap_out(&data1).unwrap();
swapper.swap_update(token, &data2).unwrap();
swapper.swap_in(token, &mut data).unwrap();
assert_data_eq(&data, &data2);
}
#[test]
#[should_panic]
fn invalid_token() {
let mut swapper = MockSwapper::new();
let mut data: [u8; 4096] = unsafe{ uninitialized() };
swapper.swap_in(0, &mut data);
assert_eq!(swapper.swap_in(0, &mut data), Err(()));
}
}
Loading…
Cancel
Save