Commit 32f592df authored by Ralf's avatar Ralf

get rid of Empty WakeableState, thanks to take_mut

parent 5cb81035
......@@ -4,6 +4,7 @@ version = "0.1.0"
dependencies = [
"chan 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"take_mut 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -35,3 +36,8 @@ dependencies = [
"libc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "take_mut"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
......@@ -6,3 +6,4 @@ authors = ["Constantin Berhard <git.mail.enormator@xoxy.net>"]
[dependencies]
log = "0.3.5"
chan = "0.1.14"
take_mut = "0.1.3"
......@@ -4,6 +4,7 @@
// FIXME: While we are still prototyping, allow missing docs
#![allow(missing_docs)]
extern crate take_mut;
#[macro_use]
extern crate log;
#[macro_use]
......
use std::{mem, thread};
use std::thread;
use std::time::Duration;
use std::sync::{Arc, Mutex, Condvar};
use take_mut;
#[derive(PartialEq,Eq,Debug,Copy,Clone)]
pub enum ShouldThreadRun {
......@@ -15,8 +16,7 @@ struct ThreadState {
enum WakeableState<T> {
Lazy(T),
Running(thread::JoinHandle<T>, Arc<ThreadState>),
Empty,
Running(thread::JoinHandle<T>, Arc<ThreadState>)
}
pub struct WakeableHandle<T, F> {
......@@ -49,56 +49,43 @@ pub fn spawn_wakeable<D, F, T>(t: T, d: D, f: F) -> WakeableHandle<T, F>
handle
}
impl<T, F> WakeableHandle<T, F> {
pub fn spawn<D>(&mut self, d: D)
where D: Send + 'static,
T: Send + 'static,
F: Fn(WakeableThread, T, D) -> T + Send + Sync + 'static
{
// get ahand of the t, wherever it is
let t = self.get_t();
// prepare the state mgmt for this thread
let state = Arc::new(ThreadState {
mutex: Mutex::new(ShouldThreadRun::Yes),
cond: Condvar::new(),
});
let thread = WakeableThread { state: state.clone() };
// spawn the next thread with this
let fun = self.fun.clone();
let handle = thread::spawn(move || fun(thread, t, d));
// store everything back into our state
self.w_state = WakeableState::Running(handle, state);
}
/// This is "unsafe" because it leaves the handle in the empty state, which
/// can cause panics.
fn get_t(&mut self) -> T {
let w_state = mem::replace(&mut self.w_state, WakeableState::Empty);
match w_state {
impl<T> WakeableState<T> {
fn get_t(self) -> T {
match self {
WakeableState::Lazy(t) => t,
WakeableState::Running(handle, state) => {
state.wakeup();
handle.join().unwrap() // panics only if the thread paniced
}
WakeableState::Empty => panic!("The WakeableState can not be empty"),
},
}
}
}
pub fn terminate(mut self) -> T {
self.get_t() // This is fine to call, because the handle will be destroyed
impl<T, F> WakeableHandle<T, F> {
pub fn spawn<D>(&mut self, d: D)
where D: Send + 'static,
T: Send + 'static,
F: Fn(WakeableThread, T, D) -> T + Send + Sync + 'static
{
let fun = self.fun.clone();
take_mut::take(&mut self.w_state, |w_state| {
// get ahand of the t, wherever it is
let t = w_state.get_t();
// prepare the state mgmt for this thread
let state = Arc::new(ThreadState {
mutex: Mutex::new(ShouldThreadRun::Yes),
cond: Condvar::new(),
});
let thread = WakeableThread { state: state.clone() };
// spawn the next thread with this
let handle = thread::spawn(move || fun(thread, t, d));
// store everything back into our state
WakeableState::Running(handle, state)
});
}
}
impl<T, F> Drop for WakeableHandle<F, T> {
fn drop(&mut self) {
match self.w_state {
WakeableState::Empty => {} // all right, the user called "terminate"
WakeableState::Lazy(_) => {} // we were never used :( TODO: emit a warning?
WakeableState::Running(_, ref state) => {
// the thread could still be running. emit a warning? Also, speed up the shutdown
state.wakeup();
}
};
pub fn terminate(self) -> T {
self.w_state.get_t()
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment