]> git.lizzy.rs Git - rust.git/blob - src/librustrt/at_exit_imp.rs
dcba7fb7cb6a6255d51b295c6c9f2d6d3e2d2d17
[rust.git] / src / librustrt / 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 use core::prelude::*;
16
17 use alloc::owned::Box;
18 use collections::vec::Vec;
19 use core::atomics;
20 use core::mem;
21
22 use exclusive::Exclusive;
23
24 type Queue = Exclusive<Vec<proc():Send>>;
25
26 static mut QUEUE: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
27 static mut RUNNING: atomics::AtomicBool = atomics::INIT_ATOMIC_BOOL;
28
29 pub fn init() {
30     let state: Box<Queue> = box Exclusive::new(Vec::new());
31     unsafe {
32         rtassert!(!RUNNING.load(atomics::SeqCst));
33         rtassert!(QUEUE.swap(mem::transmute(state), atomics::SeqCst) == 0);
34     }
35 }
36
37 pub fn push(f: proc():Send) {
38     unsafe {
39         // Note that the check against 0 for the queue pointer is not atomic at
40         // all with respect to `run`, meaning that this could theoretically be a
41         // use-after-free. There's not much we can do to protect against that,
42         // however. Let's just assume a well-behaved runtime and go from there!
43         rtassert!(!RUNNING.load(atomics::SeqCst));
44         let queue = QUEUE.load(atomics::SeqCst);
45         rtassert!(queue != 0);
46         (*(queue as *const Queue)).lock().push(f);
47     }
48 }
49
50 pub fn run() {
51     let cur = unsafe {
52         rtassert!(!RUNNING.load(atomics::SeqCst));
53         let queue = QUEUE.swap(0, atomics::SeqCst);
54         rtassert!(queue != 0);
55
56         let queue: Box<Queue> = mem::transmute(queue);
57         let v = mem::replace(&mut *queue.lock(), Vec::new());
58         v
59     };
60
61     for to_run in cur.move_iter() {
62         to_run();
63     }
64 }