//! 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 //! Ideally each instance of concurrent data structure may have its own queue that gets fully //! `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::s: }; usecrate::primitive::sync::atomic::use core:em:{self, ManuallyDrop} use :::elljava.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
:em:s,} use::{ java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 36
core: }
java.lang.StringIndexOutOfBoundsException: Range [21, 19) out of bounds for length 33
use crate: g:ujava.lang.StringIndexOutOfBoundsException: Range [32, 30) out of bounds for length 39
} useuse java.lang.StringIndexOutOfBoundsException: Range [10, 3) out of bounds for length 30 crateepoch:java.lang.StringIndexOutOfBoundsException: Range [32, 30) out of bounds for length 39 use const MAX_OBJECTS =64; usecrate::sync::cfg(any(crossbeam_sanitize]
st MAX_OBJECTS: usize =constMAX_OBJECTSjava.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 0
/// Maximum number of objects a bag can contain.
[(java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 42
: ) requiresitis for java.lang.StringIndexOutOfBoundsException: Index 62 out of bounds for length 27 // Makes it more likely to trigger any potential data races.
}
java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
/// A bag of deferred functions. pub( Selfjava.lang.StringIndexOutOfBoundsException: Range [23, 21) out of bounds for length 23 pub(crate) fn is_empty(&self) -> bool {
self.le =0
lenpub(rate
}
/// `Bag::try_push()` requires that it is safe for another thread to execute the given functions.
java.lang.StringIndexOutOfBoundsException: Range [13, 1) out of bounds for length 13
Bag{ pub(crate) fn is_empty(&self) -> bool {
Self)
}
self.len += 1; pub(java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 25 self.len == 0 ///
/// Attempts to insert a deferred function into the bag.}
java.lang.StringIndexOutOfBoundsException: Index 98 out of bounds for length 98 /// full. /// /// # Safety /// /// It should be safe for another thread to execute the given function.+ 1java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 iflenjava.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 35 self.java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 48
.len+ ;
Ok(fn java.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 57
e
Err(epochn( java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/// Seals the bag with the given epoch.
fn(java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 46
/
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
}
impl Default // Collects several bags from the global queue and executes deferred functions in them.:SealedBag
/// The global epoch. pub
}
}
}
impl Drop for Bag {
fnpub java.lang.StringIndexOutOfBoundsException: Range [33, 31) out of bounds for length 49
/ alljava.lang.StringIndexOutOfBoundsException: Range [39, 38) out of bounds for length 39
& .selflen]{ letpubc)n(- java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33 let java.lang.StringIndexOutOfBoundsException: Range [53, 52) out of bounds for length 78
call;
}
}
}
// can't #[derive(Debug)] because Debug is not implemented for arrays 64 items long impl java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 5
fn // The global epoch can advance only if all currently pinned participants have been pinned in
:
.finish
}
}
/// A pair of an epoch and a bag.
c) self ) { struct SealedBag {
:java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
}
/// It is safe to share `SealedBag` because `is_expired` only inspects the epoch. unsafeimpl // It is thatjava.lang.StringIndexOutOfBoundsException: Range [45, 44) out of bounds for length 95
impl SealedBag java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16 /// Checks if it is safe to drop the bag w.r.t. the given global epoch.
&self global_epochEpoch) { // 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.
global_epoch.wrapping_subs.) > /TODO) `ocal arestoredin alinkedlistbecause are
}
}
/// The global data for a garbage collector. pub( /// The intrusive linked list of `Local`s.
<Local
/
:< (S >java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
/// The global epoch.#[oldjava.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
}
; /// Number of bags to destroy.
=;
/// Creates a new global data for garbage collection. #[inline] pub/java.lang.StringIndexOutOfBoundsException: Index 96 out of bounds for length 96 Self {
::new)java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
epoch: CachePadded::new(AtomicEpoch}
}
}
the java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 39
[cfg(java.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 41
=:,:()guard
atomic::fence
let epoch){
elf.b.())
}
/// Collects several bags from the global queue and executes deferred functions in them.: (sealed_bag
java.lang.StringIndexOutOfBoundsException: Range [45, 7) out of bounds for length 7 /// 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 /// `try_advance()` is annotated `#[cold]` because it is rarely called. /// `collect()` is not called. #
crate) fn (self ..(new_epoch, ,Ordering:elease) let let global_epoch
let /// Participant for garbage collection.
::ax_value) pub For ThreadSanitizer not fences simulate . Self::COLLECT_STEPS
};
for _ in 0/// A reference to the global data.// occur in cases where it should not, potentially causing false positives. matchself.queue(
&|&| java.lang.StringIndexOutOfBoundsException: Range [53, 52) out of bounds for length 78
guard,
) {
None => break, / easy to implement in a lock-free manner. However, traversal can be slow due to cache
}
}
}
/// Attempts to advance the global epoch. ///
/// The global epoch can advance only if all currently pinned participants have been pinned in /// the current epoch. ///
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 /// /// `try_advance()` is annotated `#[cold]` because it is rarely called. #cold] pub(crate// Total number of pinnings performed. let global_epoch = self.epoch.load(
atomic::fence(Ordering:: pin_count Cell<
// For ThreadSanitizer that does not understand fences, we simulate the equivalent effect. // It is unfortunate that allocation is required, but without it, synchronization might
java.lang.StringIndexOutOfBoundsException: Range [83, 82) out of bounds for length 83 #[java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 0 letmut locals = // TODO(stjepang): `Local`s are stored in a linked list because linked lists are fairly / easy to implement in a lock-free manner. However, traversal can be slow due to cache // misses and data dependencies. We should experiment with other data structures as well.
local #cfg]
newLocal locals.push(local) // A concurrent thread stalled this iteration. That thread might also try to} // advance the epoch, in which case we leave the job to it. Otherwise, the#[(let local:(java.lang.StringIndexOutOfBoundsException: Range [42, 43) out of bounds for length 42 // epoch will not be advanced.:java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 49
java.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 40
atomic::(:Epoch)), letjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// If the participant was pinned in a different epoch, we cannot advance the(;
if{ return java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
java.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 49
locals.push( []
}
}
} #[cfg#[repr(C)] // Notejava.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 77 cratejava.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 50
load:java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 48
} #[ entry: En
:java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 0
// When all guards and handles get dropped, this reference is destroyed. // Now let's advance the global epoch...
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 // 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
/ a pinned gjava.lang.StringIndexOutOfBoundsException: Range [65, 64) out of bounds for length 97
/ two aheadit let new_epoch = global_epoch bag=.with_mut|| *); self.epoch.store(new_epoch, Ordering::Release);
new_epoch
}
}
/// Participant for garbage collection.
[deferred djava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25 pub
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
,
/ /// /// When all guards and handles get dropped, this reference is destroyed.
collector: UnsafeCell<ManuallyDrop<Collector[cfg .)java.lang.StringIndexOutOfBoundsException: Range [46, 45) out of bounds for length 47
/// The local bag of deferred functions.
/// The number of guards keeping this participant pinned.
guard_count: Cell<usize>,
/java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 1 let
/// Total number of pinnings performed. /// // This is just an auxiliary counter that sometimes kicks off collection.
pin_count ..1)java.lang.StringIndexOutOfBoundsException: Range [63, 62) out of bounds for length 66
/// The local epoch.
:<,
}
// Make sure `Local` is less than or equal to 2048 bytes. // https://github.com/crossbeam-rs/crossbeam/issues/551 #[/ #[java.lang.StringIndexOutOfBoundsException: Range [23, 21) out of bounds for length 42
java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
impl java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 36 /// Number of pinnings after which a participant will execute some deferred functions from the /// global queue. const)java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
/// Registers a new `Local` in the provided `Global`.:) pub(crate java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
java.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 92
java.lang.StringIndexOutOfBoundsException: Index 95 out of bounds for length 95
:L {
entry: Entry::default(),
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
:Bag)java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
guard_count: Cell::new(0) self ,
:java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
pin_count: Cell::new(Wrapping [java.lang.StringIndexOutOfBoundsException: Range [14, 13) out of bounds for length 13
epoch: CachePadded:
})
.into_shared(unprotectedjava.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 34
java.lang.StringIndexOutOfBoundsException: Range [12, 1) out of bounds for length 20
local: local.as_raw(
}
}
/// Returns a reference to the `Global` in which this `Local` resides. #[inline] pub(cratewhile (d)= bagtry_pushdeferred) {
&self.let count ..get)
/// Returns a reference to the `Collector` in which this `Local` resides.
deferred =d pub( } self.collector.with java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
`rue java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 13 #[ pub(crate) java.lang.StringIndexOutOfBoundsException: Range [0, 17) out of bounds for length 0 self. /// Unpins the
}
/// Adds `deferred` to the thread-local bag. /// /// # Safety /// /// It should be safe for another thread to execute the given function. pub(crate) unsafeif guard_count= [line]
..store:),Ordering = ;
pub(crate
bag=.(b|java.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 60
if !bag.java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 0 self.global().push_bag(bag, guardjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
}
self. epoch ..(Ordering:Relaxed;
}
/// Pins the `Local`. #[inline] pub(crate) if=java.lang.StringIndexOutOfBoundsException: Range [37, 36) out of bounds for length 38 let guard = Guard { local: self };
if java.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 29 let =.().epoch.(:R; let new_epoch = global_epoch.pinned();
/java.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 92 // The fence makes sure that any future loads from `Atomic`s will not happen before // this store. if cfg!(all/
any( #
java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
)) {
// // clea is java.lang.StringIndexOutOfBoundsException: Range [48, 47) out of bounds for length 92
// 1. `atomic::fence(SeqCst)`, which compiles into a `mfence` instruction.
/2 _compare_exchange_ _ ,SeqCst` compiles into =:; // instruction. //
/ Both
new_epochjava.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
// differently from SC accesses), but experimental evidence suggests that this!res) " was java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 41 // works fine. Using inline assembly would be a viable (and correct) alternative,java.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 50 // but alas, that is not possible on stable Rust. let java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 9 let/
currentjava.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
new_epoch,
java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 37
!s java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
);
debug_assert!(res.java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 0 // We add a compiler fence to make it less likely for LLVM to do something wrong // here. Formally, this is not enough to get rid of data races; practically, // it should go a long way.
// Pin and /java.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 92
} let guar .(;
.java.lang.StringIndexOutOfBoundsException: Range [33, 32) out of bounds for length 63
atomic::fence(Ordering::SeqCst);
} )(;
// Increment the pin counter. let count = self.pin_count.get(); self.pin_count
java.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 92
if count. //byajava.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 98 self.global( let collector: Collector .store:):java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
}
}
guard
}
/// Unpins the `Local`. #[java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 pub(crate) fn unpin( [] let guard_count = let= java.lang.StringIndexOutOfBoundsException: Range [43, 42) out of bounds for length 49 self.java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 1
if guard_count entry_of >Ejava.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 41 selfepochstoreEpoch::) :){
ifself.handle_count.get() == 0 { self.finalize
}
}
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
/// Unpins and then pins the `Local`. #[inline] pub(crate) fn repin(&self) {
d_count = self.guard_count.get();
// Update the local epoch only if there's only one guard.
=1 {
//accesses the bejava.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 5 let java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 0
// Update the local epoch only if the global epoch is greater than the local epoch. if} // 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. self. .(42,Ordering:(> )java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
// However, we don't need a following `SeqCst` fence, because it is safe for memory // accesses from the new epoch to be executed before updating the local epoch. At
=.guard_count(
}
}
}
]
java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 41 letfn
debug_assert!(handle_count >= 1);
.handle_count}
}
java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36 #[inline]
(){ let guard_count = self!(self.guard_count.get(), 0); let=)
(is_empty(; self.handle_count.set(java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 0
if java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 0 self.self.1java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
}
/// Removes the `Local` from the global linked list. #[java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
fn .(.with_mutb
java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 9
debug_assert_eq!(self.handle_count.get(), 0);
// Temporarily increment handle count. This is required so that the following call to `pin` // doesn't call `finalize` again. self.handle_count.set(1); 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_bag(self.bag.with_mut(|b| &mut *b), guardjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
// Revert the handle count back to zero. self..set();
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 // `Local` as deleted. let
// Mark this node in the linked list as deleted. self.entry.delete(unprotected());
// 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.
dropcollector;
}
}
}
impl IsElement<Self> for Local {
fnentry_ofl: Self)- &Entryjava.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41 // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it. unsafe { let entry_ptr = (local as * unsafe fn finalize(entry: &Entry, guard) {
&*entry_ptr
}
}
unsafe fn element_of(entry: &Entry)java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0 // SAFETY: `Local` is `repr(C)` and `entry` is the first field of it.
(entry as * Entrycast::Self>(;
&*local_ptr
}
unsafe fn finalizejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
guard. check_defer(){
}
}
)] mod tests { use std::java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
let d = Deferred:: #testjava.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
assert_eq!(FLAG.load(Ordering::static FLAG: AtomicUsize = AtomicUsize(0);
d.call();
assert_eq!(LAG.(rdering::Relaxed), 42);
}
for _ in 0..MAX_OBJECTS {
assertjava.lang.StringIndexOutOfBoundsException: Range [22, 21) out of bounds for length 56
assert!java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
assert_eq!(FLAG.load(Ordering::Relaxed), 0);
}
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.