• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
6 
7 use crate::collector::{Collector, LocalHandle};
8 use crate::guard::Guard;
9 use crate::primitive::{lazy_static, thread_local};
10 
11 lazy_static! {
12     /// The global data for the default garbage collector.
13     static ref COLLECTOR: Collector = Collector::new();
14 }
15 
16 thread_local! {
17     /// The per-thread participant for the default garbage collector.
18     static HANDLE: LocalHandle = COLLECTOR.register();
19 }
20 
21 /// Pins the current thread.
22 #[inline]
pin() -> Guard23 pub fn pin() -> Guard {
24     with_handle(|handle| handle.pin())
25 }
26 
27 /// Returns `true` if the current thread is pinned.
28 #[inline]
is_pinned() -> bool29 pub fn is_pinned() -> bool {
30     with_handle(|handle| handle.is_pinned())
31 }
32 
33 /// Returns the default global collector.
default_collector() -> &'static Collector34 pub fn default_collector() -> &'static Collector {
35     &COLLECTOR
36 }
37 
38 #[inline]
with_handle<F, R>(mut f: F) -> R where F: FnMut(&LocalHandle) -> R,39 fn with_handle<F, R>(mut f: F) -> R
40 where
41     F: FnMut(&LocalHandle) -> R,
42 {
43     HANDLE
44         .try_with(|h| f(h))
45         .unwrap_or_else(|_| f(&COLLECTOR.register()))
46 }
47 
48 #[cfg(all(test, not(crossbeam_loom)))]
49 mod tests {
50     use crossbeam_utils::thread;
51 
52     #[test]
pin_while_exiting()53     fn pin_while_exiting() {
54         struct Foo;
55 
56         impl Drop for Foo {
57             fn drop(&mut self) {
58                 // Pin after `HANDLE` has been dropped. This must not panic.
59                 super::pin();
60             }
61         }
62 
63         thread_local! {
64             static FOO: Foo = Foo;
65         }
66 
67         thread::scope(|scope| {
68             scope.spawn(|_| {
69                 // Initialize `FOO` and then `HANDLE`.
70                 FOO.with(|_| ());
71                 super::pin();
72                 // At thread exit, `HANDLE` gets dropped first and `FOO` second.
73             });
74         })
75         .unwrap();
76     }
77 }
78