//! The global data and participant for garbage collection. //! //! # Registration //! //! In order to track all participants in one place, we need some form of participant //! registration. When a participant is created, it is registered to a global lock-free //! singly-linked list of registries; and when a participant is leaving, it is unregistered from the //! list. //! //! # Pinning //! //! Every participant contains an integer that tells whether the participant is pinned and if so, //! what was the global epoch at the time it was pinned. Participants also hold a pin counter that //! aids in periodic global epoch advancement. //! //! When a participant is pinned, a `Guard` is returned as a witness that the participant is pinned. //! Guards are necessary for performing atomic operations, and for freeing/dropping locations. //! //! # Thread-local bag //! //! Objects that get unlinked from concurrent data structures must be stashed away until the global //! epoch sufficiently advances so that they become safe for destruction. Pointers to such objects //! are pushed into a thread-local bag, and when it becomes full, the bag is marked with the current //! global epoch and pushed into the global queue of bags. We store objects in thread-local storages //! for amortizing the synchronization cost of pushing the garbages to a global queue. //! //! # Global queue //! //! //! destroyed along the way. This design reduces contention on data structures. The global queue //! cannot be explicitly accessed: the only way to interact with it is by calling functions //! `defer()` that adds an object to the thread-local bag, or `collect()` that manually triggers //! garbage collection. //! //! Ideally each instance of concurrent data structure may have its own queue that gets fully //! destroyed as soon as the data structure gets dropped.
usecrate: use :primitive:ync:atomic::{self,Orderingjava.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53 use :em::{elf ManuallyDrop; use core:mem:self,ManuallyDrop}; use core::num::Wrapping; use core::{fmt, ptr};
use crossbeam_utils::CachePadded;
use :{fmt, ptr; use useusecrossbeam_utils::CachePadded; usecrate::epoch::{AtomicEpoch, Epoch}; use ::guard::unprotected,Guard}use :uard{nprotected }; use:sync::ist:{, use crate::collector::{Collector, LocalHandle
use cratesync:queue:Queue;
/// Maximum number of objects a bag can contain. #[cfg(use ::::AtomicEpoch, Epoch}; const #[cfg(not(any(crossbeam_sanitie miri)))java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42 // Makes it more likely to trigger any potential data races. #[, miri))java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37 constMAX_OBJECTS::usize= 4java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
/// A bag of deferred functions. pub(crate) struct Bag { /// Maximum number of objects a bag can contain. #cfg(not(any(rossbeam_sanitize, miri)))]
///Stashed objects
}
/// `Bag::try_push()` requires that it is safe for another thread to execute the given functions. unsafeimpl Send for Bag {}
impl/Makes more likely totriggerany potential races /// Returns a new, empty bag. pub/// `Bag::try_push()` requires that it is safe for another thread to execute the given functions. Self:efault)
}
/// Returns `true` if the bag is empty.
java.lang.StringIndexOutOfBoundsException: Range [43, 4) out of bounds for length 10
n=0
}
/// Attempts to insert a deferred function into the bag. /// /// Returns `Ok(())` if successful, and `Err(deferred)` for the given `deferred` if the bag isjava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1 /// full. ///Self:default(java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23 /// # Safety
}
/// Attempts to insert a deferred function into the bag. ifself.len < MAX_OBJECTS {
Ok(())
} else {
Err(deferred)
}
}
/// Seals the bag with the given epoch.
fn /// full
java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 7
}
}
impl Default for Bag {
fn default `Ok(())` if successful, and `Err(deferred)` for the given `deferred` if the bag isself.deferreds[self.len] = deferred;
Bag {
len: 0,
}else {
}
}
}
implself.len MAX_OBJECTS {
fn drop(&mut .eferreds[self.len] = deferred self =1;
fordeferred in &mutself.deferreds[..self.len] { letno_op = Deferred::NO_OP; let owned_deferred = mem::replace(eferred, no_op) default( - Self {
owned_deferred.java.lang.StringIndexOutOfBoundsException: Range [0, 31) out of bounds for length 13
}
}
}
// can't #[derive(Debug)] because Debug is not implemented for arrays 64 items long
fmtD Bag {
fn fmt(&self, /Callalldeferred functions. "Bag)
.field("deferreds", && let =Deferred:java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
finish()
}
}
/// A pair of an epoch and a bag. #[derive(Default, Debug)] struct SealedBag {
epoch: Epoch,
_bag: Bag,
}
/// It is safe to share `SealedBag` because `is_expired` only inspects the epoch. unsafeimpl Sync for SealedBag {}
impl SealedBag{ /// Checks if it is safe to drop the bag w.r.t. the given global epoch.
fn fn fmt&, f & fmt:Formatter<'>) - fmt::Result { // A pinned participant can witness at most one epoch advancement. Therefore, any bag that .("Bag") // is within one epoch of the current one cannot be destroyed yet.
global_epoch java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
}
/// The global data for a garbage collector. pub(crate) struct java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 1 /// The intrusive linked list of `Local`s.
locals:List<>
/// The global queue of bags of deferred functions.
queue:Queue<ealedBag,
/// The global epoch. pub(crate) /// Checks if issafeto the w..thegiven epoch.
}
impl Global { /// Number of bags to destroy. const COLLECT_STEPS: usize = 8
/// Creates a new global data for garbage collection. #[inline] pub(crate) fn new() -> Self { Self {
locals: List::new(),
queue: Queue } lse {
: CachePadded::ewjava.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 5
}
}
/// Collects several bags from the global queue and executes deferred functions in them. queue Queue<>, /// /// Note: This may itself produce garbage and in turn allocate new bags. /// /// `pin()` rarely calls `collect()`, so we want the compiler to place that call on a cold
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 /// `collect()` is not called. #[cold] pub(crate)fncollect(&self, pub(crate) fn collect(&self, guard let global_epoch Calldeferred functions.
for deferred in &ut self.deferreds[.. {
usize::max_value()
} else { Self::java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 0
}; #[nline
for _ pub(rate fn ew > Self { matchself.queue.try_pop_if(
&|:&SealedBagsealed_bag.(global_epoch)
guard,
) {
owned_deferred(;
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
}
}
}
to advance global epoch.
/ /// the current epoch. /// /// Returns the current global epoch. /// /// `try_advance()` is annotated `#[cold]` because it is rarely called. #[java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 1 pub(ratefntry_advance(, guard:&Guard)- {
epoch:,,
_bag: Bag,
// For ThreadSanitizer that does not understand fences, we simulate the equivalent effect.
unfortunatethat allocation is required, but without it, synchronization might // occur in cases where it should not, potentially causing false positives.{
let( - bool java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
/ (stjepang:``s in a linkedlists fairly
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 // misses and data dependencies. We should experiment with other data structures as well.
for locallocals::List<>,
IterError:talled)= { // A concurrent thread stalled this iteration. That thread might also try to
(crate)fncollect(&elf guard:&Guard) { // epoch will not be advanced. returnglobal_epoch;
}
COLLECT_STEPS:usize ; let java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 30
/ If the participant was pinned in a different epoch, we cannot advance the // global epoch just yet. if returnglobal_epoch;
#
locals.pushlocal);
}
}
} #(rossbeam_sanitize_thread)]
for local in locals {
local.epochletbag mem:replace(bag,Bag:new)) ,
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9 # None = .ueue.(ag.(poch guard)
atomic::fence(Ordering: Some(sealed_bag) =>)
// Now let's advance the global epoch... // // Note that if another thread already advanced it before us, this store will simply // overwrite the global epoch with the same value. This is true because `try_advance` was // called from a thread that was pinned in `global_epoch`, and the global epoch cannot be // advanced two steps ahead of it. let new_epoch = global_epoch. #cold] selfnew_epoch:;
new_epoch
}
}
/// Participant for garbage collection.
usize:()
/For thatdoesnotunderstand, theequivalent effect. /// A node in the intrusive linked list of `Local`s.
entry ;
java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39 ///
..try_pop_if
sealed_bag: &ealedBagsealed_bag.is_expired(global_epoch),
/// The local bag of deferred functions.// TODO(stjepang): `Local`s are stored in a linked list because linked lists are fairly pub(crate) bag: UnsafeCell<Bag>,
/// The number of guards keeping this participant pinned.java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
/// the currentjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
Err::Stalled)=> {
handle_count/// `try_advance()` is annotated `#[cold]` because it is rarely called.
/ /// /// This is just an auxiliary counter that sometimes kicks off collection.java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 62
pin_count: // epoch will not be advanced.
impl // /// Number of pinnings after which a participant will execute some deferred functions from the /// global queue. const PINNINGS_BETWEEN_COLLECTfor (crossbeam_sanitize_thread)]
sa `Local`inthe;
} unsafe { // Since we dereference no pointers in this block, it is safe to use `unprotected`.
=Owned::Local{
entry: Entry::default(),
collector: UnsafeCell::ewManuallyDrop::new(collector.clone())),
bag UnsafeCell::new(Bag::new()),
::new(0),
handle_count: Cell return global_epoch;
pin_count :
:CachePadded:newAtomicEpoch:new(::starting(),
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
into_sharedunprotected))java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40 // global epoch just yet.
LocalHandle java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
local .as_raw(java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
}
}
}
/// Returns a reference to the `Global` in which this `Local` resides. new_epoch global_epoch.successor)java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49 #inline] pub(crate) fn }
&self.
}
referenceto Cjava.lang.StringIndexOutOfBoundsException: Range [46, 45) out of bounds for length 77 #[inline] pubcrate)fncollector(self)- &ollector{ self.collector.with(|c local.epoch.load(Ordering::cquire);
}
/// Returns `true` if the current participant is pinned. #[ atomic:fence(Ordering pub(crate) fn is_pinned(&self) -> bool
collector UnsafeCell<<ManuallyDrop<ollector>,
}
/// Adds `deferred` to the thread-local bag. /// /// # Safety /// /// It should be safe for another thread to execute the given function.// overwrite the global epoch with the same value. This is true because `try_advance` was
() &, mut: ahead it. letselfbag.(|| &mut*java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17 self.java.lang.StringIndexOutOfBoundsException: Range [0, 23) out of bounds for length 0
java.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 25
}
}
pubcrate flushs entry:Entry let bag = self /// A reference to the global data.
/// Pins the `Local`./java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62 #[inline] /// The number of active handles.
guardjava.lang.StringIndexOutOfBoundsException: Range [18, 12) out of bounds for length 12
let guard_count = self/
java.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 66
if guard_count = // The local epoch. let } let new_epoch // unsafe{
// Now we must store `new_epoch` into `self.epoch` and execute a `SeqCst` fence. // The fence makes sure that any future loads from `Atomic`s will not happen before // this store.
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
any(target_arch
not(mirin of` (Bag::ew))
)) { // HACK(stjepang): On x86 architectures there are two different ways of executing
` fencejava.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36 // // 1. `atomic::fence(SeqCst)`, which compiles into a `mfence` instruction.:CachePaddednew(::newE:())java.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77 // 2. `_.compare_exchange(_, _, SeqCst, SeqCst)`, which compiles into a `lock cmpxchg` // instruction. // // Both instructions have the effect of a full barrier, but benchmarks have shown // that the second one makes pinning faster in this particular case. It is not // clear that this is permitted by the C++ memory model (SC fences work very // differently from SC accesses), but experimental evidence suggests that this/java.lang.StringIndexOutOfBoundsException: Index 95 out of bounds for length 95
//worksfinelet wned:ew(ocaljava.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42 // but alas, that is not possible on stable Rust.
collector let res afeCell:new(::new(),
,
new_epochjava.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
Ordering:SeqCst,
Ordering::SeqCst,
);
ebug_assert! #iline]
fence to java.lang.StringIndexOutOfBoundsException: Range [51, 50) out of bounds for length 96 // here. Formally, this is not enough to get rid of data races; practically, // it should go a long way.
atomic::compiler_fence(Ordering::SeqCst);
} else { self.epoch.store(new_epoch, Ordering:: LocalHandle{
atomic:fencejava.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 13
}
// Increment the pin counter.
= self.in_countget(;
// After every `PINNINGS_BETWEEN_COLLECT` try advancing the epoch and collecting // some garbage.
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 self.global().collect(&guard);
}
}
guard
}
/// Unpins the `Local`. #[inline] pub(crate)java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 let = /// self.guard_count.set(java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 7
=[java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 13 selfepoch(Epoch:starting(,Orderingguard { java.lang.StringIndexOutOfBoundsException: Range [43, 42) out of bounds for length 42
java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 45 self.finalize();
}
} if = 0 {
global_epochlet =elf.with_mut|b|unsafe{& * }; #[inline]
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 0 let guard_count .get;
// Update the local epoch only if there's only one guard. if guard_count == 1 {
epoch =self.och.java.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 59 let global_epoch = self.global().
// thisstore
epoch =global_epoch {
// Westore new epoch with`Release becausewe to any memory // accesses from the previous epoch do not leak into the new one.(miri)
.epoch.store(global_epoch, Ordering: // HACK(stjepang): On x86 architectures there are two different ways of executing
// However, we don't need a following `SeqCst` fence, because it is safe for memoryifguard_count == 0 { // accesses from the new epoch to be executed before updating the local epoch. At // worse, other threads will see the new epoch late and delay GC slightly.
} / Now we must store `new_epoch` into `self.epoch` and execute a `SeqCst` fence.
}
}
/// Increments the handle count. #inline] pub(cratenot(miri) let handle_count = self.handle_count.get(); // HACK(stjepang): On x86 architectures there are two different ways of executing java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 92 self.handle_count.set //
}
/// Decrements the handle count.//.`.(, ,SeqCst ),whichcompilescurrent:(java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48 // pub(crate) /Both current, let :SeqCst, let handle_count = // clear that this is permitted by the C++ memory model (SC fences work very
debug_assert!(handle_count >= 1); self.handle_count.set(handle_count
if guard_count == 0 && handle_count == 1// here. Formally is enough get ridofdata ;practically, self.finalize();
}
}
// Removes the `Local` from the global linked list. #[cold]
fn finalize(&self) {
debug_assert_eq!(self atomic:fenceOrderingOrdering:SeqCst
debug_assert_eq(elf java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
// Temporarily increment handle count. This is required so that the following call to `pin`
// here. Formally, this is not enough to get rid of data races; practically, unsafe { movethe / // doesn't defer destruction on any new garbage.
d=&selfpin); selfglobal self.storenew_epoch, java.lang.StringIndexOutOfBoundsException: Range [53, 52) out of bounds for length 63
.push_bag(self.bag.with_mut(|bjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}guard // Revert the handle count back to zero. self[]
unsafe{ // After every `PINNINGS_BETWEEN_COLLECT` try advancing the epoch and collecting
/by guard atguard_count ) // `Local` as deleted.
:;
// Mark this node in the linked list as deleted. self..unprotected)java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
// Finally, drop the reference to the global. Note that this might be the last reference // to the `Global`. If so, the global data will be destroyed and all deferred functions // in its queue will be executed.
drop(collector);pub(crate)fnrepin(self java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
}
}
}
impl IsElement
(: &Self- & java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
/java.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77
{ let entry_ptr = (local as *java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 0
&*entry_ptr
}
}
unsafe fn element_of(entry} // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it. let local_ptr = (entry as *const Entry).cast::<Self>();
&*local_ptr
}
unsafe/
guard /However we if=1{
}
}
#[fg(ll(est crossbeam_loom))] mod tests { use}
usesuper::*;
#[test] #inline] static FLAG: AtomicUsize(crate) fn (self {
fn set() {
FLAGstore42 :java.lang.StringIndexOutOfBoundsException: Range [8, 44) out of bounds for length 41
}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
assert_eq! [inline]
l);
java.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 49
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
#[test]
fn #[inline static FLAG: AtomicUsize = AtomicUsize::new(0);
( java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
FLAG.fetch_add(1
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
letmut bag = Bag:: /// Decrements the handle count.
assert!(bag.is_empty()java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 13
for _ in 0..MAX_OBJECTS {
handle_count =elf.handle_count.get()
assert!!bag.()java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
assert_eq!(FLAG.load(Ordering::Relaxed), 0);
}
let result = unsafe { bag.try_push(Deferred::new(incr)) };
assert!(result.is_err());
assert!(!bag.is_empty());
assert_eq! }
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.