]> git.lizzy.rs Git - rust.git/blob - src/libstd/unstable/at_exit.rs
20ddf941a7b95d67af79b17eb75777fb7c1e4bc9
[rust.git] / src / libstd / unstable / at_exit.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 use cast;
12 use libc::size_t;
13 use rand::RngUtil;
14 use rand;
15 use sys;
16 use task;
17 use vec;
18
19 #[cfg(test)] use uint;
20
21 /**
22 Register a function to be run during runtime shutdown.
23
24 After all non-weak tasks have exited, registered exit functions will
25 execute, in random order, on the primary scheduler. Each function runs
26 in its own unsupervised task.
27 */
28 pub fn at_exit(f: ~fn()) {
29     unsafe {
30         let runner: &fn(*ExitFunctions) = exit_runner;
31         let runner_pair: sys::Closure = cast::transmute(runner);
32         let runner_ptr = runner_pair.code;
33         let runner_ptr = cast::transmute(runner_ptr);
34         rustrt::rust_register_exit_function(runner_ptr, ~f);
35     }
36 }
37
38 // NB: The double pointer indirection here is because ~fn() is a fat
39 // pointer and due to FFI problems I am more comfortable making the
40 // interface use a normal pointer
41 mod rustrt {
42     use libc::c_void;
43
44     extern {
45         pub fn rust_register_exit_function(runner: *c_void, f: ~~fn());
46     }
47 }
48
49 struct ExitFunctions {
50     // The number of exit functions
51     count: size_t,
52     // The buffer of exit functions
53     start: *~~fn()
54 }
55
56 fn exit_runner(exit_fns: *ExitFunctions) {
57     let exit_fns = unsafe { &*exit_fns };
58     let count = (*exit_fns).count;
59     let start = (*exit_fns).start;
60
61     // NB: from_buf memcpys from the source, which will
62     // give us ownership of the array of functions
63     let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) };
64     // Let's not make any promises about execution order
65     let mut rng = rand::rng();
66     rng.shuffle_mut(exit_fns_vec);
67
68     debug!("running %u exit functions", exit_fns_vec.len());
69
70     while !exit_fns_vec.is_empty() {
71         match exit_fns_vec.pop() {
72             ~f => {
73                 let mut task = task::task();
74                 task.supervised();
75                 task.spawn(f);
76             }
77         }
78     }
79 }
80
81 #[test]
82 fn test_at_exit() {
83     let i = 10;
84     do at_exit {
85         debug!("at_exit1");
86         assert_eq!(i, 10);
87     }
88 }
89
90 #[test]
91 fn test_at_exit_many() {
92     let i = 10;
93     for uint::range(20, 100) |j| {
94         do at_exit {
95             debug!("at_exit2");
96             assert_eq!(i, 10);
97             assert!(j > i);
98         }
99     }
100 }