parent
0420e85e4d
commit
a1e9ee36b2
@ -0,0 +1,50 @@
|
|||||||
|
use alloc::vec_deque::VecDeque;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
struct FifoSwapManager {
|
||||||
|
deque: VecDeque<Addr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PageTable> SwapManager<T> for FifoSwapManager {
|
||||||
|
fn new(_page_table: &T) -> Self {
|
||||||
|
FifoSwapManager {
|
||||||
|
deque: VecDeque::<Addr>::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tick(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, addr: usize) {
|
||||||
|
self.deque.push_back(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self, addr: usize) {
|
||||||
|
let id = self.deque.iter()
|
||||||
|
.position(|&x| x == addr)
|
||||||
|
.expect("address not found");
|
||||||
|
self.deque.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn swap(&mut self) -> Option<Addr> {
|
||||||
|
self.deque.pop_front()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
// let mut pt = mock_page_table::MockPageTable::new();
|
||||||
|
// let mut sm = FifoSwapManager::new();
|
||||||
|
// let write_seq = [3, 1, 4, 2, 5, 2, 1, 2, 3, 4, 5, 1, 1];
|
||||||
|
// let pgfault_count = [4, 4, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11, 11];
|
||||||
|
// for i in write_seq {
|
||||||
|
// pt.write(i);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
use alloc::btree_set::BTreeSet;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct MockPageTable {
|
||||||
|
mapped_set: BTreeSet<Addr>,
|
||||||
|
accessed_set: BTreeSet<Addr>,
|
||||||
|
dirty_set: BTreeSet<Addr>,
|
||||||
|
pgfault_handler: PgfaultHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
type PgfaultHandler = fn(&mut MockPageTable, Addr);
|
||||||
|
|
||||||
|
impl PageTable for MockPageTable {
|
||||||
|
fn accessed(&self, addr: Addr) -> bool {
|
||||||
|
self.accessed_set.contains(&addr)
|
||||||
|
}
|
||||||
|
fn dirty(&self, addr: Addr) -> bool {
|
||||||
|
self.dirty_set.contains(&addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MockPageTable {
|
||||||
|
pub fn new(pgfault_handler: PgfaultHandler) -> Self {
|
||||||
|
MockPageTable {
|
||||||
|
mapped_set: BTreeSet::<Addr>::new(),
|
||||||
|
accessed_set: BTreeSet::<Addr>::new(),
|
||||||
|
dirty_set: BTreeSet::<Addr>::new(),
|
||||||
|
pgfault_handler,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Read memory, mark accessed, trigger page fault if not present
|
||||||
|
pub fn read(&mut self, addr: Addr) {
|
||||||
|
while !self.mapped_set.contains(&addr) {
|
||||||
|
(self.pgfault_handler)(self, addr);
|
||||||
|
}
|
||||||
|
self.accessed_set.insert(addr);
|
||||||
|
|
||||||
|
}
|
||||||
|
/// Write memory, mark accessed and dirty, trigger page fault if not present
|
||||||
|
pub fn write(&mut self, addr: Addr) {
|
||||||
|
while !self.mapped_set.contains(&addr) {
|
||||||
|
(self.pgfault_handler)(self, addr);
|
||||||
|
}
|
||||||
|
self.accessed_set.insert(addr);
|
||||||
|
self.dirty_set.insert(addr);
|
||||||
|
}
|
||||||
|
pub fn map(&mut self, addr: Addr) {
|
||||||
|
self.mapped_set.insert(addr);
|
||||||
|
}
|
||||||
|
pub fn unmap(&mut self, addr: Addr) {
|
||||||
|
self.mapped_set.remove(&addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
static mut PGFAULT_COUNT: usize = 0;
|
||||||
|
|
||||||
|
fn assert_pgfault_eq(x: usize) {
|
||||||
|
assert_eq!(unsafe{ PGFAULT_COUNT }, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
fn pgfault_handler(pt: &mut MockPageTable, addr: Addr) {
|
||||||
|
unsafe{ PGFAULT_COUNT += 1; }
|
||||||
|
pt.map(addr);
|
||||||
|
}
|
||||||
|
let mut pt = MockPageTable::new(pgfault_handler);
|
||||||
|
|
||||||
|
pt.map(0);
|
||||||
|
pt.read(0);
|
||||||
|
assert_pgfault_eq(0);
|
||||||
|
assert!(pt.accessed(0));
|
||||||
|
assert!(!pt.dirty(0));
|
||||||
|
|
||||||
|
pt.write(1);
|
||||||
|
assert_pgfault_eq(1);
|
||||||
|
assert!(pt.accessed(1));
|
||||||
|
assert!(pt.dirty(1));
|
||||||
|
|
||||||
|
pt.unmap(0);
|
||||||
|
pt.read(0);
|
||||||
|
assert_pgfault_eq(2);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
pub mod fifo;
|
||||||
|
mod mock_page_table;
|
||||||
|
|
||||||
|
type Addr = usize;
|
||||||
|
|
||||||
|
trait SwapManager<T: PageTable> {
|
||||||
|
/// Create and initialize for the swap manager
|
||||||
|
fn new(page_table: &T) -> Self;
|
||||||
|
/// Called when tick interrupt occured
|
||||||
|
fn tick(&mut self);
|
||||||
|
/// Called when map a swappable page into the memory
|
||||||
|
fn push(&mut self, addr: Addr);
|
||||||
|
/// Called to delete the addr entry from the swap manager
|
||||||
|
fn pop(&mut self, addr: Addr);
|
||||||
|
/// Try to swap out a page, return then victim
|
||||||
|
fn swap(&mut self) -> Option<Addr>;
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PageTable {
|
||||||
|
fn accessed(&self, addr: Addr) -> bool;
|
||||||
|
fn dirty(&self, addr: Addr) -> bool;
|
||||||
|
}
|
Loading…
Reference in new issue