diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 8825099e36c..6ab00cfe8fa 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -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 diff --git a/src/libstd/os.rs b/src/libstd/os.rs index f46d9ab7c7e..550c8d2faba 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -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; diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs index 086079c312a..9ddb59bfffc 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -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>; +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 = 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); + } +} diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 21c8197ef05..5d5ccefda5d 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -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...