]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2013 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | //! Implementation of running at_exit routines | |
12 | //! | |
13 | //! Documentation can be found on the `rt::at_exit` function. | |
14 | ||
62682a34 | 15 | use alloc::boxed::FnBox; |
e9174d1e | 16 | use ptr; |
62682a34 | 17 | use sys_common::mutex::Mutex; |
1a4d82fc | 18 | |
62682a34 | 19 | type Queue = Vec<Box<FnBox()>>; |
1a4d82fc JJ |
20 | |
21 | // NB these are specifically not types from `std::sync` as they currently rely | |
22 | // on poisoning and this module needs to operate at a lower level than requiring | |
23 | // the thread infrastructure to be in place (useful on the borders of | |
24 | // initialization/destruction). | |
62682a34 | 25 | static LOCK: Mutex = Mutex::new(); |
e9174d1e | 26 | static mut QUEUE: *mut Queue = ptr::null_mut(); |
1a4d82fc | 27 | |
c34b1796 AL |
28 | // The maximum number of times the cleanup routines will be run. While running |
29 | // the at_exit closures new ones may be registered, and this count is the number | |
30 | // of times the new closures will be allowed to register successfully. After | |
31 | // this number of iterations all new registrations will return `false`. | |
32 | const ITERS: usize = 10; | |
33 | ||
34 | unsafe fn init() -> bool { | |
1a4d82fc JJ |
35 | if QUEUE.is_null() { |
36 | let state: Box<Queue> = box Vec::new(); | |
62682a34 | 37 | QUEUE = Box::into_raw(state); |
c34b1796 | 38 | } else if QUEUE as usize == 1 { |
1a4d82fc | 39 | // can't re-init after a cleanup |
c34b1796 | 40 | return false |
1a4d82fc JJ |
41 | } |
42 | ||
e9174d1e | 43 | true |
1a4d82fc JJ |
44 | } |
45 | ||
46 | pub fn cleanup() { | |
c34b1796 AL |
47 | for i in 0..ITERS { |
48 | unsafe { | |
49 | LOCK.lock(); | |
50 | let queue = QUEUE; | |
51 | QUEUE = if i == ITERS - 1 {1} else {0} as *mut _; | |
52 | LOCK.unlock(); | |
1a4d82fc | 53 | |
c34b1796 | 54 | // make sure we're not recursively cleaning up |
e9174d1e | 55 | assert!(queue as usize != 1); |
1a4d82fc | 56 | |
c34b1796 AL |
57 | // If we never called init, not need to cleanup! |
58 | if queue as usize != 0 { | |
59 | let queue: Box<Queue> = Box::from_raw(queue); | |
60 | for to_run in *queue { | |
61 | to_run(); | |
62 | } | |
1a4d82fc JJ |
63 | } |
64 | } | |
65 | } | |
66 | } | |
67 | ||
62682a34 | 68 | pub fn push(f: Box<FnBox()>) -> bool { |
c34b1796 | 69 | let mut ret = true; |
1a4d82fc JJ |
70 | unsafe { |
71 | LOCK.lock(); | |
c34b1796 AL |
72 | if init() { |
73 | (*QUEUE).push(f); | |
74 | } else { | |
75 | ret = false; | |
76 | } | |
1a4d82fc JJ |
77 | LOCK.unlock(); |
78 | } | |
e9174d1e | 79 | ret |
1a4d82fc | 80 | } |