crossbeam_epoch/
default.rs1use crate::collector::{Collector, LocalHandle};
8use crate::guard::Guard;
9use crate::primitive::thread_local;
10#[cfg(not(crossbeam_loom))]
11use crate::sync::once_lock::OnceLock;
12
13fn collector() -> &'static Collector {
14    #[cfg(not(crossbeam_loom))]
15    {
16        static COLLECTOR: OnceLock<Collector> = OnceLock::new();
18        COLLECTOR.get_or_init(Collector::new)
19    }
20    #[cfg(crossbeam_loom)]
23    {
24        loom::lazy_static! {
25            static ref COLLECTOR: Collector = Collector::new();
27        }
28        &COLLECTOR
29    }
30}
31
32thread_local! {
33    static HANDLE: LocalHandle = collector().register();
35}
36
37#[inline]
39pub fn pin() -> Guard {
40    with_handle(|handle| handle.pin())
41}
42
43#[inline]
45pub fn is_pinned() -> bool {
46    with_handle(|handle| handle.is_pinned())
47}
48
49pub fn default_collector() -> &'static Collector {
51    collector()
52}
53
54#[inline]
55fn with_handle<F, R>(mut f: F) -> R
56where
57    F: FnMut(&LocalHandle) -> R,
58{
59    HANDLE
60        .try_with(|h| f(h))
61        .unwrap_or_else(|_| f(&collector().register()))
62}
63
64#[cfg(all(test, not(crossbeam_loom)))]
65mod tests {
66    use crossbeam_utils::thread;
67
68    #[test]
69    fn pin_while_exiting() {
70        struct Foo;
71
72        impl Drop for Foo {
73            fn drop(&mut self) {
74                super::pin();
76            }
77        }
78
79        thread_local! {
80            static FOO: Foo = const { Foo };
81        }
82
83        thread::scope(|scope| {
84            scope.spawn(|_| {
85                FOO.with(|_| ());
87                super::pin();
88                });
90        })
91        .unwrap();
92    }
93}