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