2014-05-05 16:58:42 -07:00
|
|
|
// 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.
|
|
|
|
|
2014-12-22 09:04:23 -08:00
|
|
|
use prelude::v1::*;
|
2014-11-24 11:16:40 -08:00
|
|
|
|
2015-02-23 02:58:22 +03:00
|
|
|
use boxed;
|
2014-11-24 11:16:40 -08:00
|
|
|
use cell::UnsafeCell;
|
2015-01-19 08:27:09 +03:00
|
|
|
use ptr;
|
2014-11-24 17:33:37 -08:00
|
|
|
use rt;
|
2014-12-22 09:04:23 -08:00
|
|
|
use sync::{StaticMutex, StaticCondvar};
|
2014-12-23 11:53:35 -08:00
|
|
|
use sync::mpsc::{channel, Sender, Receiver};
|
2014-10-15 15:45:59 -07:00
|
|
|
use sys::helper_signal;
|
2014-05-05 16:58:42 -07:00
|
|
|
|
2015-02-17 15:10:25 -08:00
|
|
|
use thread;
|
2014-05-05 16:58:42 -07:00
|
|
|
|
|
|
|
/// 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> {
|
|
|
|
/// Internal lock which protects the remaining fields
|
2014-11-24 11:16:40 -08:00
|
|
|
pub lock: StaticMutex,
|
|
|
|
pub cond: StaticCondvar,
|
2014-05-05 16:58:42 -07:00
|
|
|
|
std: Stabilize unit, bool, ty, tuple, arc, any
This commit applies stability attributes to the contents of these modules,
summarized here:
* The `unit` and `bool` modules have become #[unstable] as they are purely meant
for documentation purposes and are candidates for removal.
* The `ty` module has been deprecated, and the inner `Unsafe` type has been
renamed to `UnsafeCell` and moved to the `cell` module. The `marker1` field
has been removed as the compiler now always infers `UnsafeCell` to be
invariant. The `new` method i stable, but the `value` field, `get` and
`unwrap` methods are all unstable.
* The `tuple` module has its name as stable, the naming of the `TupleN` traits
as stable while the methods are all #[unstable]. The other impls in the module
have appropriate stability for the corresponding trait.
* The `arc` module has received the exact same treatment as the `rc` module
previously did.
* The `any` module has its name as stable. The `Any` trait is also stable, with
a new private supertrait which now contains the `get_type_id` method. This is
to make the method a private implementation detail rather than a public-facing
detail.
The two extension traits in the module are marked #[unstable] as they will not
be necessary with DST. The `is` method is #[stable], the as_{mut,ref} methods
have been renamed to downcast_{mut,ref} and are #[unstable].
The extension trait `BoxAny` has been clarified as to why it is unstable as it
will not be necessary with DST.
This is a breaking change because the `marker1` field was removed from the
`UnsafeCell` type. To deal with this change, you can simply delete the field and
only specify the value of the `data` field in static initializers.
[breaking-change]
2014-07-23 19:10:12 -07:00
|
|
|
// You'll notice that the remaining fields are UnsafeCell<T>, and this is
|
2014-05-05 16:58:42 -07:00
|
|
|
// 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.
|
std: Stabilize unit, bool, ty, tuple, arc, any
This commit applies stability attributes to the contents of these modules,
summarized here:
* The `unit` and `bool` modules have become #[unstable] as they are purely meant
for documentation purposes and are candidates for removal.
* The `ty` module has been deprecated, and the inner `Unsafe` type has been
renamed to `UnsafeCell` and moved to the `cell` module. The `marker1` field
has been removed as the compiler now always infers `UnsafeCell` to be
invariant. The `new` method i stable, but the `value` field, `get` and
`unwrap` methods are all unstable.
* The `tuple` module has its name as stable, the naming of the `TupleN` traits
as stable while the methods are all #[unstable]. The other impls in the module
have appropriate stability for the corresponding trait.
* The `arc` module has received the exact same treatment as the `rc` module
previously did.
* The `any` module has its name as stable. The `Any` trait is also stable, with
a new private supertrait which now contains the `get_type_id` method. This is
to make the method a private implementation detail rather than a public-facing
detail.
The two extension traits in the module are marked #[unstable] as they will not
be necessary with DST. The `is` method is #[stable], the as_{mut,ref} methods
have been renamed to downcast_{mut,ref} and are #[unstable].
The extension trait `BoxAny` has been clarified as to why it is unstable as it
will not be necessary with DST.
This is a breaking change because the `marker1` field was removed from the
`UnsafeCell` type. To deal with this change, you can simply delete the field and
only specify the value of the `data` field in static initializers.
[breaking-change]
2014-07-23 19:10:12 -07:00
|
|
|
pub chan: UnsafeCell<*mut Sender<M>>,
|
2014-05-05 16:58:42 -07:00
|
|
|
|
|
|
|
/// OS handle used to wake up a blocked helper thread
|
std: Stabilize unit, bool, ty, tuple, arc, any
This commit applies stability attributes to the contents of these modules,
summarized here:
* The `unit` and `bool` modules have become #[unstable] as they are purely meant
for documentation purposes and are candidates for removal.
* The `ty` module has been deprecated, and the inner `Unsafe` type has been
renamed to `UnsafeCell` and moved to the `cell` module. The `marker1` field
has been removed as the compiler now always infers `UnsafeCell` to be
invariant. The `new` method i stable, but the `value` field, `get` and
`unwrap` methods are all unstable.
* The `tuple` module has its name as stable, the naming of the `TupleN` traits
as stable while the methods are all #[unstable]. The other impls in the module
have appropriate stability for the corresponding trait.
* The `arc` module has received the exact same treatment as the `rc` module
previously did.
* The `any` module has its name as stable. The `Any` trait is also stable, with
a new private supertrait which now contains the `get_type_id` method. This is
to make the method a private implementation detail rather than a public-facing
detail.
The two extension traits in the module are marked #[unstable] as they will not
be necessary with DST. The `is` method is #[stable], the as_{mut,ref} methods
have been renamed to downcast_{mut,ref} and are #[unstable].
The extension trait `BoxAny` has been clarified as to why it is unstable as it
will not be necessary with DST.
This is a breaking change because the `marker1` field was removed from the
`UnsafeCell` type. To deal with this change, you can simply delete the field and
only specify the value of the `data` field in static initializers.
[breaking-change]
2014-07-23 19:10:12 -07:00
|
|
|
pub signal: UnsafeCell<uint>,
|
2014-05-05 16:58:42 -07:00
|
|
|
|
|
|
|
/// Flag if this helper thread has booted and been initialized yet.
|
std: Stabilize unit, bool, ty, tuple, arc, any
This commit applies stability attributes to the contents of these modules,
summarized here:
* The `unit` and `bool` modules have become #[unstable] as they are purely meant
for documentation purposes and are candidates for removal.
* The `ty` module has been deprecated, and the inner `Unsafe` type has been
renamed to `UnsafeCell` and moved to the `cell` module. The `marker1` field
has been removed as the compiler now always infers `UnsafeCell` to be
invariant. The `new` method i stable, but the `value` field, `get` and
`unwrap` methods are all unstable.
* The `tuple` module has its name as stable, the naming of the `TupleN` traits
as stable while the methods are all #[unstable]. The other impls in the module
have appropriate stability for the corresponding trait.
* The `arc` module has received the exact same treatment as the `rc` module
previously did.
* The `any` module has its name as stable. The `Any` trait is also stable, with
a new private supertrait which now contains the `get_type_id` method. This is
to make the method a private implementation detail rather than a public-facing
detail.
The two extension traits in the module are marked #[unstable] as they will not
be necessary with DST. The `is` method is #[stable], the as_{mut,ref} methods
have been renamed to downcast_{mut,ref} and are #[unstable].
The extension trait `BoxAny` has been clarified as to why it is unstable as it
will not be necessary with DST.
This is a breaking change because the `marker1` field was removed from the
`UnsafeCell` type. To deal with this change, you can simply delete the field and
only specify the value of the `data` field in static initializers.
[breaking-change]
2014-07-23 19:10:12 -07:00
|
|
|
pub initialized: UnsafeCell<bool>,
|
2014-11-24 11:16:40 -08:00
|
|
|
|
|
|
|
/// Flag if this helper thread has shut down
|
|
|
|
pub shutdown: UnsafeCell<bool>,
|
2014-05-05 16:58:42 -07:00
|
|
|
}
|
|
|
|
|
2014-12-22 00:49:42 +01:00
|
|
|
unsafe impl<M:Send> Send for Helper<M> { }
|
2014-12-06 11:39:25 -05:00
|
|
|
|
2014-12-22 00:49:42 +01:00
|
|
|
unsafe impl<M:Send> Sync for Helper<M> { }
|
2014-12-06 11:39:25 -05:00
|
|
|
|
2014-12-24 17:40:40 +01:00
|
|
|
struct RaceBox(helper_signal::signal);
|
|
|
|
|
|
|
|
unsafe impl Send for RaceBox {}
|
|
|
|
unsafe impl Sync for RaceBox {}
|
|
|
|
|
2014-05-05 16:58:42 -07:00
|
|
|
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.
|
2014-12-07 14:15:25 -05:00
|
|
|
pub fn boot<T, F>(&'static self, f: F, helper: fn(helper_signal::signal, Receiver<M>, T)) where
|
2015-02-13 22:58:37 +11:00
|
|
|
T: Send + 'static,
|
2014-12-07 14:15:25 -05:00
|
|
|
F: FnOnce() -> T,
|
|
|
|
{
|
2014-05-05 16:58:42 -07:00
|
|
|
unsafe {
|
2014-12-08 20:20:03 -08:00
|
|
|
let _guard = self.lock.lock().unwrap();
|
2014-05-05 16:58:42 -07:00
|
|
|
if !*self.initialized.get() {
|
|
|
|
let (tx, rx) = channel();
|
2015-02-23 02:58:22 +03:00
|
|
|
*self.chan.get() = boxed::into_raw(box tx);
|
2014-10-15 15:45:59 -07:00
|
|
|
let (receive, send) = helper_signal::new();
|
2014-05-05 16:58:42 -07:00
|
|
|
*self.signal.get() = send as uint;
|
|
|
|
|
2014-12-24 17:40:40 +01:00
|
|
|
let receive = RaceBox(receive);
|
|
|
|
|
2014-05-05 16:58:42 -07:00
|
|
|
let t = f();
|
2015-02-17 15:10:25 -08:00
|
|
|
thread::spawn(move || {
|
2014-12-24 17:40:40 +01:00
|
|
|
helper(receive.0, rx, t);
|
2014-12-08 20:20:03 -08:00
|
|
|
let _g = self.lock.lock().unwrap();
|
2014-11-24 11:16:40 -08:00
|
|
|
*self.shutdown.get() = true;
|
|
|
|
self.cond.notify_one()
|
2015-01-05 21:59:45 -08:00
|
|
|
});
|
2014-05-05 16:58:42 -07:00
|
|
|
|
2015-02-01 12:44:15 -05:00
|
|
|
rt::at_exit(move|| { self.shutdown() });
|
2014-05-05 16:58:42 -07:00
|
|
|
*self.initialized.get() = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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 {
|
2014-12-08 20:20:03 -08:00
|
|
|
let _guard = self.lock.lock().unwrap();
|
2014-05-05 16:58:42 -07:00
|
|
|
|
|
|
|
// 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().is_null());
|
2014-12-23 11:53:35 -08:00
|
|
|
(**self.chan.get()).send(msg).unwrap();
|
2014-10-15 15:45:59 -07:00
|
|
|
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
2014-05-05 16:58:42 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2014-12-08 20:20:03 -08:00
|
|
|
let mut guard = self.lock.lock().unwrap();
|
2014-05-05 16:58:42 -07:00
|
|
|
|
|
|
|
// Close the channel by destroying it
|
2015-02-23 02:58:22 +03:00
|
|
|
let chan: Box<Sender<M>> = Box::from_raw(*self.chan.get());
|
2015-01-19 08:27:09 +03:00
|
|
|
*self.chan.get() = ptr::null_mut();
|
2014-05-05 16:58:42 -07:00
|
|
|
drop(chan);
|
2014-10-15 15:45:59 -07:00
|
|
|
helper_signal::signal(*self.signal.get() as helper_signal::signal);
|
2014-05-05 16:58:42 -07:00
|
|
|
|
|
|
|
// Wait for the child to exit
|
2014-11-24 11:16:40 -08:00
|
|
|
while !*self.shutdown.get() {
|
2014-12-08 20:20:03 -08:00
|
|
|
guard = self.cond.wait(guard).unwrap();
|
2014-11-24 11:16:40 -08:00
|
|
|
}
|
2014-05-05 16:58:42 -07:00
|
|
|
drop(guard);
|
|
|
|
|
|
|
|
// Clean up after ourselves
|
|
|
|
self.lock.destroy();
|
2014-10-15 15:45:59 -07:00
|
|
|
helper_signal::close(*self.signal.get() as helper_signal::signal);
|
2014-05-05 16:58:42 -07:00
|
|
|
*self.signal.get() = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|