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