diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs new file mode 100644 index 00000000000..df507de8bcf --- /dev/null +++ b/src/libstd/rt/at_exit_imp.rs @@ -0,0 +1,65 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation of running at_exit routines +//! +//! Documentation can be found on the `rt::at_exit` function. + +use cast; +use option::{Some, None}; +use ptr::RawPtr; +use unstable::sync::Exclusive; +use util; + +type Queue = Exclusive<~[proc()]>; + +static mut QUEUE: *mut Queue = 0 as *mut Queue; +static mut RUNNING: bool = false; + +pub fn init() { + unsafe { + rtassert!(!RUNNING); + rtassert!(QUEUE.is_null()); + let state: ~Queue = ~Exclusive::new(~[]); + QUEUE = cast::transmute(state); + } +} + +pub fn push(f: proc()) { + unsafe { + rtassert!(!RUNNING); + rtassert!(!QUEUE.is_null()); + let state: &mut Queue = cast::transmute(QUEUE); + let mut f = Some(f); + state.with(|arr| { + arr.push(f.take_unwrap()); + }); + } +} + +pub fn run() { + let vec = unsafe { + rtassert!(!RUNNING); + rtassert!(!QUEUE.is_null()); + RUNNING = true; + let state: ~Queue = cast::transmute(QUEUE); + QUEUE = 0 as *mut Queue; + let mut vec = None; + state.with(|arr| { + vec = Some(util::replace(arr, ~[])); + }); + vec.take_unwrap() + }; + + + for f in vec.move_iter() { + f(); + } +} diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 40e9a3ec5b2..7aa966802f2 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -127,6 +127,9 @@ mod util; // Global command line argument storage pub mod args; +// Support for running procedures when a program has exited. +mod at_exit_imp; + /// The default error code of the rust runtime if the main task fails instead /// of exiting cleanly. pub static DEFAULT_ERROR_CODE: int = 101; @@ -171,9 +174,27 @@ pub fn init(argc: int, argv: **u8) { env::init(); logging::init(); local_ptr::init(); + at_exit_imp::init(); } } +/// Enqueues a procedure to run when the runtime is cleaned up +/// +/// The procedure passed to this function will be executed as part of the +/// runtime cleanup phase. For normal rust programs, this means that it will run +/// after all other tasks have exited. +/// +/// The procedure is *not* executed with a local `Task` available to it, so +/// primitives like logging, I/O, channels, spawning, etc, are *not* available. +/// This is meant for "bare bones" usage to clean up runtime details, this is +/// not meant as a general-purpose "let's clean everything up" function. +/// +/// It is forbidden for procedures to register more `at_exit` handlers when they +/// are running, and doing so will lead to a process abort. +pub fn at_exit(f: proc()) { + at_exit_imp::push(f); +} + /// One-time runtime cleanup. /// /// This function is unsafe because it performs no checks to ensure that the @@ -184,6 +205,7 @@ pub fn init(argc: int, argv: **u8) { /// Invoking cleanup while portions of the runtime are still in use may cause /// undefined behavior. pub unsafe fn cleanup() { + at_exit_imp::run(); args::cleanup(); local_ptr::cleanup(); }