]>
git.proxmox.com Git - rustc.git/blob - library/std/src/sys_common/at_exit_imp.rs
1 //! Implementation of running at_exit routines
3 //! Documentation can be found on the `rt::at_exit` function.
7 use crate::sys_common
::mutex
::StaticMutex
;
9 type Queue
= Vec
<Box
<dyn FnOnce()>>;
11 // NB these are specifically not types from `std::sync` as they currently rely
12 // on poisoning and this module needs to operate at a lower level than requiring
13 // the thread infrastructure to be in place (useful on the borders of
14 // initialization/destruction).
15 // It is UB to attempt to acquire this mutex reentrantly!
16 static LOCK
: StaticMutex
= StaticMutex
::new();
17 static mut QUEUE
: *mut Queue
= ptr
::null_mut();
19 const DONE
: *mut Queue
= 1_usize
as *mut _
;
21 // The maximum number of times the cleanup routines will be run. While running
22 // the at_exit closures new ones may be registered, and this count is the number
23 // of times the new closures will be allowed to register successfully. After
24 // this number of iterations all new registrations will return `false`.
25 const ITERS
: usize = 10;
27 unsafe fn init() -> bool
{
29 let state
: Box
<Queue
> = box Vec
::new();
30 QUEUE
= Box
::into_raw(state
);
31 } else if QUEUE
== DONE
{
32 // can't re-init after a cleanup
43 let _guard
= LOCK
.lock();
44 mem
::replace(&mut QUEUE
, if i
== ITERS { DONE }
else { ptr::null_mut() }
)
47 // make sure we're not recursively cleaning up
48 assert
!(queue
!= DONE
);
50 // If we never called init, not need to cleanup!
52 let queue
: Box
<Queue
> = Box
::from_raw(queue
);
53 for to_run
in *queue
{
54 // We are not holding any lock, so reentrancy is fine.
62 pub fn push(f
: Box
<dyn FnOnce()>) -> bool
{
64 let _guard
= LOCK
.lock();
66 // We are just moving `f` around, not calling it.
67 // There is no possibility of reentrancy here.