]> git.proxmox.com Git - rustc.git/blob - src/libstd/rt/at_exit_imp.rs
Imported Upstream version 1.2.0+dfsg1
[rustc.git] / src / libstd / rt / at_exit_imp.rs
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
15 // FIXME: switch this to use atexit. Currently this
16 // segfaults (the queue's memory is mysteriously gone), so
17 // instead the cleanup is tied to the `std::rt` entry point.
18
19 use alloc::boxed::FnBox;
20 use boxed::Box;
21 use sys_common::mutex::Mutex;
22 use vec::Vec;
23
24 type Queue = Vec<Box<FnBox()>>;
25
26 // NB these are specifically not types from `std::sync` as they currently rely
27 // on poisoning and this module needs to operate at a lower level than requiring
28 // the thread infrastructure to be in place (useful on the borders of
29 // initialization/destruction).
30 static LOCK: Mutex = Mutex::new();
31 static mut QUEUE: *mut Queue = 0 as *mut Queue;
32
33 // The maximum number of times the cleanup routines will be run. While running
34 // the at_exit closures new ones may be registered, and this count is the number
35 // of times the new closures will be allowed to register successfully. After
36 // this number of iterations all new registrations will return `false`.
37 const ITERS: usize = 10;
38
39 unsafe fn init() -> bool {
40 if QUEUE.is_null() {
41 let state: Box<Queue> = box Vec::new();
42 QUEUE = Box::into_raw(state);
43 } else if QUEUE as usize == 1 {
44 // can't re-init after a cleanup
45 return false
46 }
47
48 return true
49 }
50
51 pub fn cleanup() {
52 for i in 0..ITERS {
53 unsafe {
54 LOCK.lock();
55 let queue = QUEUE;
56 QUEUE = if i == ITERS - 1 {1} else {0} as *mut _;
57 LOCK.unlock();
58
59 // make sure we're not recursively cleaning up
60 rtassert!(queue as usize != 1);
61
62 // If we never called init, not need to cleanup!
63 if queue as usize != 0 {
64 let queue: Box<Queue> = Box::from_raw(queue);
65 for to_run in *queue {
66 to_run();
67 }
68 }
69 }
70 }
71 }
72
73 pub fn push(f: Box<FnBox()>) -> bool {
74 let mut ret = true;
75 unsafe {
76 LOCK.lock();
77 if init() {
78 (*QUEUE).push(f);
79 } else {
80 ret = false;
81 }
82 LOCK.unlock();
83 }
84 return ret
85 }