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:

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>

source

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?
examples/map_as.rs (line 33)
32
33
34
35
36
37
38
39
40
fn main() {
    let guard = CollectionGuard::acquire();
    let gced: Ref<SomeType> = Ref::new(SomeType, &guard);
    let type_erased: AnyRef = gced.as_any();
    type_erased
        .load_mapped::<dyn SomeTrait>(&guard)
        .unwrap()
        .do_something();
}
More examples
Hide additional examples
examples/allocate_a_lot.rs (line 10)
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();
                }
            });
        }
    });
}
examples/trace.rs (line 12)
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);
}
examples/basic.rs (line 5)
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);
}
source

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<'_>

source

pub fn allocating_in<'a>(&self, pool: &'a LocalPool) -> CollectionGuard<'a>

Returns a guard that allocates from pool.

source

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?
examples/trace.rs (line 18)
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
Hide additional examples
examples/basic.rs (line 27)
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);
}
source

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.

source

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?
examples/allocate_a_lot.rs (line 15)
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();
                }
            });
        }
    });
}
source

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.

source

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.

source

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.

Trait Implementations§

source§

impl<'a> AsMut<CollectionGuard<'a>> for CollectionGuard<'a>

source§

fn as_mut(&mut self) -> &mut CollectionGuard<'a>

Converts this type into a mutable reference of the (usually inferred) input type.
source§

impl<'a> AsRef<CollectionGuard<'a>> for CollectionGuard<'a>

source§

fn as_ref(&self) -> &CollectionGuard<'a>

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Drop for CollectionGuard<'_>

source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for CollectionGuard<'a>

§

impl<'a> !RefUnwindSafe for CollectionGuard<'a>

§

impl<'a> !Send for CollectionGuard<'a>

§

impl<'a> !Sync for CollectionGuard<'a>

§

impl<'a> Unpin for CollectionGuard<'a>

§

impl<'a> !UnwindSafe for CollectionGuard<'a>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<A> Cast for A

source§

fn cast<To>(self) -> To
where To: CastFrom<A>,

Casts self to the To type. This may be a lossy operation.
source§

impl<A> CastFrom<A> for A

source§

fn from_cast(from: A) -> A

Returns from as Self.
source§

impl<A, B> CastInto<A> for B
where A: CastFrom<B>,

source§

fn cast_into(self) -> A

Returns self as To.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.