94 lines
2.4 KiB
Rust
94 lines
2.4 KiB
Rust
//! The default garbage collector.
|
|
//!
|
|
//! For each thread, a participant is lazily initialized on its first use, when the current thread
|
|
//! is registered in the default collector. If initialized, the thread's participant will get
|
|
//! destructed on thread exit, which in turn unregisters the thread.
|
|
|
|
use crate::collector::{Collector, LocalHandle};
|
|
use crate::guard::Guard;
|
|
use crate::primitive::thread_local;
|
|
#[cfg(not(crossbeam_loom))]
|
|
use crate::sync::once_lock::OnceLock;
|
|
|
|
fn collector() -> &'static Collector {
|
|
#[cfg(not(crossbeam_loom))]
|
|
{
|
|
/// The global data for the default garbage collector.
|
|
static COLLECTOR: OnceLock<Collector> = OnceLock::new();
|
|
COLLECTOR.get_or_init(Collector::new)
|
|
}
|
|
// FIXME: loom does not currently provide the equivalent of Lazy:
|
|
// https://github.com/tokio-rs/loom/issues/263
|
|
#[cfg(crossbeam_loom)]
|
|
{
|
|
loom::lazy_static! {
|
|
/// The global data for the default garbage collector.
|
|
static ref COLLECTOR: Collector = Collector::new();
|
|
}
|
|
&COLLECTOR
|
|
}
|
|
}
|
|
|
|
thread_local! {
|
|
/// The per-thread participant for the default garbage collector.
|
|
static HANDLE: LocalHandle = collector().register();
|
|
}
|
|
|
|
/// Pins the current thread.
|
|
#[inline]
|
|
pub fn pin() -> Guard {
|
|
with_handle(|handle| handle.pin())
|
|
}
|
|
|
|
/// Returns `true` if the current thread is pinned.
|
|
#[inline]
|
|
pub fn is_pinned() -> bool {
|
|
with_handle(|handle| handle.is_pinned())
|
|
}
|
|
|
|
/// Returns the default global collector.
|
|
pub fn default_collector() -> &'static Collector {
|
|
collector()
|
|
}
|
|
|
|
#[inline]
|
|
fn with_handle<F, R>(mut f: F) -> R
|
|
where
|
|
F: FnMut(&LocalHandle) -> R,
|
|
{
|
|
HANDLE
|
|
.try_with(|h| f(h))
|
|
.unwrap_or_else(|_| f(&collector().register()))
|
|
}
|
|
|
|
#[cfg(all(test, not(crossbeam_loom)))]
|
|
mod tests {
|
|
use crossbeam_utils::thread;
|
|
|
|
#[test]
|
|
fn pin_while_exiting() {
|
|
struct Foo;
|
|
|
|
impl Drop for Foo {
|
|
fn drop(&mut self) {
|
|
// Pin after `HANDLE` has been dropped. This must not panic.
|
|
super::pin();
|
|
}
|
|
}
|
|
|
|
thread_local! {
|
|
static FOO: Foo = Foo;
|
|
}
|
|
|
|
thread::scope(|scope| {
|
|
scope.spawn(|_| {
|
|
// Initialize `FOO` and then `HANDLE`.
|
|
FOO.with(|_| ());
|
|
super::pin();
|
|
// At thread exit, `HANDLE` gets dropped first and `FOO` second.
|
|
});
|
|
})
|
|
.unwrap();
|
|
}
|
|
}
|