// use std::collections::HashMap; use std::mem; use std::sync::{Arc, Mutex}; use std::thread; use hulunbuir::{ slot::{Slot, Take}, Address, Collector, Keep, }; use env_logger; use rand::{thread_rng, Rng}; struct Node { children: Vec
, locked: HashMap, } impl Keep for Node { fn with_keep(&self, f: F) { let union: Vec<_> = self .children .iter() .chain(self.locked.keys()) .cloned() .collect(); let _: Vec<_> = union.iter().map(f).collect(); } } impl Node { fn new() -> Self { Node { children: Vec::new(), locked: HashMap::new(), } } fn lock(&mut self, address: &Address) { if self.locked.contains_key(address) { *self.locked.get_mut(address).unwrap() += 1; } else { self.locked.insert(address.clone(), 1); } } fn unlock(&mut self, address: &Address) { // println!("unlocking"); *self.locked.get_mut(address).unwrap() -= 1; if *self.locked.get(address).unwrap() == 0 { // println!("removing"); self.locked.remove(address); } } } fn wait(collector: &Mutex>>, address: &Address) -> Node { loop { let result = collector.lock().unwrap().take(address).unwrap(); match result { Take::Free(node) => return node, Take::Busy(parker) => parker.park(), } } } fn main() { env_logger::init(); let collector = Arc::new(Mutex::new(Collector::new(4096))); let root = collector .lock() .unwrap() .allocate(Slot::new(Node::new())) .unwrap(); collector.lock().unwrap().set_root(root.clone()); let mut handle: [Option>; 10] = Default::default(); for i in 0..10 { let thread_collector = Arc::clone(&collector); let thread_root = root.clone(); handle[i] = Some(thread::spawn(move || { let mut rng = thread_rng(); let collector = thread_collector; let root = thread_root; for _j in 0..16384 { let mut current = root.clone(); let mut node; let mut node_stack = Vec::new(); loop { // println!("start loop"); node = wait(&collector, ¤t); let stop = node.children.is_empty() || rng.gen::() < 0.05; if stop { // current node is still used outside loop block // so it is not filled before breaking // go to hell RAII break; } let child_index = rng.gen_range(0, node.children.len()); let next_current = node.children[child_index].to_owned(); node.lock(&next_current); collector.lock().unwrap().fill(¤t, node).unwrap(); node_stack.push(current.clone()); current = next_current; } let replaced_child = rng.gen_range(0, 100); // mutex lock is saved for reusing here // otherwise, other thread may trigger a collecting between // allocation of new object and filling its parent // which will collect the new object immediately let mut new_child_write = collector.lock().unwrap(); let new_child = new_child_write.allocate(Slot::new(Node::new())).unwrap(); if node.children.len() <= replaced_child { node.children.push(new_child); } else { node.children[replaced_child] = new_child; } new_child_write.fill(¤t, node).unwrap(); mem::drop(new_child_write); while let Some(parent) = node_stack.pop() { let mut node = wait(&collector, &parent); node.unlock(¤t); collector.lock().unwrap().fill(&parent, node).unwrap(); current = parent; } } })); } for i in 0..10 { handle[i].take().unwrap().join().unwrap(); } }