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};
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
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;
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);
- }
-}
-
-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);
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);
+ }
+}