Struct refuse::CollectionGuard
source · pub struct CollectionGuard<'a> { /* private fields */ }Expand description
A guard that prevents garbage collection while held.
To perform garbage collection, all threads must be paused to be traced. A
CollectionGuard allows the ability to read garbage-collectable data by
ensuring the garbage collector can’t run while it exists.
To ensure the garbage collector can run without long pauses, either:
- Acquire
CollectionGuards for short periods of time, dropping the guards when not needed. - Call
CollectionGuard::yield_to_collector()at a regular basis. This function is very cheap to invoke if the collector is not trying to acquire the lock.
This type should not be held across potentially blocking operations such as
IO, reading from a channel, or any other operation that may pause the
current thread. CollectionGuard::while_unlocked() can be used to
temporarily release a guard during a long operation.
Implementations§
source§impl CollectionGuard<'static>
impl CollectionGuard<'static>
sourcepub fn acquire() -> Self
pub fn acquire() -> Self
Acquires a lock that prevents the garbage collector from running.
This guard is used to provide read-only access to garbage collected allocations.
It is safe to acquire multiple guards on the same thread. The collector will only be able to run when all guards have been released.
Examples found in repository?
More examples
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
fn main() {
std::thread::scope(|s| {
for _ in 0..16 {
s.spawn(|| {
let mut guard = CollectionGuard::acquire();
for _ in 0..100 {
for _ in 0..100 {
Ref::new([0; 32], &guard);
}
guard.yield_to_collector();
}
});
}
});
}11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
fn main() {
let mut guard = CollectionGuard::acquire();
let message = Ref::new(String::from("Hello!"), &guard);
let error = Root::new(Error { message }, &guard);
// Because `error` is a Root and refers to the message,
guard.collect();
assert_eq!(message.load(&guard).expect("still alive"), "Hello!");
// After we drop the Root, the message will be able to be collected.
drop(error);
guard.collect();
assert_eq!(message.load(&guard), None);
}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
fn main() {
let guard = CollectionGuard::acquire();
// Allocate a vec![Ref(1), Ref(2), Ref(3)].
let values: Vec<Ref<u32>> = (1..=3).map(|value| Ref::new(value, &guard)).collect();
let values = Root::new(values, &guard);
drop(guard);
// Manually execute the garbage collector. Our data will not be freed,
// since `values` is a "root" reference.
refuse::collect();
// Root references allow direct access to their data, even when a
// `CollectionGuard` isn't held.
let (one, two, three) = (values[0], values[1], values[2]);
// Accessing the data contained in a `Ref` requires a guard, however.
let mut guard = CollectionGuard::acquire();
assert_eq!(one.load(&guard), Some(&1));
assert_eq!(two.load(&guard), Some(&2));
assert_eq!(three.load(&guard), Some(&3));
// Dropping our root will allow the collector to free our `Ref`s.
drop(values);
guard.collect();
assert_eq!(one.load(&guard), None);
}sourcepub fn try_acquire() -> Option<Self>
pub fn try_acquire() -> Option<Self>
Tries to acquire a lock that prevents the garbage collector from running.
The function will return None if the collector is attempting to run garbage collection, and this thread is not already guarded.
This guard is used to provide read-only access to garbage collected allocations.
It is safe to acquire multiple guards on the same thread. The collector will only be able to run when all guards have been released.
source§impl CollectionGuard<'_>
impl CollectionGuard<'_>
sourcepub fn allocating_in<'a>(&self, pool: &'a LocalPool) -> CollectionGuard<'a>
pub fn allocating_in<'a>(&self, pool: &'a LocalPool) -> CollectionGuard<'a>
Returns a guard that allocates from pool.
sourcepub fn collect(&mut self)
pub fn collect(&mut self)
Manually invokes the garbage collector.
This method temporarily releases this guard’s lock and waits for a garbage collection to run. If a garbage collection is already in progress, this function will return when the in-progress collection completes. Otherwise, the collector is started and this function waits until the collection finishes.
Finally, the guard is reacquired before returning.
§Panics
This function will panic if any other CollectionGuards are held by
the current thread when invoked.
Examples found in repository?
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
fn main() {
let mut guard = CollectionGuard::acquire();
let message = Ref::new(String::from("Hello!"), &guard);
let error = Root::new(Error { message }, &guard);
// Because `error` is a Root and refers to the message,
guard.collect();
assert_eq!(message.load(&guard).expect("still alive"), "Hello!");
// After we drop the Root, the message will be able to be collected.
drop(error);
guard.collect();
assert_eq!(message.load(&guard), None);
}More examples
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
fn main() {
let guard = CollectionGuard::acquire();
// Allocate a vec![Ref(1), Ref(2), Ref(3)].
let values: Vec<Ref<u32>> = (1..=3).map(|value| Ref::new(value, &guard)).collect();
let values = Root::new(values, &guard);
drop(guard);
// Manually execute the garbage collector. Our data will not be freed,
// since `values` is a "root" reference.
refuse::collect();
// Root references allow direct access to their data, even when a
// `CollectionGuard` isn't held.
let (one, two, three) = (values[0], values[1], values[2]);
// Accessing the data contained in a `Ref` requires a guard, however.
let mut guard = CollectionGuard::acquire();
assert_eq!(one.load(&guard), Some(&1));
assert_eq!(two.load(&guard), Some(&2));
assert_eq!(three.load(&guard), Some(&3));
// Dropping our root will allow the collector to free our `Ref`s.
drop(values);
guard.collect();
assert_eq!(one.load(&guard), None);
}sourcepub fn try_collect(&mut self) -> Result<(), WouldDeadlock>
pub fn try_collect(&mut self) -> Result<(), WouldDeadlock>
Manually invokes the garbage collector.
This method temporarily releases this guard’s lock and waits for a garbage collection to run. If a garbage collection is already in progress, this function will return when the in-progress collection completes. Otherwise, the collector is started and this function waits until the collection finishes.
Finally, the guard is reacquired before returning.
§Errors
If another CollectionGuard is held by the current thread,
WouldDeadlock will be returned and unlocked will not be invoked.
sourcepub fn yield_to_collector(&mut self)
pub fn yield_to_collector(&mut self)
Yield to the garbage collector, if needed.
This function will not yield unless the garbage collector is trying to acquire this thread’s lock. Because of this, it is a fairly efficient function to invoke. To minimize collection pauses, long-held guards should call this function regularly.
If any other guards are currently held by this thread, this function does nothing.
Examples found in repository?
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
fn main() {
std::thread::scope(|s| {
for _ in 0..16 {
s.spawn(|| {
let mut guard = CollectionGuard::acquire();
for _ in 0..100 {
for _ in 0..100 {
Ref::new([0; 32], &guard);
}
guard.yield_to_collector();
}
});
}
});
}sourcepub fn coordinated_yield(
&mut self,
yielder: impl FnOnce(Yielder<'_>) -> YieldComplete
)
pub fn coordinated_yield( &mut self, yielder: impl FnOnce(Yielder<'_>) -> YieldComplete )
Perform a coordinated yield to the collector, if needed.
This function is useful if the code yielding has held locks that the
garbage collector might need during the tracing process. Instead of
always unlocking the locks before calling
Self::yield_to_collector(), this function can be used to only
release the local locks when yielding.
If this function detects that it should yield to the collector,
yielder will be invoked. The function can do whatever else is needed
before waiting for the collector to finish, and then invoke
Yielder::wait().
If this function does not yield, yielder is not invoked.
This function will not yield unless the garbage collector is trying to acquire this thread’s lock. Because of this, it is a fairly efficient function to invoke. To minimize collection pauses, long-held guards should call this function regularly.
If any other guards are currently held by this thread, this function does nothing.
sourcepub fn while_unlocked<R>(&mut self, unlocked: impl FnOnce() -> R) -> R
pub fn while_unlocked<R>(&mut self, unlocked: impl FnOnce() -> R) -> R
Executes unlocked while this guard is temporarily released.
§Panics
This function will panic if any other CollectionGuards are held by
the current thread when invoked.
sourcepub fn try_while_unlocked<R>(
&mut self,
unlocked: impl FnOnce() -> R
) -> Result<R, WouldDeadlock>
pub fn try_while_unlocked<R>( &mut self, unlocked: impl FnOnce() -> R ) -> Result<R, WouldDeadlock>
Executes unlocked while this guard is temporarily released.
§Errors
If another CollectionGuard is held by the current thread,
WouldDeadlock will be returned and unlocked will not be invoked.