use std::cell::Cell;
use std::sync::atomic::{self, AtomicUsize, AtomicBool};
use std::sync::atomic::Ordering::{Relaxed, Acquire, Release, SeqCst};
use mem::epoch::{Atomic, Guard, global};
use mem::epoch::participants::ParticipantNode;
pub struct Participant {
epoch: AtomicUsize,
in_critical: AtomicUsize,
num_ops: Cell<u64>,
pub active: AtomicBool,
pub next: Atomic<ParticipantNode>,
}
unsafe impl Sync for Participant {}
const GC_THRESH: u64 = 128;
impl Participant {
pub fn new() -> Participant {
Participant {
epoch: AtomicUsize::new(0),
in_critical: AtomicUsize::new(0),
num_ops: Cell::new(0),
active: AtomicBool::new(true),
next: Atomic::null(),
}
}
pub fn enter(&self) -> bool {
let new_count = self.in_critical.load(Relaxed) + 1;
self.in_critical.store(new_count, Relaxed);
if new_count > 1 { return false }
atomic::fence(SeqCst);
let global_epoch = global::get().epoch.load(Relaxed);
if global_epoch != self.epoch.load(Relaxed) {
self.epoch.store(global_epoch, Relaxed);
self.num_ops.set(0);
} else {
self.num_ops.set(self.num_ops.get() + 1);
}
true
}
pub fn exit(&self) {
let new_count = self.in_critical.load(Relaxed) - 1;
self.in_critical.store(
new_count,
if new_count > 0 { Relaxed } else { Release });
}
pub unsafe fn reclaim<T>(&self, data: *mut T) {
let cur_global = global::get().epoch.load(Acquire);
global::get().garbage[cur_global % 3].insert(data);
}
pub fn try_collect(&self, guard: &Guard) -> bool {
let cur_epoch = global::get().epoch.load(SeqCst);
for p in global::get().participants.iter(guard) {
if p.in_critical.load(Relaxed) > 0 && p.epoch.load(Relaxed) != cur_epoch {
return false
}
}
let new_epoch = cur_epoch.wrapping_add(1);
atomic::fence(Acquire);
if global::get().epoch.compare_and_swap(cur_epoch, new_epoch, SeqCst) != cur_epoch {
return false
}
self.epoch.store(new_epoch, Relaxed);
unsafe {
global::get().garbage[new_epoch.wrapping_add(1) % 3].collect();
}
self.num_ops.set(0);
true
}
pub fn should_gc(&self) -> bool {
self.num_ops.get() >= GC_THRESH
}
}