1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
use std::marker; use super::{local, Shared}; /// An RAII-style guard for pinning the current epoch. /// /// A guard must be acquired before most operations on an `Atomic` pointer. On /// destruction, it unpins the epoch. #[must_use] #[derive(Debug)] pub struct Guard { _marker: marker::PhantomData<*mut ()>, // !Send and !Sync } /// Pin the current epoch. /// /// Threads generally pin before interacting with a lock-free data /// structure. Pinning requires a full memory barrier, so is somewhat /// expensive. It is rentrant -- you can safely acquire nested guards, and only /// the first guard requires a barrier. Thus, in cases where you expect to /// perform several lock-free operations in quick succession, you may consider /// pinning around the entire set of operations. pub fn pin() -> Guard { local::with_participant(|p| { p.enter(); let g = Guard { _marker: marker::PhantomData, }; if p.should_gc() { p.try_collect(&g); } g }) } impl Guard { /// Assert that the value is no longer reachable from a lock-free data /// structure and should be collected when sufficient epochs have passed. pub unsafe fn unlinked<T>(&self, val: Shared<T>) { local::with_participant(|p| p.reclaim(val.as_raw())) } /// Move the thread-local garbage into the global set of garbage. pub fn migrate_garbage(&self) { local::with_participant(|p| p.migrate_garbage()) } } impl Drop for Guard { fn drop(&mut self) { local::with_participant(|p| p.exit()); } }