std: Remove unused helper_thread.rs file
This module has been removed for quite some time!
This commit is contained in:
parent
377b1adc36
commit
a031325e83
1 changed files with 0 additions and 170 deletions
|
@ -1,170 +0,0 @@
|
|||
// Copyright 2013-2014 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.
|
||||
|
||||
//! Implementation of the helper thread for the timer module
|
||||
//!
|
||||
//! This module contains the management necessary for the timer worker thread.
|
||||
//! This thread is responsible for performing the send()s on channels for timers
|
||||
//! that are using channels instead of a blocking call.
|
||||
//!
|
||||
//! The timer thread is lazily initialized, and it's shut down via the
|
||||
//! `shutdown` function provided. It must be maintained as an invariant that
|
||||
//! `shutdown` is only called when the entire program is finished. No new timers
|
||||
//! can be created in the future and there must be no active timers at that
|
||||
//! time.
|
||||
|
||||
use prelude::v1::*;
|
||||
|
||||
use boxed;
|
||||
use cell::UnsafeCell;
|
||||
use rt;
|
||||
use sync::{StaticMutex, StaticCondvar};
|
||||
use sync::mpsc::{channel, Sender, Receiver};
|
||||
use sys::helper_signal;
|
||||
|
||||
use thread;
|
||||
|
||||
/// A structure for management of a helper thread.
|
||||
///
|
||||
/// This is generally a static structure which tracks the lifetime of a helper
|
||||
/// thread.
|
||||
///
|
||||
/// The fields of this helper are all public, but they should not be used, this
|
||||
/// is for static initialization.
|
||||
pub struct Helper<M:Send> {
|
||||
/// Internal lock which protects the remaining fields
|
||||
pub lock: StaticMutex,
|
||||
pub cond: StaticCondvar,
|
||||
|
||||
// You'll notice that the remaining fields are UnsafeCell<T>, and this is
|
||||
// because all helper thread operations are done through &self, but we need
|
||||
// these to be mutable (once `lock` is held).
|
||||
|
||||
/// Lazily allocated channel to send messages to the helper thread.
|
||||
pub chan: UnsafeCell<*mut Sender<M>>,
|
||||
|
||||
/// OS handle used to wake up a blocked helper thread
|
||||
pub signal: UnsafeCell<usize>,
|
||||
|
||||
/// Flag if this helper thread has booted and been initialized yet.
|
||||
pub initialized: UnsafeCell<bool>,
|
||||
|
||||
/// Flag if this helper thread has shut down
|
||||
pub shutdown: UnsafeCell<bool>,
|
||||
}
|
||||
|
||||
unsafe impl<M:Send> Send for Helper<M> { }
|
||||
|
||||
unsafe impl<M:Send> Sync for Helper<M> { }
|
||||
|
||||
struct RaceBox(helper_signal::signal);
|
||||
|
||||
unsafe impl Send for RaceBox {}
|
||||
unsafe impl Sync for RaceBox {}
|
||||
|
||||
macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
|
||||
static $name: Helper<$m> = Helper {
|
||||
lock: ::sync::MUTEX_INIT,
|
||||
cond: ::sync::CONDVAR_INIT,
|
||||
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
||||
signal: ::cell::UnsafeCell { value: 0 },
|
||||
initialized: ::cell::UnsafeCell { value: false },
|
||||
shutdown: ::cell::UnsafeCell { value: false },
|
||||
};
|
||||
) }
|
||||
|
||||
impl<M: Send> Helper<M> {
|
||||
/// Lazily boots a helper thread, becoming a no-op if the helper has already
|
||||
/// been spawned.
|
||||
///
|
||||
/// This function will check to see if the thread has been initialized, and
|
||||
/// if it has it returns quickly. If initialization has not happened yet,
|
||||
/// the closure `f` will be run (inside of the initialization lock) and
|
||||
/// passed to the helper thread in a separate task.
|
||||
///
|
||||
/// This function is safe to be called many times.
|
||||
pub fn boot<T, F>(&'static self, f: F, helper: fn(helper_signal::signal, Receiver<M>, T)) where
|
||||
T: Send + 'static,
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
unsafe {
|
||||
let _guard = self.lock.lock().unwrap();
|
||||
if *self.chan.get() as usize == 0 {
|
||||
let (tx, rx) = channel();
|
||||
*self.chan.get() = boxed::into_raw(box tx);
|
||||
let (receive, send) = helper_signal::new();
|
||||
*self.signal.get() = send as usize;
|
||||
|
||||
let receive = RaceBox(receive);
|
||||
|
||||
let t = f();
|
||||
thread::spawn(move || {
|
||||
helper(receive.0, rx, t);
|
||||
let _g = self.lock.lock().unwrap();
|
||||
*self.shutdown.get() = true;
|
||||
self.cond.notify_one()
|
||||
});
|
||||
|
||||
let _ = rt::at_exit(move || { self.shutdown() });
|
||||
*self.initialized.get() = true;
|
||||
} else if *self.chan.get() as usize == 1 {
|
||||
panic!("cannot continue usage after shutdown");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends a message to a spawned worker thread.
|
||||
///
|
||||
/// This is only valid if the worker thread has previously booted
|
||||
pub fn send(&'static self, msg: M) {
|
||||
unsafe {
|
||||
let _guard = self.lock.lock().unwrap();
|
||||
|
||||
// Must send and *then* signal to ensure that the child receives the
|
||||
// message. Otherwise it could wake up and go to sleep before we
|
||||
// send the message.
|
||||
assert!(*self.chan.get() as usize != 0);
|
||||
assert!(*self.chan.get() as usize != 1,
|
||||
"cannot continue usage after shutdown");
|
||||
(**self.chan.get()).send(msg).unwrap();
|
||||
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&'static self) {
|
||||
unsafe {
|
||||
// Shut down, but make sure this is done inside our lock to ensure
|
||||
// that we'll always receive the exit signal when the thread
|
||||
// returns.
|
||||
let mut guard = self.lock.lock().unwrap();
|
||||
|
||||
let ptr = *self.chan.get();
|
||||
if ptr as usize == 1 {
|
||||
panic!("cannot continue usage after shutdown");
|
||||
}
|
||||
// Close the channel by destroying it
|
||||
let chan = Box::from_raw(*self.chan.get());
|
||||
*self.chan.get() = 1 as *mut Sender<M>;
|
||||
drop(chan);
|
||||
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
||||
|
||||
// Wait for the child to exit
|
||||
while !*self.shutdown.get() {
|
||||
guard = self.cond.wait(guard).unwrap();
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
// Clean up after ourselves
|
||||
self.lock.destroy();
|
||||
helper_signal::close(*self.signal.get() as helper_signal::signal);
|
||||
*self.signal.get() = 0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue