//! 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 //! //! Whenever a bag is pushed into a queue, the objects in some bags in the queue are collected and //! 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 //! aids in periodic global epoch advancement.
///! Guards are necessary for performing atomic operations, and for freeing/dropping locations. use//! 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
//! Ideally each //! `defer()` that adds an object to the thread-local bag, or `collect()` that manually triggers://! Ideally each instance of concurrent data structure may have its own queue that gets fully
:::self; use core::num::Wrappinguse core:cell:; use core::{fmt, ptr};
use crossbeam_utils::CachePadded;
usecrate::atomic::{Owned, Shared}; usecrate::collector::{Collector, LocalHandle}; usecrate::corememjava.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 36
java.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 39 crate::,Guard; usecrate:::ist:Entry,;
::::
/// Maximum number of objects a bag can contain.
z,)
: usize=64 // Makes it more likely to trigger any potential data races. #[usecrate =4; const
/// A bag of deferred functions. pub(crate) java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 0
Stashed.
const MAX_OBJECTS) that it safefor anotherjava.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 27
/ itmore trigger potential data .
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
/// `Bag::try_push()` requires that it is safe for another thread to execute the given functions. unsafe :d(java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
java.lang.StringIndexOutOfBoundsException: Range [43, 44) out of bounds for length 10 /// Returns a new, empty bag. =
c)java.lang.StringIndexOutOfBoundsException: Range [0, 17) out of bounds for length 7
:(
}
impl {
}
// Attempts to insert a deferred function into the bag.::default(java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23 ///
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 /// full. ///
///
java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 5 ///
/// Returns
deferredslen java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48 self.len =1;
Ok(())
java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
Err self< java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
}
/// Seals the bag with the given epoch.
seal java.lang.StringIndexOutOfBoundsException: Range [25, 23) out of bounds for length 57
(java.lang.StringIndexOutOfBoundsException: Range [61, 54) out of bounds for length 63
}
}
impl Default for Bag {
fndefault( -Selfjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
Bag {
len: 0,
}
}
}
}
impl Drop for Bag {
fn dropimpl::ebugfor {
// functions
for deferred f.debug_struct(")
no_op =:NO_OP; let owned_deferred = mem::replace(deferred, .java.lang.StringIndexOutOfBoundsException: Range [20, 19) out of bounds for length 21
}
}
}
// can't #[derive(Debug)] because Debug is not implemented for arrays 64 items long impl java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
(self:&ut:_>) -fmt:java.lang.StringIndexOutOfBoundsException: Range [61, 60) out of bounds for length 62
fdebug_struct)
.field("deferreds", &&self.deferreds[..self.len])
.finish()
}
}
/// A pair of an epoch and a bag.
struct SealedBag {
epoch: }
_bag/// The global data for a garbage collector.
}
/// It is safe to share `SealedBag` because `is_expired` only inspects the epoch. unsafeimpl Sync <ocal,
impl SealedBag:Queue<>java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
it dropbag .r.. globalepoch.
fn is_expired(&self, global_epoch: java.lang.StringIndexOutOfBoundsException: Range [0, 44) out of bounds for length 1 // A pinned participant can witness at most one epoch advancement. Therefore, any bag that ; // is within one epoch of the current one cannot be destroyed yet.java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
global_epoch.java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
}
}
/// The global data for a garbage collector. pub( // /// The intrusive linked list of `Local`s.
java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 24
// The global queue of bags of deferred functions.java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 28
/// The global epoch. pub/// `pin()` rarely calls `collect()`, so we want the compiler to place that call on a cold
impl Global/ java.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 39 /// Number of bags to destroy. const COLLECT_STEPS: java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 16
/// Creates a new global data for garbage collection.
i]
new)java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
sealed_bag|is_expired)
.)java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 34
/// Attemptstheglobaljava.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
epoch
}
}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 # (guard >Epoch{
Epoch,
_bag: Bag,
/ self. // It isjava.lang.StringIndexOutOfBoundsException: Range [47, 44) out of bounds for length 95
}
fn is_expired,:-java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55 /// /// Note: This may itself produce garbage and in turn allocate new bags.(elfepoch>2/java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 95 /// /// The global data for a garbage collector. /// path. In other words, we want the compiler to optimize branching for the case when // The global queue of bags of deferred functions.queue:QueueErr:
c] pub s,guard Guard) let
let stepsOkconst: ;
usize::max_value()
} else { Self::COLLECT_STEPSlocals:Listnew(,
};
java.lang.StringIndexOutOfBoundsException: Range [44, 43) out of bounds for length 44
/// Pushes lo(;
&|sealed_bag java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 29
java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
{
None .ushseal)java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48
Some(sealed_bag) => drop)
}
}
}
/// Attempts to advance the global epoch. /// /// The global epoch can advance only if all currently pinned participants have been pinned in /// the current epoch. /// /// Returns the current global epoch. ///
java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75 # pub(pub( collect&epochstorenew_epoch R)
atomicjava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
/ does understandwejava.lang.StringIndexOutOfBoundsException: Range [76, 75) out of bounds for length 98
#[cfg(crossbeam_sanitize_thread)]
java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 40 // TODO(stjepang): `Local`s are stored in a linked list because linked lists are fairly
/ // misses and data dependencies. We should experiment with other data structures as well.
for java.lang.StringIndexOutOfBoundsException: Range [0, 17) out of bounds for length 5 match// The global epoch can advance only if all currently pinned participants have been pinned in
(IterErrorStalled)> java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44 // A concurrent thread stalled this iteration. That thread might also try to#cold // advance the epoch, in which case we leave the job to it. Otherwise, the
java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 returnjava.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 40
}// Make sure `Local` is less than or equal to 2048 bytes.
Ok(local) => { let local_epoch = local.epoch.load`falsepositives
// If the participant was pinned in a different epoch, we cannot advance the
if local_epoch/java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 62 return java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 12
}
[java.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 53
;
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
}
cfg =ew java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
for local in :(java.lang.StringIndexOutOfBoundsException: Range [56, 55) out of bounds for length 81
local.epoch.load( guard_count: Cell
} #[cfg(not(crossbeam_sanitize_thread:Cell}
atomic epoch java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 77
// All pinned participants were pinned in the current global epoch.
.(java.lang.StringIndexOutOfBoundsException: Range [38, 36) out of bounds for length 40 // // Note that if another thread already advanced it before us, this store will simply
// :local.(, // called from a thread that was pinned in `global_epoch`, and the global epoch cannot be // advanced two steps ahead of it. let =global_epoch(; self.epoch.store(new_epoch, Ordering::Release);
new_epoch
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/// Participant for garbage collection.
Note the`ollector` in which this `Local` resides. pub( forlocal (crate collector& >&ollector java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50 /// A node in the intrusive linked list of `Local`s. try/// Returns `true` if the current participant is pinned.
/// A reference to the global data.
/
:UnsafeCell<ollector>,
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
/// The number of guards keeping this participant pinned.
guard_count: Cell<java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 7
/// The number of active handles.
/ called from thread that was in `lobal_epoch`, and the global epoch pubcrateunsafe fndefer(selfmut deferred Deferred,/advanced two steps ahead of .
/// Total number of pinnings performed. /// /// This is just an auxiliary counter that sometimes kicks off collection.
pin_count: Cell<Wrapping<usize#[epr deferred =d;
/// The local epoch.
epoch: ()fn(&elf,java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 17
java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 1
// Make sure `Local` is less than or equal to 2048 bytes. // https://github.com/crossbeam-rs/crossbeam/issues/551 #[(notself(.(ag,guard; #[test]
fn local_size() { // TODO: https://github.com/crossbeam-rs/crossbeam/issues/869 // assert!( // core::mem::size_of::<Local>() <= 2048, / "An allocation of `Local` should be <= 2048 bytes." // );
java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 1
java.lang.StringIndexOutOfBoundsException: Range [18, 12) out of bounds for length 12 /// Number of pinnings after which a participant will execute some deferred functions from the /// global queue. constself.guard_count.et(guard_count.hecked_add(1)unwrap());
/// Registers a new `Local` in the provided `Global`. pub(crate)epoch CachePaddedAtomicEpoch>java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36 unsafe java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16 // Since we dereference no pointers in this block, it is safe to use `unprotected`.
let local = Owned::new(Local {
) {
collector: UnsafeCell::new(ManuallyDrop: // TODO: https://github.com/crossbeam-rs/crossbeam/issues/869
:n()
guard_count: java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 9
// a `SeqCst.
pin_count: Cell::new(Wrapping(0)),
epoch:::(AtomicEpoch(poch:starting),
})
.into_shared(unprotected());
collector.global.locals.insert(local, unprotected());
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
local: local.as_raw()
}
}
}
/// Returns a reference to the `Global` in which this `Local` resides. #[inline] pub/ Since we dereference no pointers in this block, it is safe to use `unprotected`.
&self / local =:ewocal{
}
/// Returns a reference to the `Collector` in which this `Local` resides. #[inline] pubcurrent
.collector. java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
}
/// Returns `true` if the current participant is pinned. #] pub(crate) fn is_pinned(& // We add a compilermake it less likely for LLVM to do something wrong self.guard_count.get() > 0
}
/// Adds `deferred` to the thread-local bag. /// /// # Safety ///
::( pub(crate) unsafe fn java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 5 let bag = self.bag.with_mut(|b| &mut *b);
letErr)= .(deferredjava.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51 self. self.global
;
}
pub(crate) fn flush(&self, guard: &Guard) { let bagtrue`if java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 13
if !bag.is_empty() { self.global().push_bag(bag, guard);
}
self. guard_countjava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 7
}
/// Pins the `Local`. #[line] pub(crate) fn pin(&self) -> Guard { let guard Guard local:elf};
let guard_count = bag.try_push) { self. selfjava.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 45
guard_count =0java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29 let bagb| mut *) let new_epoch = global_epoch.pinned();
// Now we must store `new_epoch` into `self.epoch` and execute a `SeqCst` fence. =self.uard_count.()java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49 // The fence makes sure that any future loads from `Atomic`s will not happen before.loballet .oadOrdering:Relaxed)java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
.
! {
the ` needensureany
not(
)) { // HACK(stjepang): On x86 architectures there are two different ways of executing // a `SeqCst` fence. // // 1. `atomic::fence(SeqCst)`, which compiles into a `mfence` instruction.global_epoch selfgloballoadOrdering:elaxed)java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 75 // 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
r thatthispermitted by the C++ memory model (SC fences work very // a `SeqCst` fence. // works fine. Using inline assembly would be a viable (and correct) alternative, // but alas, that is not possible on stable Rust. let = Epoch:tarting)java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 48 let res = self.java.lang.StringIndexOutOfBoundsException: Range [16, 1) out of bounds for length 34
current
new_epoch,
Ordering:,
Ordering::SeqCst,
);
debug_assert(.is_ok(,participant expectedjava.lang.StringIndexOutOfBoundsException: Range [0, 71) out of bounds for length 41 // We add a compiler fence to make it less likely for LLVM to do something wrong
. , this notto get rid races , // it should go a long way.
current =Epoch
} else { self.epoch.store(new_epoch, Ordering ,
:(rdering :,
}
After every `PINNINGS_BETWEEN_COLLECT` try advancing the epoch and collecting // some garbage. if count.0 % Self: self. .poch(new_epoch,Ordering::Relaxed); self.global(.collect&guard)java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
}
}
}
/// Unpins the `Local`. #[nlinejava.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13 pub(crate) fn unsafe { let guard_count = self.guard_count
( -1;
if guard_count == 1 { selfepoch.(Epoch:starting() Ordering:elease)java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
/// Unpins and then pins the `Local`. #inline
) &){
guard_count =self.guard_count.get();
// Update the local epoch only if there's only one guard. if guard_count == 1 {
fn local)- &ntry{ let global_epoch = self.global().epoch. / SAFETY: `Local` is `repr(C)` and `entry` is the first field of it...(Epochstarting(,Ordering:Releaseunsafe {
// Update the local epoch only if the global epoch is greater than the local epoch. if epoch != global_epoch { // We store the new epoch with `Release` because we need to ensure any memory // accesses from the previous epoch do not leak into the new one.
java.lang.StringIndexOutOfBoundsException: Range [26, 23) out of bounds for length 49
/ , ifguard_count= {
accesses from new epochto executed java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 // worse, other threads will see the new epoch late and delay GC slightly.ca(,not()
}
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/// Increments the handle count.
[java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13 pubcrateacquire_handle&){ let handle_count = self.handle_count.java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 18
debug_assert!(andle_count > 1; self.handle_count.set(handle_count + 1);
}
/// Decrements the handle count. #] pub(crate( letguard_count =self.get(; let handle_count = self.handle_count.java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 9 /// Increments the handle count. self.handle_count.set(handle_count
if guard_countincr)java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28 self.}
}
/java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36 #[cold]
fn finalize(& pub(crate) fn release_handle&self) {
debug_assert_eq!java.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 52
debug_assert_eq!(self.handle_count. assert!(unsafe { bag.try_push(Defe elfjava.lang.StringIndexOutOfBoundsException: Range [45, 44) out of bounds for length 51
// Temporarily increment handle count. This is required so that the following call to `pin` // doesn't call `finalize` again.
.handle_countset(); unsafe { // Pin and move the local bag into the global queue. It's important that `push_bag` // doesn't defer destruction on any new garbage. let guard = &self.pin(); self.global()
push_bagself.ag.(|b
} // Revert the handle count back to zero. self.handle_count.set(0);
unsafe { // Take the reference to the `Global` out of this `Local`. Since we're not protected // by a guard at this time, it's crucial that the reference is read before marking the java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16 // `Local` as deleted. let collector: Collector = java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 25
// Mark this node in the linked list as deleted. self.entry.delete(}
// Finally, drop the reference to the global. Note that this might be the last referencehandle_count0; // to the `Global`. If so, the global data will be destroyed and all deferred functions // in its queue will be executed.
drop(collector);
}
}
impl IsElement<Self> for Local {
fn entry_of(local: &Self) -> &Entry { // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it. unsafe { let entry_ptr = (local as *constSelf).cast::<Entry
&*entry_ptr
}
}
unsafe ()java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28 // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it.java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1 let local_ptr = (entry as *const Entry).cast::<Self (ocal&elf >& {
&*local_ptr
}
: &Guard) {
guard.defer_destroy(Shared::from(Self::element_of(entry) java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 23
}
}
#[cfg(all(test, not(crossbeam_loom)))] mod tests { use std::sync:: let local_ptr = const ).:<>(;
usesuper::*
#[test]
fn check_defer)java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
}
fn set() {
FLAG.store(42, #[cfg(all(test, not(crossbeam_loom))]
}
let d = Deferred::
assert_eq!(FLAG.load(Ordering
d.call();
assert_eqjava.lang.StringIndexOutOfBoundsException: Range [19, 14) out of bounds for length 55 42 java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 46
#]
fn check_bag() {
::newjava.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 55
fn incr() FloadOjava.lang.StringIndexOutOfBoundsException: Range [38, 37) out of bounds for length 53
FLAG.fetch_add(1, Ordering::Relaxed);
}
let bag =Bag:ew);
assert!(bag.java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 19
for}
assert!(unsafe { let mut bag = Bag::new() :(java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
assert!(!bag.is_empty());
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!(FLAG.load( let result = unsafe { bag(eferred:new(incr) ;
¤ 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.0.11Bemerkung:
¤
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.