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

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

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

@ -49,25 +49,31 @@ mod test {
} }
#[test] #[test]
fn test() { fn swap_out_in() {
let mut swapper = MockSwapper::new(); let mut swapper = MockSwapper::new();
let mut data: [u8; 4096] = unsafe{ uninitialized() }; let mut data: [u8; 4096] = unsafe{ uninitialized() };
let data1: [u8; 4096] = unsafe{ uninitialized() }; let data1: [u8; 4096] = unsafe{ uninitialized() };
let token = swapper.swap_out(&data1).unwrap(); 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); 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() }; let data2: [u8; 4096] = unsafe{ uninitialized() };
swapper.swap_update(token, &data2); let token = swapper.swap_out(&data1).unwrap();
swapper.swap_in(token, &mut data); swapper.swap_update(token, &data2).unwrap();
swapper.swap_in(token, &mut data).unwrap();
assert_data_eq(&data, &data2); assert_data_eq(&data, &data2);
} }
#[test] #[test]
#[should_panic]
fn invalid_token() { fn invalid_token() {
let mut swapper = MockSwapper::new(); let mut swapper = MockSwapper::new();
let mut data: [u8; 4096] = unsafe{ uninitialized() }; 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