Skip to content

Commit 530909f

Browse files
committed
Implement std::rt::at_exit
This routine is currently only used to clean up the timer helper thread in the libnative implementation, but there are possibly other uses for this. The documentation is clear that the procedures are *not* run with any task context and hence have very little available to them. I also opted to disallow at_exit inside of at_exit and just abort the process at that point.
1 parent fce7922 commit 530909f

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

src/libstd/rt/at_exit_imp.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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 cast;
16+
use option::{Some, None};
17+
use ptr::RawPtr;
18+
use unstable::sync::Exclusive;
19+
use util;
20+
21+
type Queue = Exclusive<~[proc()]>;
22+
23+
static mut QUEUE: *mut Queue = 0 as *mut Queue;
24+
static mut RUNNING: bool = false;
25+
26+
pub fn init() {
27+
unsafe {
28+
rtassert!(!RUNNING);
29+
rtassert!(QUEUE.is_null());
30+
let state: ~Queue = ~Exclusive::new(~[]);
31+
QUEUE = cast::transmute(state);
32+
}
33+
}
34+
35+
pub fn push(f: proc()) {
36+
unsafe {
37+
rtassert!(!RUNNING);
38+
rtassert!(!QUEUE.is_null());
39+
let state: &mut Queue = cast::transmute(QUEUE);
40+
let mut f = Some(f);
41+
state.with(|arr| {
42+
arr.push(f.take_unwrap());
43+
});
44+
}
45+
}
46+
47+
pub fn run() {
48+
let vec = unsafe {
49+
rtassert!(!RUNNING);
50+
rtassert!(!QUEUE.is_null());
51+
RUNNING = true;
52+
let state: ~Queue = cast::transmute(QUEUE);
53+
QUEUE = 0 as *mut Queue;
54+
let mut vec = None;
55+
state.with(|arr| {
56+
vec = Some(util::replace(arr, ~[]));
57+
});
58+
vec.take_unwrap()
59+
};
60+
61+
62+
for f in vec.move_iter() {
63+
f();
64+
}
65+
}

src/libstd/rt/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ mod util;
127127
// Global command line argument storage
128128
pub mod args;
129129

130+
// Support for running procedures when a program has exited.
131+
mod at_exit_imp;
132+
130133
/// The default error code of the rust runtime if the main task fails instead
131134
/// of exiting cleanly.
132135
pub static DEFAULT_ERROR_CODE: int = 101;
@@ -171,9 +174,27 @@ pub fn init(argc: int, argv: **u8) {
171174
env::init();
172175
logging::init();
173176
local_ptr::init();
177+
at_exit_imp::init();
174178
}
175179
}
176180

181+
/// Enqueues a procedure to run when the runtime is cleaned up
182+
///
183+
/// The procedure passed to this function will be executed as part of the
184+
/// runtime cleanup phase. For normal rust programs, this means that it will run
185+
/// after all other tasks have exited.
186+
///
187+
/// The procedure is *not* executed with a local `Task` available to it, so
188+
/// primitives like logging, I/O, channels, spawning, etc, are *not* available.
189+
/// This is meant for "bare bones" usage to clean up runtime details, this is
190+
/// not meant as a general-purpose "let's clean everything up" function.
191+
///
192+
/// It is forbidden for procedures to register more `at_exit` handlers when they
193+
/// are running, and doing so will lead to a process abort.
194+
pub fn at_exit(f: proc()) {
195+
at_exit_imp::push(f);
196+
}
197+
177198
/// One-time runtime cleanup.
178199
///
179200
/// This function is unsafe because it performs no checks to ensure that the
@@ -184,6 +205,7 @@ pub fn init(argc: int, argv: **u8) {
184205
/// Invoking cleanup while portions of the runtime are still in use may cause
185206
/// undefined behavior.
186207
pub unsafe fn cleanup() {
208+
at_exit_imp::run();
187209
args::cleanup();
188210
local_ptr::cleanup();
189211
}

0 commit comments

Comments
 (0)