WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

Commit ea493917 authored by qinsoon's avatar qinsoon
Browse files

use doubly linked list for from/to_space of treadmill

parent 996e71a2
......@@ -18,4 +18,5 @@ lazy_static = "0.1.15"
log = "0.3.5"
simple_logger = "0.4.0"
aligned_alloc = "0.1.2"
crossbeam = "0.2.8"
\ No newline at end of file
crossbeam = "0.2.8"
doubly = "1.1.1"
\ No newline at end of file
#![allow(dead_code)]
extern crate doubly;
use utils::Address;
use utils::mem::memmap;
use utils::LOG_POINTER_SIZE;
......@@ -12,6 +14,8 @@ use std::sync::Arc;
use std::fmt;
use std::sync::Mutex;
use self::doubly::DoublyLinkedList;
const SPACE_ALIGN : usize = 1 << 19;
const BLOCK_SIZE : usize = 1 << 12; // 4kb
......@@ -75,6 +79,10 @@ impl FreeListSpace {
trace!("requiring {} bytes ({} blocks)", size, blocks_needed);
let res = {
if blocks_needed > 1 {
unimplemented!()
}
let mut treadmill = self.treadmill.lock().unwrap();
treadmill.alloc_blocks(blocks_needed)
};
......@@ -104,83 +112,58 @@ impl FreeListSpace {
let mut alive_nodes_scanned = 0;
let mut treadmill = self.treadmill.lock().unwrap();
let trace_map = self.trace_map();
let mark_state = objectmodel::load_mark_state();
let mut resnapped_any = false;
loop {
trace!("scanning {}", unsafe { &*treadmill.scan });
let addr = unsafe{&*treadmill.scan}.payload;
nodes_scanned += 1;
if objectmodel::is_traced(trace_map, self.start, unsafe { addr.to_object_reference() }, mark_state) && unsafe{&*treadmill.scan}.color == objectmodel::flip(mark_state) {
// the object is alive, do not need to 'move' its node
alive_nodes_scanned += 1;
// but they will be alive, we will set them to opposite mark color
// (meaning they are not available after flip)
unsafe{&mut *treadmill.scan}.color = objectmodel::flip(mark_state);
trace!("is alive, set color to {}", objectmodel::flip(mark_state));
{
let trace_map = self.trace_map();
let mark_state = objectmodel::load_mark_state();
// advance cur backwards
treadmill.scan = unsafe{&*treadmill.scan}.prev();
} else {
// this object is dead
// we do not need to set their color
let from = treadmill.from;
let to = treadmill.to;
free_nodes_scanned += 1;
let total_nodes = treadmill.spaces[from].len();
let mut i = 0;
while nodes_scanned < total_nodes {
trace!("scanning {}", treadmill.spaces[from][i]);
let addr = treadmill.spaces[from][i].payload;
// we resnap it after current 'free' pointer
if treadmill.scan != treadmill.free {
// since we are going to move current node (scan), we get its prev first
let prev = unsafe{&*treadmill.scan}.prev();
trace!("get scan's prev before resnapping it: {}", unsafe { &*prev });
nodes_scanned += 1;
let alive_node = unsafe { &mut *treadmill.scan }.remove();
if objectmodel::is_traced(trace_map, self.start, unsafe { addr.to_object_reference() }, mark_state) {
// this object is alive
alive_nodes_scanned += 1;
trace!("is dead, take it out of treadmill");
if TRACE_TREADMILL {
trace!("treadmill: {}", &treadmill as &Treadmill);
}
// move to tospace
let node = treadmill.spaces[from].remove(i);
treadmill.spaces[to].push_front(node);
// insert alive node after free
unsafe{&mut *treadmill.free}.insert_after(alive_node);
trace!("is alive");
trace!("insert after free");
if TRACE_TREADMILL {
trace!("treadmill: {}", &treadmill as &Treadmill);
}
// if this is the first object inserted, it is the 'bottom'
// then 1) all resnapped objects will be between 'free' and 'bottom'
// 2) the traversal can stop when scan meets bottom
if !resnapped_any {
treadmill.b = treadmill.scan;
resnapped_any = true;
}
treadmill.scan = prev;
// do not increment i
} else {
trace!("is dead and it is free pointer, do not move it");
treadmill.scan = unsafe{&*treadmill.scan}.prev();
free_nodes_scanned += 1;
i += 1;
}
}
// check if we can stop
if resnapped_any && treadmill.scan == treadmill.b {
break;
}
if !resnapped_any && treadmill.scan == treadmill.free {
// we never set bottom (meaning everything is alive)
// check if we have any free nodes
if free_nodes_scanned == 0 && treadmill.spaces[treadmill.to].len() == 0 {
println!("didnt free up any memory in treadmill space");
panic!("we ran out of memory in large object space")
}
}
// next allocation in to_space will starts from alive_nodes_scanned
treadmill.from_space_next = alive_nodes_scanned;
// flip
if treadmill.from == 0 {
treadmill.from = 1;
treadmill.to = 0;
} else {
treadmill.from = 0;
treadmill.to = 1;
}
if cfg!(debug_assertions) {
debug!("---tread mill space---");
debug!("total nodes scanned: {}", nodes_scanned);
......@@ -228,202 +211,84 @@ impl fmt::Display for FreeListSpace {
}
struct Treadmill{
free: *mut TreadmillNode,
scan: *mut TreadmillNode,
b : *mut TreadmillNode
from_space_next : usize, // next available node in from_space
from: usize,
to : usize,
spaces : [DoublyLinkedList<TreadmillNode>; 2]
}
impl Treadmill {
fn new(start: Address, end: Address) -> Treadmill {
let mut addr = start;
let half_space = start.plus(end.diff(start) / 2);
let free = TreadmillNode::singleton(addr);
addr = addr.plus(BLOCK_SIZE);
let mut from_space = DoublyLinkedList::new();
let mut to_space = DoublyLinkedList::new();
let mut tail = free;
let mut addr = start;
while addr < half_space {
from_space.push_back(TreadmillNode::new(addr));
addr = addr.plus(BLOCK_SIZE);
}
while addr < end {
tail = unsafe {(&mut *tail)}.init_insert_after(addr);
to_space.push_back(TreadmillNode::new(addr));
addr = addr.plus(BLOCK_SIZE);
}
Treadmill {
free: free,
scan: free,
b: free
from_space_next: 0,
from: 0,
to : 1,
spaces: [from_space, to_space]
}
}
fn alloc_blocks(&mut self, n_blocks: usize) -> Address {
let unavailable_color = objectmodel::load_mark_state();
// check if we have n_blocks available
let mut cur = self.free;
for _ in 0..n_blocks {
if unsafe{&*cur}.color == unavailable_color {
trace!("next block color is {}, no available blocks, return zero", unavailable_color);
return unsafe {Address::zero()};
}
let ref from_space = self.spaces[self.from];
if self.from_space_next + n_blocks <= from_space.len() {
let ret = from_space[self.from_space_next].payload;
self.from_space_next += n_blocks;
cur = unsafe {&*cur}.next;
}
// we make sure that n_blocks are available, mark them as black
let mut cur2 = self.free;
for _ in 0..n_blocks {
unsafe{&mut *cur2}.color = unavailable_color;
cur2 = unsafe {&*cur2}.next
ret
} else {
unsafe {Address::zero()}
}
debug_assert!(cur == cur2);
let ret = self.free;
self.free = cur;
trace!("set free to {}", unsafe {&*cur});
unsafe{&*ret}.payload
}
}
impl fmt::Display for Treadmill {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut cursor = self.free;
write!(f, "next: {}", self.from_space_next);
write!(f, "from:").unwrap();
for i in 0..self.spaces[self.from].len() {
write!(f, "{}->", self.spaces[self.from][i]).unwrap();
}
write!(f, "\n").unwrap();
loop {
write!(f, "{}", unsafe{&*cursor}).unwrap();
if cursor == self.free {
write!(f, "(free)").unwrap();
}
if cursor == self.scan {
write!(f, "(scan)").unwrap();
}
if cursor == self.b {
write!(f, "(bottom)").unwrap();
}
if unsafe{&*cursor}.next() == self.free {
break;
} else {
write!(f, "\n->").unwrap();
cursor = unsafe{&*cursor}.next();
}
write!(f, "to:").unwrap();
for i in 0..self.spaces[self.to].len() {
write!(f, "{}->", self.spaces[self.to][i]).unwrap();
}
Ok(())
write!(f, "\n")
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum TreadmillNodeColor {
Offwhite,
White,
Grey,
Black
}
struct TreadmillNode {
payload: Address,
color: u8,
prev: *mut TreadmillNode,
next: *mut TreadmillNode
}
impl fmt::Display for TreadmillNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}-{:?}]", self.payload, self.color)
}
payload: Address
}
impl TreadmillNode {
fn singleton(addr: Address) -> *mut TreadmillNode {
let mut ptr = Box::into_raw(Box::new(TreadmillNode {
payload: addr,
// starts as 0 (1, i.e. mark_state, means allocated/alive)
color: objectmodel::flip(objectmodel::load_mark_state()),
prev: ptr::null_mut(),
next: ptr::null_mut(),
}));
// first node in the cyclic doubly linked list
unsafe {
(*ptr).prev = ptr;
(*ptr).next = ptr;
}
ptr
}
/// returns the inserted node
fn init_insert_after(&mut self, addr: Address) -> *mut TreadmillNode {
unsafe {
// node <- ptr -> node.next
let mut ptr = Box::into_raw(Box::new(TreadmillNode {
payload: addr,
color: objectmodel::flip(objectmodel::load_mark_state()),
// inserted between node and node.next
prev: self as *mut TreadmillNode,
next: self.next
}));
// ptr <- node.next
unsafe{(&mut *self.next)}.prev = ptr;
// node -> ptr
self.next = ptr;
ptr
}
}
fn insert_after(&mut self, node: *mut TreadmillNode) {
unsafe {
// self <- node -> self.next
(&mut *node).next = self.next;
(&mut *node).prev = self as *mut TreadmillNode;
// self.next -> node
self.next = node;
// node <- node.next.prev
(&mut *(&mut *node).next).prev = node;
}
}
/// remove current node from treadmill, and returns the node
fn remove(&mut self) -> *mut TreadmillNode {
if self.next == self as *mut TreadmillNode && self.prev == self as *mut TreadmillNode {
// if this is the only node, return itself
self as *mut TreadmillNode
} else {
// we need to take it out from the list
unsafe {
use std::ptr;
// its prev node's next will be its next node
(&mut *self.prev).next = self.next as *mut TreadmillNode;
// its next node' prev will be its prev node
(&mut *self.next).prev = self.prev as *mut TreadmillNode;
// clear current node prev and next
self.prev = ptr::null_mut();
self.next = ptr::null_mut();
}
// then return it
self as *mut TreadmillNode
fn new(addr: Address) -> TreadmillNode {
TreadmillNode {
payload: addr
}
}
}
fn next(&self) -> *mut TreadmillNode {
self.next
}
fn prev(&self) -> *mut TreadmillNode {
self.prev
impl fmt::Display for TreadmillNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.payload)
}
}
......@@ -450,6 +315,7 @@ mod tests {
}
#[test]
#[ignore]
fn test_treadmill_alloc_spanblock() {
let mut space = FreeListSpace::new(BLOCK_SIZE * 10);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment