+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use cast;
-use libc::size_t;
-use rand::RngUtil;
-use rand;
-use sys;
-use task;
-use vec;
-
-#[cfg(test)] use uint;
-
-/**
-Register a function to be run during runtime shutdown.
-
-After all non-weak tasks have exited, registered exit functions will
-execute, in random order, on the primary scheduler. Each function runs
-in its own unsupervised task.
-*/
-pub fn at_exit(f: ~fn()) {
- unsafe {
- let runner: &fn(*ExitFunctions) = exit_runner;
- let runner_pair: sys::Closure = cast::transmute(runner);
- let runner_ptr = runner_pair.code;
- let runner_ptr = cast::transmute(runner_ptr);
- rustrt::rust_register_exit_function(runner_ptr, ~f);
- }
-}
-
-// NB: The double pointer indirection here is because ~fn() is a fat
-// pointer and due to FFI problems I am more comfortable making the
-// interface use a normal pointer
-mod rustrt {
- use libc::c_void;
-
- extern {
- pub fn rust_register_exit_function(runner: *c_void, f: ~~fn());
- }
-}
-
-struct ExitFunctions {
- // The number of exit functions
- count: size_t,
- // The buffer of exit functions
- start: *~~fn()
-}
-
-fn exit_runner(exit_fns: *ExitFunctions) {
- let exit_fns = unsafe { &*exit_fns };
- let count = (*exit_fns).count;
- let start = (*exit_fns).start;
-
- // NB: from_buf memcpys from the source, which will
- // give us ownership of the array of functions
- let mut exit_fns_vec = unsafe { vec::from_buf(start, count as uint) };
- // Let's not make any promises about execution order
- let mut rng = rand::rng();
- rng.shuffle_mut(exit_fns_vec);
-
- debug!("running %u exit functions", exit_fns_vec.len());
-
- while !exit_fns_vec.is_empty() {
- match exit_fns_vec.pop() {
- ~f => {
- let mut task = task::task();
- task.supervised();
- task.spawn(f);
- }
- }
- }
-}
-
-#[test]
-fn test_at_exit() {
- let i = 10;
- do at_exit {
- debug!("at_exit1");
- assert_eq!(i, 10);
- }
-}
-
-#[test]
-fn test_at_exit_many() {
- let i = 10;
- for uint::range(20, 100) |j| {
- do at_exit {
- debug!("at_exit2");
- assert_eq!(i, 10);
- assert!(j > i);
- }
- }
-}
sched_reaper(this),
osmain_driver(NULL),
non_weak_tasks(0),
- at_exit_runner(NULL),
- at_exit_started(false),
env(env)
{
// Create the single threaded scheduler that will run on the platform's
}
}
- run_exit_functions();
allow_scheduler_exit();
}
-void
-rust_kernel::register_exit_function(spawn_fn runner, fn_env_pair *f) {
- scoped_lock with(at_exit_lock);
-
- assert(!at_exit_started && "registering at_exit function after exit");
-
- if (at_exit_runner) {
- // FIXME #2912 Would be very nice to assert this but we can't because
- // of the way coretest works (the test case ends up using its own
- // function)
- //assert(runner == at_exit_runner
- // && "there can be only one at_exit_runner");
- }
-
- at_exit_runner = runner;
- at_exit_fns.push_back(f);
-}
-
-void
-rust_kernel::run_exit_functions() {
- rust_task *task;
-
- {
- scoped_lock with(at_exit_lock);
-
- assert(!at_exit_started && "running exit functions twice?");
-
- at_exit_started = true;
-
- if (at_exit_runner == NULL) {
- return;
- }
-
- rust_scheduler *sched = get_scheduler_by_id(main_sched_id());
- assert(sched);
- task = sched->create_task(NULL, "at_exit");
-
- final_exit_fns.count = at_exit_fns.size();
- final_exit_fns.start = at_exit_fns.data();
- }
-
- task->start(at_exit_runner, NULL, &final_exit_fns);
-}
-
//
// Local Variables:
// mode: C++
typedef std::map<rust_sched_id, rust_scheduler*> sched_map;
-// This is defined as a struct only because we need a single pointer to pass
-// to the Rust function that runs the at_exit functions
-struct exit_functions {
- size_t count;
- fn_env_pair **start;
-};
-
class rust_kernel {
rust_exchange_alloc exchange_alloc;
rust_log _log;
void allow_scheduler_exit();
void begin_shutdown();
- lock_and_signal at_exit_lock;
- spawn_fn at_exit_runner;
- bool at_exit_started;
- std::vector<fn_env_pair*> at_exit_fns;
- exit_functions final_exit_fns;
-
- void run_exit_functions();
-
public:
struct rust_env *env;
void inc_live_count();
void dec_live_count();
- void register_exit_function(spawn_fn runner, fn_env_pair *f);
};
template <typename T> struct kernel_owned {