From c009bfdf94a48434e1f6bf3bfe59cf539f464ee2 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 24 Nov 2014 17:22:40 -0800 Subject: Make at_exit initialize lazily --- src/libstd/rt/at_exit_imp.rs | 41 +++++++++++++++++++++++------------------ src/libstd/rt/mod.rs | 2 -- 2 files changed, 23 insertions(+), 20 deletions(-) (limited to 'src/libstd/rt') 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); - } -} - -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); + QUEUE.store(mem::transmute(state), atomic::SeqCst); + libc::atexit(run); } } -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... -- cgit 1.4.1-3-g733a5