Make at_exit initialize lazily

This commit is contained in:
Aaron Turon 2014-11-24 17:22:40 -08:00
parent b66681cd31
commit c009bfdf94
4 changed files with 25 additions and 23 deletions

View File

@ -138,7 +138,7 @@ pub use funcs::c95::stdio::{fread, freopen, fseek, fsetpos, ftell};
pub use funcs::c95::stdio::{fwrite, perror, puts, remove, rename, rewind};
pub use funcs::c95::stdio::{setbuf, setvbuf, tmpfile, ungetc};
pub use funcs::c95::stdlib::{abs, atof, atoi, calloc, exit, _exit};
pub use funcs::c95::stdlib::{abs, atof, atoi, calloc, exit, _exit, atexit};
pub use funcs::c95::stdlib::{free, getenv, labs, malloc, rand};
pub use funcs::c95::stdlib::{realloc, srand, strtod, strtol};
pub use funcs::c95::stdlib::{strtoul, system};
@ -4102,7 +4102,7 @@ pub mod funcs {
pub fn free(p: *mut c_void);
pub fn exit(status: c_int) -> !;
pub fn _exit(status: c_int) -> !;
// Omitted: atexit.
pub fn atexit(cb: extern fn()) -> c_int;
pub fn system(s: *const c_char) -> c_int;
pub fn getenv(s: *const c_char) -> *mut c_char;
// Omitted: bsearch, qsort

View File

@ -43,7 +43,6 @@ use boxed::Box;
use ops::{Drop, FnOnce};
use option::Option;
use option::Option::{Some, None};
use os;
use path::{Path, GenericPath, BytesContainer};
use sys;
use ptr::RawPtr;

View File

@ -14,9 +14,10 @@
use core::prelude::*;
use libc;
use boxed::Box;
use vec::Vec;
use sync::atomic;
use sync::{atomic, Once, ONCE_INIT};
use mem;
use thunk::Thunk;
@ -24,31 +25,21 @@ use rt::exclusive::Exclusive;
type Queue = Exclusive<Vec<Thunk>>;
static INIT: Once = ONCE_INIT;
static QUEUE: atomic::AtomicUint = atomic::INIT_ATOMIC_UINT;
static RUNNING: atomic::AtomicBool = atomic::INIT_ATOMIC_BOOL;
pub fn init() {
fn init() {
let state: Box<Queue> = box Exclusive::new(Vec::new());
unsafe {
rtassert!(!RUNNING.load(atomic::SeqCst));
assert!(QUEUE.swap(mem::transmute(state), atomic::SeqCst) == 0);
QUEUE.store(mem::transmute(state), atomic::SeqCst);
libc::atexit(run);
}
}
pub fn push(f: Thunk) {
unsafe {
// Note that the check against 0 for the queue pointer is not atomic at
// all with respect to `run`, meaning that this could theoretically be a
// use-after-free. There's not much we can do to protect against that,
// however. Let's just assume a well-behaved runtime and go from there!
rtassert!(!RUNNING.load(atomic::SeqCst));
let queue = QUEUE.load(atomic::SeqCst);
rtassert!(queue != 0);
(*(queue as *const Queue)).lock().push(f);
}
}
pub fn run() {
// Note: this is private and so can only be called via atexit above,
// which guarantees initialization.
extern fn run() {
let cur = unsafe {
rtassert!(!RUNNING.load(atomic::SeqCst));
let queue = QUEUE.swap(0, atomic::SeqCst);
@ -63,3 +54,17 @@ pub fn run() {
to_run.invoke(());
}
}
pub fn push(f: Thunk) {
INIT.doit(init);
unsafe {
// Note that the check against 0 for the queue pointer is not atomic at
// all with respect to `run`, meaning that this could theoretically be a
// use-after-free. There's not much we can do to protect against that,
// however. Let's just assume a well-behaved runtime and go from there!
rtassert!(!RUNNING.load(atomic::SeqCst));
let queue = QUEUE.load(atomic::SeqCst);
rtassert!(queue != 0);
(*(queue as *const Queue)).lock().push(f);
}
}

View File

@ -100,7 +100,6 @@ pub fn init(argc: int, argv: *const *const u8) {
unsafe {
args::init(argc, argv);
local_ptr::init();
at_exit_imp::init();
thread::init();
unwind::register(failure::on_fail);
}
@ -212,7 +211,6 @@ pub unsafe fn cleanup() {
args::cleanup();
thread::cleanup();
local_ptr::cleanup();
at_exit_imp::run();
}
// FIXME: these probably shouldn't be public...