Commit 2c222eda authored by Ralf's avatar Ralf

document a bunch of stuff

parent 32f592df
......@@ -2,7 +2,7 @@ use std::time::Duration;
use actors::{Actor, LockAction};
use input::Event;
use util::wakeable::{spawn_wakeable, prepare_wakeable};
use util::wakeable::Wakeable;
use brain::environment::*;
use brain::handlers;
use brain::{Actors, State};
......@@ -23,7 +23,7 @@ impl State for UnLockingState {
// TODO: abort if already locked
let locking = self.locking;
for _ in 0..3 {
let locker = spawn_wakeable(actors.lock, (), move |t, mut lock_actor, _| {
let locker = Wakeable::spawn(actors.lock, (), move |t, mut lock_actor, _| {
lock_actor.act(if locking {
LockAction::PressLock
} else {
......@@ -65,7 +65,7 @@ impl OpenState {
impl State for OpenState {
fn run(&mut self, mut actors: Actors, env: &mut Environment) -> Option<Box<State>> {
let mut buzzer = prepare_wakeable(actors.buzz, move |t, mut buzz_actor, d| {
let mut buzzer = Wakeable::new(actors.buzz, move |t, mut buzz_actor, d| {
buzz_actor.act(true);
t.sleep(d);
buzz_actor.act(false);
......@@ -74,7 +74,7 @@ impl State for OpenState {
let r = handle_events!(env,
EventHandler::new_safe(|ev| {
if let Event::Bell(true) = ev {
buzzer.spawn(Duration::from_secs(2));
buzzer.respawn(Duration::from_secs(2));
}
}));
actors.buzz = buzzer.terminate();
......
//! This module implements *wakeable*, *ownership-threading* threads.
//! "Wakeable" here means that that thread can be "woken up" if it uses
//! the special sleep function provided to it, so that it terminates earlier.
//! "Onwership-threading" means that a piece of exclusive ownership T is handed
//! to the thread when it is created -- but before it is even run -- which will
//! be passed to the actual closure that runs in the new thread. The closure
//! has to return that ownership again.
//! Because of this threading, a weakeable thread can at any time be asked
//! to give back the T that is has. If necessary, it will stop the thread to
//! get hold of the T faster.
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 {
Yes,
No,
}
struct ThreadState {
mutex: Mutex<ShouldThreadRun>,
cond: Condvar,
/// Represents a Wakeable thread govering T, running closure F.
pub struct Wakeable<T, F> {
w_state: WakeableState<T>,
fun: Arc<F>,
}
/// The state of a Wakeable: Either the thread has not been spawned yet,
/// or we have a handle to get the T when returned by the thread, plus
/// a way to talk to it (the ThreadState).
enum WakeableState<T> {
Lazy(T),
Running(thread::JoinHandle<T>, Arc<ThreadState>)
}
pub struct WakeableHandle<T, F> {
w_state: WakeableState<T>, // invariant: This is never empty when control is to the user
fun: Arc<F>,
}
pub struct WakeableThread {
state: Arc<ThreadState>,
}
pub fn prepare_wakeable<D, F, T>(t: T, f: F) -> WakeableHandle<T, F>
where D: Send + 'static,
T: Send + 'static,
F: Fn(WakeableThread, T, D) -> T + Send + Sync + 'static
{
WakeableHandle {
w_state: WakeableState::Lazy(t),
fun: Arc::new(f),
}
}
pub fn spawn_wakeable<D, F, T>(t: T, d: D, f: F) -> WakeableHandle<T, F>
where D: Send + 'static,
T: Send + 'static,
F: Fn(WakeableThread, T, D) -> T + Send + Sync + 'static
{
let mut handle = prepare_wakeable(t, f);
handle.spawn(d);
handle
}
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
},
impl<T, F> Wakeable<T, F> {
/// This constructor creates a new Wakeable with the given owned data T
/// and closure F. No thread is started, the wakeable is only prepared.
/// The type D describes additional data that can be passed to F whenever
/// it is triggered.
pub fn new<D>(t: T, f: F) -> Wakeable<T, F>
where D: Send + 'static,
T: Send + 'static,
F: Fn(WakeableThread, T, D) -> T + Send + Sync + 'static
{
Wakeable {
w_state: WakeableState::Lazy(t),
fun: Arc::new(f),
}
}
}
/// Like [new], but immediately spawns the thread
pub fn spawn<D>(t: T, d: D, f: F) -> Wakeable<T, F>
where D: Send + 'static,
T: Send + 'static,
F: Fn(WakeableThread, T, D) -> T + Send + Sync + 'static
{
let mut handle = Wakeable::new(t, f);
handle.respawn(d);
handle
}
impl<T, F> WakeableHandle<T, F> {
pub fn spawn<D>(&mut self, d: D)
/// (Re-)spawns the wakeable thread, potentially stopping the still running
/// current rhead.
pub fn respawn<D>(&mut self, d: D)
where D: Send + 'static,
T: Send + 'static,
F: Fn(WakeableThread, T, D) -> T + Send + Sync + 'static
......@@ -83,13 +79,65 @@ impl<T, F> WakeableHandle<T, F> {
WakeableState::Running(handle, state)
});
}
/// Returns the T managed by the Wakeable, potentially termianting a still
/// running thread.
pub fn terminate(self) -> T {
self.w_state.get_t()
}
}
impl<T> WakeableState<T> {
/// Extracts the T from this state, by terminating the thread if necessary.
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
},
}
}
}
/// This structure is provided to thrads spawned by Wakeable, It provides
/// the thread-side API of this module.
pub struct WakeableThread {
state: Arc<ThreadState>,
}
/// Defines whether the thread should be running right now, or whether it
/// should try to terminate as quickly as possible.
#[derive(PartialEq,Eq,Debug,Copy,Clone)]
pub enum ShouldThreadRun {
Yes,
No,
}
impl WakeableThread {
/// Sleeps for the given duration, making sure that we immediately wake
/// up if the thread should terminate.
/// Returns whether the thread should terminate, i.e., whether we slept
/// for the full lngth.
pub fn sleep(&self, d: Duration) -> ShouldThreadRun {
self.state.sleep(d)
}
/// Returns the current "should we terminate" state.
pub fn should_terminate(&self) -> bool {
self.state.should_terminate()
}
}
/// Manages the state of a thread spawned by Wakeable. used to signal
/// "wake up" to sleeping threads.
struct ThreadState {
mutex: Mutex<ShouldThreadRun>,
cond: Condvar,
}
impl ThreadState {
/// Signals the thread to "wake up".
fn wakeup(&self) {
// We panic if the lock is poisened, which only happens if someone paniced
let mut should_run = self.mutex.lock().unwrap();
......@@ -97,7 +145,8 @@ impl ThreadState {
self.cond.notify_one();
}
pub fn sleep(&self, d: Duration) -> ShouldThreadRun {
/// Sleeps for the given duration, waking up earlier if signalled.
fn sleep(&self, d: Duration) -> ShouldThreadRun {
// We panic if the lock is poisened, which only happens if someone paniced
let should_run = self.mutex.lock().unwrap();
// check if we have to terminate early
......@@ -108,10 +157,11 @@ impl ThreadState {
let (should_run, _) = self.cond.wait_timeout(should_run, d).unwrap();
return *should_run;
}
}
impl WakeableThread {
pub fn sleep(&self, d: Duration) -> ShouldThreadRun {
self.state.sleep(d)
/// Returns whether the thread should terminate.
fn should_terminate(&self) -> bool {
// We panic if the lock is poisened, which only happens if someone paniced
let should_run = self.mutex.lock().unwrap();
return *should_run == ShouldThreadRun::No
}
}
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