1//! The default garbage collector.
2//!
3//! For each thread, a participant is lazily initialized on its first use, when the current thread
4//! is registered in the default collector. If initialized, the thread's participant will get
5//! destructed on thread exit, which in turn unregisters the thread.
67use crate::collector::{Collector, LocalHandle};
8use crate::guard::Guard;
9use crate::primitive::thread_local;
10#[cfg(not(crossbeam_loom))]
11use crate::sync::once_lock::OnceLock;
1213fn collector() -> &'static Collector {
14#[cfg(not(crossbeam_loom))]
15{
16/// The global data for the default garbage collector.
17static COLLECTOR: OnceLock<Collector> = OnceLock::new();
18 COLLECTOR.get_or_init(Collector::new)
19 }
20// FIXME: loom does not currently provide the equivalent of Lazy:
21 // https://github.com/tokio-rs/loom/issues/263
22#[cfg(crossbeam_loom)]
23{
24loom::lazy_static! {
25/// The global data for the default garbage collector.
26static ref COLLECTOR: Collector = Collector::new();
27 }
28&COLLECTOR
29 }
30}
3132thread_local! {
33/// The per-thread participant for the default garbage collector.
34static HANDLE: LocalHandle = collector().register();
35}
3637/// Pins the current thread.
38#[inline]
39pub fn pin() -> Guard {
40 with_handle(|handle| handle.pin())
41}
4243/// Returns `true` if the current thread is pinned.
44#[inline]
45pub fn is_pinned() -> bool {
46 with_handle(|handle| handle.is_pinned())
47}
4849/// Returns the default global collector.
50pub fn default_collector() -> &'static Collector {
51 collector()
52}
5354#[inline]
55fn with_handle<F, R>(mut f: F) -> R
56where
57F: FnMut(&LocalHandle) -> R,
58{
59 HANDLE
60 .try_with(|h| f(h))
61 .unwrap_or_else(|_| f(&collector().register()))
62}
6364#[cfg(all(test, not(crossbeam_loom)))]
65mod tests {
66use crossbeam_utils::thread;
6768#[test]
69fn pin_while_exiting() {
70struct Foo;
7172impl Drop for Foo {
73fn drop(&mut self) {
74// Pin after `HANDLE` has been dropped. This must not panic.
75super::pin();
76 }
77 }
7879thread_local! {
80static FOO: Foo = const { Foo };
81 }
8283 thread::scope(|scope| {
84 scope.spawn(|_| {
85// Initialize `FOO` and then `HANDLE`.
86FOO.with(|_| ());
87super::pin();
88// At thread exit, `HANDLE` gets dropped first and `FOO` second.
89});
90 })
91 .unwrap();
92 }
93}