Skip to content
Permalink
Browse files

std::thread::at_start prototype implementation.

  • Loading branch information...
pnkfelix committed Nov 7, 2015
1 parent eacd359 commit bfff1821c26c3900b0abab531ff1b5f59260fcd3
Showing with 102 additions and 0 deletions.
  1. +70 −0 src/libstd/sys/common/at_start_imp.rs
  2. +12 −0 src/libstd/sys/common/mod.rs
  3. +4 −0 src/libstd/sys/common/thread.rs
  4. +16 −0 src/libstd/thread/mod.rs
@@ -0,0 +1,70 @@
// Copyright 2015 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 boxed::Box;
use ptr;
use sys_common::mutex::Mutex;
use vec::Vec;

type Queue = Vec<Box<Fn()>>;

// NB these are specifically not types from `std::sync` as they currently rely
// on poisoning and this module needs to operate at a lower level than requiring
// the thread infrastructure to be in place (useful on the borders of
// initialization/destruction).
static LOCK: Mutex = Mutex::new();
static mut QUEUE: *mut Queue = ptr::null_mut();

unsafe fn init() -> bool {
if QUEUE.is_null() {
let state: Box<Queue> = box Vec::new();
QUEUE = Box::into_raw(state);
}

true
}

/// Runs every procedure enqueued at the time that this was invoked.
/// (recursively-enqueued procedures will not be run by this
/// invocation).
pub fn run_all() {
let enqueued: Vec<_>;
unsafe {
LOCK.lock();
let queue = QUEUE;
if queue as usize != 0 {
enqueued = (*queue).iter().collect();
LOCK.unlock();
} else {
LOCK.unlock();
return;
}
}

for ref to_run in &enqueued {
to_run();
}
}

/// Pushes `f` onto the queue of procedures to invoke on each thread,
/// from the context of that thread, when it starts executing.
pub fn push(f: Box<Fn()>) -> bool {
let mut ret = true;
unsafe {
LOCK.lock();
if init() {
(*QUEUE).push(f);
} else {
ret = false;
}
LOCK.unlock();
}
ret
}
@@ -28,6 +28,7 @@ macro_rules! rtassert {

pub mod args;
pub mod at_exit_imp;
pub mod at_start_imp;
pub mod backtrace;
pub mod condvar;
pub mod dwarf;
@@ -89,6 +90,17 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
}

/// Enqueues a procedure to run when a thread is started.
///
/// Returns `Ok` if the handler was successfully registered, meaning
/// that the closure will be run sometime after each subsequent thread
/// is constructed, but before it starts running its associated main
/// routine. Returns `Err` to indicate that the closure could not be
/// registered, meaning that it is not scheduled to be run.
pub fn at_thread_start<F: Fn() + Send + 'static>(f: F) -> Result<(), ()> {
if at_start_imp::push(Box::new(f)) {Ok(())} else {Err(())}
}

/// One-time runtime cleanup.
pub fn cleanup() {
static CLEANUP: Once = Once::new();
@@ -13,12 +13,16 @@ use prelude::v1::*;
use alloc::boxed::FnBox;
use libc;
use sys::stack_overflow;
use super::at_start_imp;

pub unsafe fn start_thread(main: *mut libc::c_void) {
// Next, set up our stack overflow handler which may get triggered if we run
// out of stack.
let _handler = stack_overflow::Handler::new();

// Next, run all the registered thread_start procedures.
at_start_imp::run_all();

// Finally, let's run some code.
Box::from_raw(main as *mut Box<FnBox()>)()
}
@@ -168,6 +168,7 @@ use fmt;
use io;
use sync::{Mutex, Condvar, Arc};
use sys::thread as imp;
use sys_common;
use sys_common::thread_info;
use sys_common::unwind;
use sys_common::util;
@@ -290,6 +291,21 @@ impl Builder {
// Free functions
////////////////////////////////////////////////////////////////////////////////


/// Enqueues a procedure to run when a thread is started.
///
/// Returns `Ok` if the handler was successfully registered, meaning
/// that the closure will be run sometime after each subsequent thread
/// is constructed, but before it starts running its associated main
/// routine. Returns `Err` to indicate that the closure could not be
/// registered, meaning that it is not scheduled to be run.
///
/// FIXME: Should we also provide some way to unregister a function?
#[unstable(feature = "TODO_unnamed_feature", reason = "recent API addition", issue="99999999")]
pub fn at_start<F: Fn() + Send + 'static>(f: F) -> ::result::Result<(), ()> {
sys_common::at_thread_start(f)
}

/// Spawns a new thread, returning a `JoinHandle` for it.
///
/// The join handle will implicitly *detach* the child thread upon being

0 comments on commit bfff182

Please sign in to comment.
You can’t perform that action at this time.