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::{lazy_static, thread_local};
1011lazy_static! {
12/// The global data for the default garbage collector.
13static ref COLLECTOR: Collector = Collector::new();
14}
1516thread_local! {
17/// The per-thread participant for the default garbage collector.
18static HANDLE: LocalHandle = COLLECTOR.register();
19}
2021/// Pins the current thread.
22#[inline]
23pub fn pin() -> Guard {
24 with_handle(|handle| handle.pin())
25}
2627/// Returns `true` if the current thread is pinned.
28#[inline]
29pub fn is_pinned() -> bool {
30 with_handle(|handle| handle.is_pinned())
31}
3233/// Returns the default global collector.
34pub fn default_collector() -> &'static Collector {
35&COLLECTOR
36}
3738#[inline]
39fn with_handle<F, R>(mut f: F) -> R
40where
41F: FnMut(&LocalHandle) -> R,
42{
43 HANDLE
44 .try_with(|h| f(h))
45 .unwrap_or_else(|_| f(&COLLECTOR.register()))
46}
4748#[cfg(all(test, not(crossbeam_loom)))]
49mod tests {
50use crossbeam_utils::thread;
5152#[test]
53fn pin_while_exiting() {
54struct Foo;
5556impl Drop for Foo {
57fn drop(&mut self) {
58// Pin after `HANDLE` has been dropped. This must not panic.
59super::pin();
60 }
61 }
6263thread_local! {
64static FOO: Foo = Foo;
65 }
6667 thread::scope(|scope| {
68 scope.spawn(|_| {
69// Initialize `FOO` and then `HANDLE`.
70FOO.with(|_| ());
71super::pin();
72// At thread exit, `HANDLE` gets dropped first and `FOO` second.
73});
74 })
75 .unwrap();
76 }
77}