<commit_before>use Cursive;
use With;
use event::{Callback, Event, EventResult};
use std::collections::HashMap;
use std::rc::Rc;
use view::{View, ViewWrapper};

/// A wrapper view that can react to events.
///
/// This view registers a set of callbacks tied to specific events, to be run
/// in certain conditions.
///
/// * Some callbacks are called only for vents ignored by the wrapped view
///   (those registered by [`on_event`] or [`on_event_inner`])
/// * Others are processed first, and can control whether the child view should
///   be given the event (those registered by [`on_pre_event`] or
///   [`on_pre_event_inner`]).
///
/// "Inner" callbacks ([`on_event_inner`] and [`on_pre_event_inner`]) are given
/// a reference to the inner wrapped view (but not to the `Cursive` root). They
/// can then return another callback, taking only a `&mut Cursive` root as
/// argument.
///
/// "Simple" callbacks ([`on_event`] and [`on_pre_event`]) skip this first
/// phase and are only called with a `&mut Cursive`.
///
/// [`on_event`]: struct.OnEventView.html#method.on_event
/// [`on_pre_event`]: struct.OnEventView.html#method.on_pre_event
/// [`on_event_inner`]: struct.OnEventView.html#method.on_event_inner
/// [`on_pre_event_inner`]: struct.OnEventView.html#method.on_pre_event_inner
///
/// # Examples
///
/// ```
/// # use cursive::event;;
/// # use cursive::views::{OnEventView, TextView};
/// let view = OnEventView::new(TextView::new("This view has an event!"))
///                         .on_event('q', |s| s.quit())
///                         .on_event(event::Key::Esc, |s| s.quit());
/// ```
pub struct OnEventView<T: View> {
    inner: T,
    callbacks: HashMap<Event, Action<T>>,
}

type InnerCallback<T> = Rc<Box<Fn(&mut T) -> Option<EventResult>>>;

struct Action<T> {
    phase: TriggerPhase,
    callback: InnerCallback<T>,
}

impl<T> Clone for Action<T> {
    fn clone(&self) -> Self {
        Action {
            phase: self.phase.clone(),
            callback: Rc::clone(&self.callback),
        }
    }
}

#[derive(PartialEq, Clone)]
enum TriggerPhase {
    BeforeChild,
    AfterChild,
}

impl<T: View> OnEventView<T> {
    /// Wraps the given view in a new OnEventView.
    pub fn new(view: T) -> Self {
        OnEventView {
            inner: view,
            callbacks: HashMap::new(),
        }
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// Chainable variant.
    pub fn on_event<F, R, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        self.with(|s| s.set_on_event(event, cb))
    }

    /// Registers a callback when the given event is received.
    ///
    /// The child will never receive this event.
    ///
    /// Chainable variant.
    pub fn on_pre_event<F, R, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        self.with(|s| s.set_on_pre_event(event, cb))
    }

    /// Registers a callback when the given event is received.
    ///
    /// The given callback will be run before the child view sees the event.
    ///
    /// * If the result is `None`, then the child view is given the event as
    ///   usual.
    /// * Otherwise, it bypasses the child view and directly processes the
    ///   result.
    ///
    /// Chainable variant.
    pub fn on_pre_event_inner<F, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.with(|s| s.set_on_pre_event_inner(event, cb))
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// If the child view ignores the event, `cb` will be called with the
    /// child view as argument.
    /// If the result is not `None`, it will be processed as well.
    ///
    /// Chainable variant.
    pub fn on_event_inner<F, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.with(|s| s.set_on_event_inner(event, cb))
    }

    /// Registers a callback when the given event is ignored by the child.
    pub fn set_on_event<F, R, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut Cursive) -> R + 'static,
    {
        let cb = Callback::from_fn(cb);
        let action =
            move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

        self.set_on_event_inner(event, action);
    }

    /// Registers a callback when the given event is received.
    ///
    /// The child will never receive this event.
    pub fn set_on_pre_event<F, R, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        let cb = Callback::from_fn(cb);
        // We want to clone the Callback every time we call the closure
        let action =
            move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

        self.set_on_pre_event_inner(event, action);
    }

    /// Registers a callback when the given event is received.
    ///
    /// The given callback will be run before the child view sees the event.
    ///
    /// * If the result is `None`, then the child view is given the event as
    ///   usual.
    /// * Otherwise, it bypasses the child view and directly processes the
    ///   result.
    pub fn set_on_pre_event_inner<F, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.callbacks.insert(
            event.into(),
            Action {
                phase: TriggerPhase::BeforeChild,
                callback: Rc::new(Box::new(cb)),
            },
        );
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// If the child view ignores the event, `cb` will be called with the
    /// child view as argument.
    /// If the result is not `None`, it will be processed as well.
    pub fn set_on_event_inner<F, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.callbacks.insert(
            event.into(),
            Action {
                phase: TriggerPhase::AfterChild,
                callback: Rc::new(Box::new(cb)),
            },
        );
    }
}

impl<T: View> ViewWrapper for OnEventView<T> {
    wrap_impl!(self.inner: T);

    fn wrap_on_event(&mut self, event: Event) -> EventResult {
        let action = self.callbacks.get(&event).cloned();
        let pre_child = action
            .as_ref()
            .map(|a| a.phase == TriggerPhase::BeforeChild)
            .unwrap_or(false);

        if pre_child {
            action
                .and_then(|a| (*a.callback)(&mut self.inner))
                .unwrap_or_else(|| self.inner.on_event(event))
        } else {
            self.inner.on_event(event).or_else(|| {
                action
                    .and_then(|a| (*a.callback)(&mut self.inner))
                    .unwrap_or(EventResult::Ignored)
            })
        }
    }
}
<commit_msg>OnEventView: add note regarding single callback per event<commit_after>use Cursive;
use With;
use event::{Callback, Event, EventResult};
use std::collections::HashMap;
use std::rc::Rc;
use view::{View, ViewWrapper};

/// A wrapper view that can react to events.
///
/// This view registers a set of callbacks tied to specific events, to be run
/// in certain conditions.
///
/// **Note**: only one callback can be registered per event. Trying to register
/// a new one will replace any existing one for that event.
///
/// * Some callbacks are called only for vents ignored by the wrapped view
///   (those registered by [`on_event`] or [`on_event_inner`])
/// * Others are processed first, and can control whether the child view should
///   be given the event (those registered by [`on_pre_event`] or
///   [`on_pre_event_inner`]).
///
/// "Inner" callbacks ([`on_event_inner`] and [`on_pre_event_inner`]) are given
/// a reference to the inner wrapped view (but not to the `Cursive` root). They
/// can then return another callback, taking only a `&mut Cursive` root as
/// argument.
///
/// "Simple" callbacks ([`on_event`] and [`on_pre_event`]) skip this first
/// phase and are only called with a `&mut Cursive`.
///
/// [`on_event`]: struct.OnEventView.html#method.on_event
/// [`on_pre_event`]: struct.OnEventView.html#method.on_pre_event
/// [`on_event_inner`]: struct.OnEventView.html#method.on_event_inner
/// [`on_pre_event_inner`]: struct.OnEventView.html#method.on_pre_event_inner
///
/// # Examples
///
/// ```
/// # use cursive::event;;
/// # use cursive::views::{OnEventView, TextView};
/// let view = OnEventView::new(TextView::new("This view has an event!"))
///                         .on_event('q', |s| s.quit())
///                         .on_event(event::Key::Esc, |s| s.quit());
/// ```
pub struct OnEventView<T: View> {
    inner: T,
    callbacks: HashMap<Event, Action<T>>,
}

type InnerCallback<T> = Rc<Box<Fn(&mut T) -> Option<EventResult>>>;

struct Action<T> {
    phase: TriggerPhase,
    callback: InnerCallback<T>,
}

impl<T> Clone for Action<T> {
    fn clone(&self) -> Self {
        Action {
            phase: self.phase.clone(),
            callback: Rc::clone(&self.callback),
        }
    }
}

#[derive(PartialEq, Clone)]
enum TriggerPhase {
    BeforeChild,
    AfterChild,
}

impl<T: View> OnEventView<T> {
    /// Wraps the given view in a new OnEventView.
    pub fn new(view: T) -> Self {
        OnEventView {
            inner: view,
            callbacks: HashMap::new(),
        }
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// Chainable variant.
    pub fn on_event<F, R, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        self.with(|s| s.set_on_event(event, cb))
    }

    /// Registers a callback when the given event is received.
    ///
    /// The child will never receive this event.
    ///
    /// Chainable variant.
    pub fn on_pre_event<F, R, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        self.with(|s| s.set_on_pre_event(event, cb))
    }

    /// Registers a callback when the given event is received.
    ///
    /// The given callback will be run before the child view sees the event.
    ///
    /// * If the result is `None`, then the child view is given the event as
    ///   usual.
    /// * Otherwise, it bypasses the child view and directly processes the
    ///   result.
    ///
    /// Chainable variant.
    pub fn on_pre_event_inner<F, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.with(|s| s.set_on_pre_event_inner(event, cb))
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// If the child view ignores the event, `cb` will be called with the
    /// child view as argument.
    /// If the result is not `None`, it will be processed as well.
    ///
    /// Chainable variant.
    pub fn on_event_inner<F, E>(self, event: E, cb: F) -> Self
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.with(|s| s.set_on_event_inner(event, cb))
    }

    /// Registers a callback when the given event is ignored by the child.
    pub fn set_on_event<F, R, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut Cursive) -> R + 'static,
    {
        let cb = Callback::from_fn(cb);
        let action =
            move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

        self.set_on_event_inner(event, action);
    }

    /// Registers a callback when the given event is received.
    ///
    /// The child will never receive this event.
    pub fn set_on_pre_event<F, R, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: 'static + Fn(&mut Cursive) -> R,
    {
        let cb = Callback::from_fn(cb);
        // We want to clone the Callback every time we call the closure
        let action =
            move |_: &mut T| Some(EventResult::Consumed(Some(cb.clone())));

        self.set_on_pre_event_inner(event, action);
    }

    /// Registers a callback when the given event is received.
    ///
    /// The given callback will be run before the child view sees the event.
    ///
    /// * If the result is `None`, then the child view is given the event as
    ///   usual.
    /// * Otherwise, it bypasses the child view and directly processes the
    ///   result.
    pub fn set_on_pre_event_inner<F, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.callbacks.insert(
            event.into(),
            Action {
                phase: TriggerPhase::BeforeChild,
                callback: Rc::new(Box::new(cb)),
            },
        );
    }

    /// Registers a callback when the given event is ignored by the child.
    ///
    /// If the child view ignores the event, `cb` will be called with the
    /// child view as argument.
    /// If the result is not `None`, it will be processed as well.
    pub fn set_on_event_inner<F, E>(&mut self, event: E, cb: F)
    where
        E: Into<Event>,
        F: Fn(&mut T) -> Option<EventResult> + 'static,
    {
        self.callbacks.insert(
            event.into(),
            Action {
                phase: TriggerPhase::AfterChild,
                callback: Rc::new(Box::new(cb)),
            },
        );
    }
}

impl<T: View> ViewWrapper for OnEventView<T> {
    wrap_impl!(self.inner: T);

    fn wrap_on_event(&mut self, event: Event) -> EventResult {
        let action = self.callbacks.get(&event).cloned();
        let pre_child = action
            .as_ref()
            .map(|a| a.phase == TriggerPhase::BeforeChild)
            .unwrap_or(false);

        if pre_child {
            action
                .and_then(|a| (*a.callback)(&mut self.inner))
                .unwrap_or_else(|| self.inner.on_event(event))
        } else {
            self.inner.on_event(event).or_else(|| {
                action
                    .and_then(|a| (*a.callback)(&mut self.inner))
                    .unwrap_or(EventResult::Ignored)
            })
        }
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#![crate_type = "bin"]

#![allow(unused_must_use, non_upper_case_globals)]

extern crate sysinfo;
extern crate libc;

use sysinfo::{ProcessExt, ProcessorExt, Signal, System, SystemExt};
use sysinfo::Signal::*;
use std::io::{self, BufRead};
use std::str::FromStr;
use std::io::Write;
use libc::pid_t;

const signals: [Signal; 31] = [Hangup, Interrupt, Quit, Illegal, Trap, Abort, Bus,
                               FloatingPointException, Kill, User1, Segv, User2, Pipe, Alarm,
                               Term, Stklft, Child, Continue, Stop, TSTP, TTIN, TTOU, Urgent,
                               XCPU, XFSZ, VirtualAlarm, Profiling, Winch, IO, Power, Sys];

fn print_help() {
    writeln!(&mut io::stdout(), "== Help menu ==");
    writeln!(&mut io::stdout(), "help               : show this menu");
    writeln!(&mut io::stdout(), "signals            : show the available signals");
    writeln!(&mut io::stdout(), "refresh            : reloads processes' information");
    writeln!(&mut io::stdout(), "refresh_disks      : reloads only disks' information");
    writeln!(&mut io::stdout(), "show [pid | name]  : show information of the given process \
                                 corresponding to [pid | name]");
    writeln!(&mut io::stdout(), "kill [pid] [signal]: send [signal] to the process with this \
                                 [pid]. 0 < [signal] < 32");
    writeln!(&mut io::stdout(), "proc               : Displays proc state");
    writeln!(&mut io::stdout(), "memory             : Displays memory state");
    writeln!(&mut io::stdout(), "temperature        : Displays components' temperature");
    writeln!(&mut io::stdout(), "disks              : Displays disks' information");
    writeln!(&mut io::stdout(), "all                : Displays all process name and pid");
    writeln!(&mut io::stdout(), "quit               : exit the program");
}

fn interpret_input(input: &str, sys: &mut System) -> bool {
    match input.trim() {
        "help" => print_help(),
        "refresh" => {
            writeln!(&mut io::stdout(), "Getting processus' information...");
            sys.refresh_all();
            writeln!(&mut io::stdout(), "Done.");
        }
        "refresh_disks" => {
            writeln!(&mut io::stdout(), "Refreshing disk list...");
            sys.refresh_disk_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "signals" => {
            let mut nb = 1i32;

            for sig in &signals {
                writeln!(&mut io::stdout(), "{:2}:{:?}", nb, sig);
                nb += 1;
            }
        }
        "proc" => {
            let procs = sys.get_processor_list();

            writeln!(&mut io::stdout(), "total process usage: {}%", procs[0].get_cpu_usage());
            for proc_ in procs.iter().skip(1) {
                writeln!(&mut io::stdout(), "{:?}", proc_);
            }
        }
        "memory" => {
            writeln!(&mut io::stdout(), "total memory: {} kB", sys.get_total_memory());
            writeln!(&mut io::stdout(), "used memory : {} kB", sys.get_used_memory());
            writeln!(&mut io::stdout(), "total swap  : {} kB", sys.get_total_swap());
            writeln!(&mut io::stdout(), "used swap   : {} kB", sys.get_used_swap());
        }
        "quit" | "exit" => return true,
        "all" => {
            for (pid, proc_) in sys.get_process_list() {
                writeln!(&mut io::stdout(), "{}:{}", pid, proc_.name);
            }
        }
        e if e.starts_with("show ") => {
            let tmp : Vec<&str> = e.split(' ').collect();

            if tmp.len() != 2 {
                writeln!(&mut io::stdout(), "show command takes a pid or a name in parameter!");
                writeln!(&mut io::stdout(), "example: show 1254");
            } else if let Ok(pid) = pid_t::from_str(tmp[1]) {
                match sys.get_process(pid) {
                    Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
                    None => writeln!(&mut io::stdout(), "pid not found")
                };
            } else {
                let proc_name = tmp[1];
                for proc_ in sys.get_process_by_name(proc_name) {
                    writeln!(&mut io::stdout(), "==== {} ====", proc_.name);
                    writeln!(&mut io::stdout(), "{:?}", proc_);
                }
            }
        }
        "temperature" => {
            for component in sys.get_components_list() {
                writeln!(&mut io::stdout(), "{:?}", component);
            }
        }
        "show" => {
            writeln!(&mut io::stdout(), "'show' command expects a pid number or a process name");
        }
        e if e.starts_with("kill ") => {
            let tmp : Vec<&str> = e.split(' ').collect();

            if tmp.len() != 3 {
                writeln!(&mut io::stdout(),
                         "kill command takes the pid and a signal number in parameter !");
                writeln!(&mut io::stdout(), "example: kill 1254 9");
            } else {
                let pid = pid_t::from_str(tmp[1]).unwrap();
                let signal = i32::from_str(tmp[2]).unwrap();

                if signal < 1 || signal > 31 {
                    writeln!(&mut io::stdout(),
                             "Signal must be between 0 and 32 ! See the signals list with the \
                              signals command");
                } else {
                    match sys.get_process(pid) {
                        Some(p) => {
                            writeln!(&mut io::stdout(), "kill: {}",
                                     p.kill(*signals.get(signal as usize - 1).unwrap()));
                        },
                        None => {
                            writeln!(&mut io::stdout(), "pid not found");
                        }
                    };
                }
            }
        }
        "disks" => {
            for disk in sys.get_disks() {
                writeln!(&mut io::stdout(), "{:?}", disk);
            }
        }
        e => {
            writeln!(&mut io::stdout(),
                     "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.", e);
        }
    }
    false
}

fn main() {
    println!("Getting processes' information...");
    let mut t = System::new();
    println!("Done.");
    let t_stin = io::stdin();
    let mut stin = t_stin.lock();
    let mut done = false;

    println!("To get the commands' list, enter 'help'.");
    while !done {
        let mut input = String::new();
        write!(&mut io::stdout(), "> ");
        io::stdout().flush();

        stin.read_line(&mut input);
        if (&input as &str).ends_with('\n') {
            input.pop();
        }
        done = interpret_input(input.as_ref(), &mut t);
    }
}
<commit_msg>Add status when displaying all processes<commit_after>//
// Sysinfo
//
// Copyright (c) 2017 Guillaume Gomez
//

#![crate_type = "bin"]

#![allow(unused_must_use, non_upper_case_globals)]

extern crate sysinfo;
extern crate libc;

use sysinfo::{ProcessExt, ProcessorExt, Signal, System, SystemExt};
use sysinfo::Signal::*;
use std::io::{self, BufRead};
use std::str::FromStr;
use std::io::Write;
use libc::pid_t;

const signals: [Signal; 31] = [Hangup, Interrupt, Quit, Illegal, Trap, Abort, Bus,
                               FloatingPointException, Kill, User1, Segv, User2, Pipe, Alarm,
                               Term, Stklft, Child, Continue, Stop, TSTP, TTIN, TTOU, Urgent,
                               XCPU, XFSZ, VirtualAlarm, Profiling, Winch, IO, Power, Sys];

fn print_help() {
    writeln!(&mut io::stdout(), "== Help menu ==");
    writeln!(&mut io::stdout(), "help               : show this menu");
    writeln!(&mut io::stdout(), "signals            : show the available signals");
    writeln!(&mut io::stdout(), "refresh            : reloads processes' information");
    writeln!(&mut io::stdout(), "refresh_disks      : reloads only disks' information");
    writeln!(&mut io::stdout(), "show [pid | name]  : show information of the given process \
                                 corresponding to [pid | name]");
    writeln!(&mut io::stdout(), "kill [pid] [signal]: send [signal] to the process with this \
                                 [pid]. 0 < [signal] < 32");
    writeln!(&mut io::stdout(), "proc               : Displays proc state");
    writeln!(&mut io::stdout(), "memory             : Displays memory state");
    writeln!(&mut io::stdout(), "temperature        : Displays components' temperature");
    writeln!(&mut io::stdout(), "disks              : Displays disks' information");
    writeln!(&mut io::stdout(), "all                : Displays all process name and pid");
    writeln!(&mut io::stdout(), "quit               : exit the program");
}

fn interpret_input(input: &str, sys: &mut System) -> bool {
    match input.trim() {
        "help" => print_help(),
        "refresh" => {
            writeln!(&mut io::stdout(), "Getting processus' information...");
            sys.refresh_all();
            writeln!(&mut io::stdout(), "Done.");
        }
        "refresh_disks" => {
            writeln!(&mut io::stdout(), "Refreshing disk list...");
            sys.refresh_disk_list();
            writeln!(&mut io::stdout(), "Done.");
        }
        "signals" => {
            let mut nb = 1i32;

            for sig in &signals {
                writeln!(&mut io::stdout(), "{:2}:{:?}", nb, sig);
                nb += 1;
            }
        }
        "proc" => {
            let procs = sys.get_processor_list();

            writeln!(&mut io::stdout(), "total process usage: {}%", procs[0].get_cpu_usage());
            for proc_ in procs.iter().skip(1) {
                writeln!(&mut io::stdout(), "{:?}", proc_);
            }
        }
        "memory" => {
            writeln!(&mut io::stdout(), "total memory: {} kB", sys.get_total_memory());
            writeln!(&mut io::stdout(), "used memory : {} kB", sys.get_used_memory());
            writeln!(&mut io::stdout(), "total swap  : {} kB", sys.get_total_swap());
            writeln!(&mut io::stdout(), "used swap   : {} kB", sys.get_used_swap());
        }
        "quit" | "exit" => return true,
        "all" => {
            for (pid, proc_) in sys.get_process_list() {
                writeln!(&mut io::stdout(), "{}:{} status={:?}", pid, proc_.name, proc_.status);
            }
        }
        e if e.starts_with("show ") => {
            let tmp : Vec<&str> = e.split(' ').collect();

            if tmp.len() != 2 {
                writeln!(&mut io::stdout(), "show command takes a pid or a name in parameter!");
                writeln!(&mut io::stdout(), "example: show 1254");
            } else if let Ok(pid) = pid_t::from_str(tmp[1]) {
                match sys.get_process(pid) {
                    Some(p) => writeln!(&mut io::stdout(), "{:?}", *p),
                    None => writeln!(&mut io::stdout(), "pid not found")
                };
            } else {
                let proc_name = tmp[1];
                for proc_ in sys.get_process_by_name(proc_name) {
                    writeln!(&mut io::stdout(), "==== {} ====", proc_.name);
                    writeln!(&mut io::stdout(), "{:?}", proc_);
                }
            }
        }
        "temperature" => {
            for component in sys.get_components_list() {
                writeln!(&mut io::stdout(), "{:?}", component);
            }
        }
        "show" => {
            writeln!(&mut io::stdout(), "'show' command expects a pid number or a process name");
        }
        e if e.starts_with("kill ") => {
            let tmp : Vec<&str> = e.split(' ').collect();

            if tmp.len() != 3 {
                writeln!(&mut io::stdout(),
                         "kill command takes the pid and a signal number in parameter !");
                writeln!(&mut io::stdout(), "example: kill 1254 9");
            } else {
                let pid = pid_t::from_str(tmp[1]).unwrap();
                let signal = i32::from_str(tmp[2]).unwrap();

                if signal < 1 || signal > 31 {
                    writeln!(&mut io::stdout(),
                             "Signal must be between 0 and 32 ! See the signals list with the \
                              signals command");
                } else {
                    match sys.get_process(pid) {
                        Some(p) => {
                            writeln!(&mut io::stdout(), "kill: {}",
                                     p.kill(*signals.get(signal as usize - 1).unwrap()));
                        },
                        None => {
                            writeln!(&mut io::stdout(), "pid not found");
                        }
                    };
                }
            }
        }
        "disks" => {
            for disk in sys.get_disks() {
                writeln!(&mut io::stdout(), "{:?}", disk);
            }
        }
        e => {
            writeln!(&mut io::stdout(),
                     "\"{}\": Unknown command. Enter 'help' if you want to get the commands' \
                      list.", e);
        }
    }
    false
}

fn main() {
    println!("Getting processes' information...");
    let mut t = System::new();
    println!("Done.");
    let t_stin = io::stdin();
    let mut stin = t_stin.lock();
    let mut done = false;

    println!("To get the commands' list, enter 'help'.");
    while !done {
        let mut input = String::new();
        write!(&mut io::stdout(), "> ");
        io::stdout().flush();

        stin.read_line(&mut input);
        if (&input as &str).ends_with('\n') {
            input.pop();
        }
        done = interpret_input(input.as_ref(), &mut t);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

extern crate logger;
extern crate sys_util;

use std::io;
use std::mem;
use std::ptr::null_mut;
use std::result::Result;

use libc::{sigaction, sigfillset, sigset_t};

use logger::{Metric, LOGGER, METRICS};

// The offset of `si_syscall` (offending syscall identifier) within the siginfo structure
// expressed as an `(u)int*`.
// Offset `6` for an `i32` field means that the needed information is located at `6 * sizeof(i32)`.
// See /usr/include/linux/signal.h for the C struct definition.
// See https://github.com/rust-lang/libc/issues/716 for why the offset is different in Rust.
const SI_OFF_SYSCALL: isize = 6;

const SYS_SECCOMP_CODE: i32 = 1;

// This no longer relies on sys_util::register_signal_handler(), which is a lot weirder than it
// should be (at least for this use case). Also, we want to change the sa_mask field of the
// sigaction struct.
/// Sets up the specified signal handler for `SIGSYS`.
pub fn setup_sigsys_handler() -> Result<(), io::Error> {
    // Safe, because this is a POD struct.
    let mut sigact: sigaction = unsafe { mem::zeroed() };
    sigact.sa_flags = libc::SA_SIGINFO;
    sigact.sa_sigaction = sigsys_handler as usize;

    // We set all the bits of sa_mask, so all signals are blocked on the current thread while the
    // SIGSYS handler is executing. Safe because the parameter is valid and we check the return
    // value.
    if unsafe { sigfillset(&mut sigact.sa_mask as *mut sigset_t) } < 0 {
        return Err(io::Error::last_os_error());
    }

    // Safe because the parameters are valid and we check the return value.
    if unsafe { sigaction(libc::SIGSYS, &sigact, null_mut()) } < 0 {
        return Err(io::Error::last_os_error());
    }

    Ok(())
}

extern "C" fn sigsys_handler(
    num: libc::c_int,
    info: *mut libc::siginfo_t,
    _unused: *mut libc::c_void,
) {
    // Safe because we're just reading some fields from a supposedly valid argument.
    let si_signo = unsafe { (*info).si_signo };
    let si_code = unsafe { (*info).si_code };

    // Sanity check. The condition should never be true.
    if num != si_signo || num != libc::SIGSYS || si_code != SYS_SECCOMP_CODE as i32 {
        // Safe because we're terminating the process anyway.
        unsafe { libc::_exit(i32::from(super::FC_EXIT_CODE_UNEXPECTED_ERROR)) };
    }

    // Other signals which might do async unsafe things incompatible with the rest of this
    // function are blocked due to the sa_mask used when registering the signal handler.
    let syscall = unsafe { *(info as *const i32).offset(SI_OFF_SYSCALL) as usize };
    METRICS.seccomp.num_faults.inc();
    error!(
        "Shutting down VM after intercepting a bad syscall ({}).",
        syscall
    );
    // Log the metrics before exiting.
    if let Err(e) = LOGGER.log_metrics() {
        error!("Failed to log metrics while stopping: {}", e);
    }

    // Safe because we're terminating the process anyway. We don't actually do anything when
    // running unit tests.
    #[cfg(not(test))]
    unsafe {
        libc::_exit(i32::from(super::FC_EXIT_CODE_BAD_SYSCALL))
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::mem;
    use std::process;

    use libc::cpu_set_t;

    use seccomp::{allow_syscall, SeccompAction, SeccompFilter};

    // This function is used when running unit tests, so all the unsafes are safe.
    fn cpu_count() -> usize {
        let mut cpuset: cpu_set_t = unsafe { mem::zeroed() };
        unsafe {
            libc::CPU_ZERO(&mut cpuset);
        }
        let ret = unsafe {
            libc::sched_getaffinity(
                0,
                mem::size_of::<cpu_set_t>(),
                &mut cpuset as *mut cpu_set_t,
            )
        };
        assert_eq!(ret, 0);

        let mut num = 0;
        for i in 0..libc::CPU_SETSIZE as usize {
            if unsafe { libc::CPU_ISSET(i, &cpuset) } {
                num += 1;
            }
        }
        num
    }

    #[test]
    fn test_signal_handler() {
        assert!(setup_sigsys_handler().is_ok());

        let filter = SeccompFilter::new(
            vec![
                allow_syscall(libc::SYS_brk),
                allow_syscall(libc::SYS_exit),
                allow_syscall(libc::SYS_futex),
                allow_syscall(libc::SYS_munmap),
                allow_syscall(libc::SYS_rt_sigprocmask),
                allow_syscall(libc::SYS_rt_sigreturn),
                allow_syscall(libc::SYS_sched_getaffinity),
                allow_syscall(libc::SYS_set_tid_address),
                allow_syscall(libc::SYS_sigaltstack),
                allow_syscall(libc::SYS_write),
            ]
            .into_iter()
            .collect(),
            SeccompAction::Trap,
        )
        .unwrap();

        assert!(filter.apply().is_ok());
        assert_eq!(METRICS.seccomp.num_faults.count(), 0);

        // Calls the blacklisted SYS_getpid.
        let _pid = process::id();

        assert!(cpu_count() > 0);

        // Kcov somehow messes with our handler getting the SIGSYS signal when a bad syscall
        // is caught, so the following assertion no longer holds. Ideally, we'd have a surefire
        // way of either preventing this behaviour, or detecting for certain whether this test is
        // run by kcov or not. The best we could do so far is to look at the perceived number of
        // available CPUs. Kcov seems to make a single CPU available to the process running the
        // tests, so we use this as an heuristic to decide if we check the assertion.
        if cpu_count() > 1 {
            // The signal handler should let the program continue during unit tests.
            assert_eq!(METRICS.seccomp.num_faults.count(), 1);
        }
    }
}
<commit_msg>vmm: fix test_signal_handler<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

extern crate logger;
extern crate sys_util;

use std::io;
use std::mem;
use std::ptr::null_mut;
use std::result::Result;

use libc::{sigaction, sigfillset, sigset_t};

use logger::{Metric, LOGGER, METRICS};

// The offset of `si_syscall` (offending syscall identifier) within the siginfo structure
// expressed as an `(u)int*`.
// Offset `6` for an `i32` field means that the needed information is located at `6 * sizeof(i32)`.
// See /usr/include/linux/signal.h for the C struct definition.
// See https://github.com/rust-lang/libc/issues/716 for why the offset is different in Rust.
const SI_OFF_SYSCALL: isize = 6;

const SYS_SECCOMP_CODE: i32 = 1;

// This no longer relies on sys_util::register_signal_handler(), which is a lot weirder than it
// should be (at least for this use case). Also, we want to change the sa_mask field of the
// sigaction struct.
/// Sets up the specified signal handler for `SIGSYS`.
pub fn setup_sigsys_handler() -> Result<(), io::Error> {
    // Safe, because this is a POD struct.
    let mut sigact: sigaction = unsafe { mem::zeroed() };
    sigact.sa_flags = libc::SA_SIGINFO;
    sigact.sa_sigaction = sigsys_handler as usize;

    // We set all the bits of sa_mask, so all signals are blocked on the current thread while the
    // SIGSYS handler is executing. Safe because the parameter is valid and we check the return
    // value.
    if unsafe { sigfillset(&mut sigact.sa_mask as *mut sigset_t) } < 0 {
        return Err(io::Error::last_os_error());
    }

    // Safe because the parameters are valid and we check the return value.
    if unsafe { sigaction(libc::SIGSYS, &sigact, null_mut()) } < 0 {
        return Err(io::Error::last_os_error());
    }

    Ok(())
}

extern "C" fn sigsys_handler(
    num: libc::c_int,
    info: *mut libc::siginfo_t,
    _unused: *mut libc::c_void,
) {
    // Safe because we're just reading some fields from a supposedly valid argument.
    let si_signo = unsafe { (*info).si_signo };
    let si_code = unsafe { (*info).si_code };

    // Sanity check. The condition should never be true.
    if num != si_signo || num != libc::SIGSYS || si_code != SYS_SECCOMP_CODE as i32 {
        // Safe because we're terminating the process anyway.
        unsafe { libc::_exit(i32::from(super::FC_EXIT_CODE_UNEXPECTED_ERROR)) };
    }

    // Other signals which might do async unsafe things incompatible with the rest of this
    // function are blocked due to the sa_mask used when registering the signal handler.
    let syscall = unsafe { *(info as *const i32).offset(SI_OFF_SYSCALL) as usize };
    METRICS.seccomp.num_faults.inc();
    error!(
        "Shutting down VM after intercepting a bad syscall ({}).",
        syscall
    );
    // Log the metrics before exiting.
    if let Err(e) = LOGGER.log_metrics() {
        error!("Failed to log metrics while stopping: {}", e);
    }

    // Safe because we're terminating the process anyway. We don't actually do anything when
    // running unit tests.
    #[cfg(not(test))]
    unsafe {
        libc::_exit(i32::from(super::FC_EXIT_CODE_BAD_SYSCALL))
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::mem;

    use libc::{cpu_set_t, syscall};

    use seccomp::{allow_syscall, SeccompAction, SeccompFilter};

    // This function is used when running unit tests, so all the unsafes are safe.
    fn cpu_count() -> usize {
        let mut cpuset: cpu_set_t = unsafe { mem::zeroed() };
        unsafe {
            libc::CPU_ZERO(&mut cpuset);
        }
        let ret = unsafe {
            libc::sched_getaffinity(
                0,
                mem::size_of::<cpu_set_t>(),
                &mut cpuset as *mut cpu_set_t,
            )
        };
        assert_eq!(ret, 0);

        let mut num = 0;
        for i in 0..libc::CPU_SETSIZE as usize {
            if unsafe { libc::CPU_ISSET(i, &cpuset) } {
                num += 1;
            }
        }
        num
    }

    #[test]
    fn test_signal_handler() {
        assert!(setup_sigsys_handler().is_ok());

        let filter = SeccompFilter::new(
            vec![
                allow_syscall(libc::SYS_brk),
                allow_syscall(libc::SYS_exit),
                allow_syscall(libc::SYS_futex),
                allow_syscall(libc::SYS_munmap),
                allow_syscall(libc::SYS_rt_sigprocmask),
                allow_syscall(libc::SYS_rt_sigreturn),
                allow_syscall(libc::SYS_sched_getaffinity),
                allow_syscall(libc::SYS_set_tid_address),
                allow_syscall(libc::SYS_sigaltstack),
                allow_syscall(libc::SYS_write),
            ]
            .into_iter()
            .collect(),
            SeccompAction::Trap,
        )
        .unwrap();

        assert!(filter.apply().is_ok());
        assert_eq!(METRICS.seccomp.num_faults.count(), 0);

        // Call the blacklisted `SYS_mkdir`.
        unsafe { syscall(libc::SYS_mkdir, "/foo/bar\0") };

        assert!(cpu_count() > 0);

        // Kcov somehow messes with our handler getting the SIGSYS signal when a bad syscall
        // is caught, so the following assertion no longer holds. Ideally, we'd have a surefire
        // way of either preventing this behaviour, or detecting for certain whether this test is
        // run by kcov or not. The best we could do so far is to look at the perceived number of
        // available CPUs. Kcov seems to make a single CPU available to the process running the
        // tests, so we use this as an heuristic to decide if we check the assertion.
        if cpu_count() > 1 {
            // The signal handler should let the program continue during unit tests.
            assert_eq!(METRICS.seccomp.num_faults.count(), 1);
        }
    }
}
<|endoftext|>


<commit_before>//! Defines types of the abstract syntax tree
//!

/// Top level type. Is returned by `parse`.
#[derive(Debug, Clone)]
pub enum Query {
    Select,
    Insert,
    Update,
    Delete
}
<commit_msg>Add AST for ManipulationStmt and DefinitionStmt<commit_after>/// Top level type. Is returned by `parse`.
#[derive(Debug, Clone)]
pub enum Query {
	// Select,
    DefStmt(DefStmt),
    ManipulationStmt(ManipulationStmt)
}

#[derive(Debug, Clone)]
pub enum DefStmt {
    Create(CreateStmt),
    Alter(AltStmt),
    Drop(DropStmt)
}

#[derive(Debug, Clone)]
pub enum ManipulationStmt {
	Update(UpdateStmt),
	Select(SelectStmt),
	Insert(InsertStmt),
	Delete(DeleteStmt)
}

#[derive(Debug, Clone)]
pub enum CreateStmt {
    Table(CreateTableStmt),
    // View
}

#[derive(Debug, Clone)]
pub enum AltStmt {
    Table(AlterTableStmt)
    //Column(String)
    //View(String)
}

#[derive(Debug, Clone)]
pub enum DropStmt {
    Table(String)
    //Column(String)
    //Index(String)
    //Database(String)
}

#[derive(Debug, Clone)]
pub struct CreateTableStmt {
    pub tid: String,
    pub cols: Option<Vec<CreateColumn>>,
}

#[derive(Debug, Clone)]
pub struct CreateColumn {
    pub id: String,
    pub datatype: DType,
}

#[derive(Debug, Clone)]
pub struct AlterTableStmt {
	pub id: String,
	pub op: AlterOp
}

#[derive(Debug, Clone)]
pub enum AlterOp {
	Add(CreateColumn),
	Drop(String),
	Alter(CreateColumn)
}

#[derive(Debug, Clone)]
pub struct UpdateStmt {
	pub tid: String,
	pub set: Vec<Condition>,
	pub conds: Option<Conditions>
}

#[derive(Debug, Clone)]
pub struct SelectStmt {
	pub target: Vec<String>,
	pub tid: Vec<String>,
	pub cond: Option<Conditions>,
	pub spec_op: Option<SpecOps>
}

#[derive(Debug, Clone)]
pub struct InsertStmt {
	pub tid: String,
	pub col: Option<Vec<String>>,
	pub val: Vec<DType>
}

#[derive(Debug, Clone)]
pub struct DeleteStmt {
	pub tid: String,
	pub cond: Option<Conditions>
}

#[derive(Debug,Clone)]
pub enum SpecOps {
	OrderByAsc(String),
	OrderByDesc(String),
	GroupBy(Vec<String>),
	Limit(u32)
}

#[derive(Debug, Clone)]
pub enum Conditions {
	// Leaf
	Leaf(Condition),
	And((Box<Conditions>, Box<Conditions>)),
	Or((Box<Conditions>, Box<Conditions>))
}

#[derive(Debug, Clone)]
pub struct Condition {
	pub a : CondType,
	pub op: CompType,
	pub b : CondType
}

#[derive(Debug, Clone)]
pub enum CompType {
	Equ,
	NEqu,
	GThan,
	SThan,
	GEThan,
	SEThan
}

#[derive(Debug, Clone)]
pub enum CondType {
	Literal(String),
	Num(f32),
	Word(String)
}

//general enums
#[derive(Debug, Clone, Copy)]
pub enum DType {
    Int,
    Bool,
    Char(u8),
    VarChar(u16)
}
<|endoftext|>


<commit_before>//! This module contains shareable mutable containers designed for enabling
//! and detecting race conditions in thread synchronization testing code.
//!
//! # Motivation
//!
//! The main purpose of a thread synchronization protocol is to ensure that
//! some operations which are not atomic in hardware, such as writing to two
//! unrelated memory locations, appear to occur as atomic transactions from the
//! point of view of other threads: at any point of time, either a given
//! operation appears to be done, or it appears not to have started.
//!
//! Testing a thread synchronization primitive involves showing that
//! inconsistent states (where an operation appears to be half-performed) have a
//! negligible probability of being exposed to the outside world in all expected
//! usage scenarios. It is typically done by showing that a given non-atomic
//! operation is properly encapsulated by the transactional semantics of the
//! synchronization protocol, and will never appear as half-done to observers.
//!
//! Non-atomic operations are easier said than done, however, when the set of
//! operations which can be atomic in hardware is larger than most people think
//! (at the time of writing, current Intel CPUs can access memory in blocks of
//! 128 bits, and current NVidia GPUs can do so in blocks of 1024 bits), not
//! well-defined by the architecture (and thus subjected to increase in future
//! hardware), and highly dependent on the compiler's optimization choices in a
//! high-level programming language such as Rust.
//!
//! Which is why I think we need some types whose operations are guaranteed to
//! be non-atomic under a set of reasonable assumptions, and which can easily be
//! observed to be in an inconsistent state.
//!
//! # Functionality
//!
//! This module provides the RaceCell type, which can hold a value of a
//! certain type T like a `Cell<T>` would, but is guaranteed **not** to be read
//! or written to in a single atomic operation, even if the corresponding type T
//! can be atomically read or written to in hardware.
//!
//! Furthermore, a RaceCell can detect scenarios where it is read at the same
//! time as it is being written (which constitutes a read-after-write race
//! condition) and report them to the reader thread.
//!
//! Such "controlled data races" can, in turn, be used to detect failures in
//! thread synchronization protocols, manifesting as inconsistent shared states
//! being exposed to the outside world.
//!
//! # Requirements on T
//!
//! In principle, any Clone + Eq type T whose equality operator and clone()
//! implementation behave well even if the inner data is in a inconsistent state
//! (e.g. filled with random bits) could be used. This is true of all primitive
//! integral types and aggregates thereof, for example.
//!
//! However, in practice, unsynchronized concurrent read/write access to
//! arbitrary data from multiple threads constitutes a data race, which is
//! undefined behaviour in Rust even when it occurs inside an UnsafeCell. This
//! is problematic because rustc's optimizer allows itself to transform code
//! which relies on undefined behaviour however it likes, leading to breakages
//! in release builds such as infinite loops appearing out of nowhere.
//!
//! For this reason, we currently only support some specific types T which have
//! atomic load and store operations, implemented as part of an atomic wrapper.
//! Note that although individual loads and stores to T are atomic, loads and
//! stores to RaceCell<T> are still guaranteed not to be atomic.

#![deny(missing_docs)]

use std::sync::atomic::{
    AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16,
    AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering,
};

/// Shareable mutable container for triggering and detecting write-after-read
/// data races in a well-controlled fashion.
#[derive(Debug, Default)]
pub struct RaceCell<T: AtomicData> {
    /// Two copies of a value of type T are made. One is stored on the stack...
    local_contents: T::AtomicWrapper,

    /// ...and one is stored on the heap, which in all popular OSs is too far
    /// away from the stack to allow any significant probability of the hardware
    /// writing both copies in a single atomic transactions.
    ///
    /// Of course, a malicious optimizer could still use hardware transactional
    /// memory or a software emulation thereof to achieve this effect, but there
    /// are no performance benefits in doing so, and in fact it will rather have
    /// an averse effect on performance, so a realistic optimizer won't do it.
    ///
    remote_version: Box<T::AtomicWrapper>,
}
//
impl<T: AtomicData> RaceCell<T> {
    /// Create a new RaceCell with a certain initial content
    pub fn new(value: T) -> Self {
        RaceCell {
            local_contents: T::AtomicWrapper::new(value.clone()),
            remote_version: Box::new(T::AtomicWrapper::new(value)),
        }
    }

    /// Update the internal contents of the RaceCell in a non-atomic fashion
    pub fn set(&self, value: T) {
        self.local_contents.relaxed_store(value.clone());
        self.remote_version.relaxed_store(value);
    }

    /// Read the current contents of the RaceCell, detecting any data race
    /// caused by a concurrently occurring write along the way.
    pub fn get(&self) -> Racey<T> {
        let local_data = self.local_contents.relaxed_load();
        let remote_data = self.remote_version.relaxed_load();
        if local_data == remote_data {
            Racey::Consistent(local_data)
        } else {
            Racey::Inconsistent
        }
    }
}
//
impl<T: AtomicData> Clone for RaceCell<T> {
    /// Making RaceCells cloneable allows putting them in concurrent containers
    fn clone(&self) -> Self {
        let local_copy = self.local_contents.relaxed_load();
        let remote_copy = self.remote_version.relaxed_load();
        RaceCell {
            local_contents: T::AtomicWrapper::new(local_copy),
            remote_version: Box::new(T::AtomicWrapper::new(remote_copy)),
        }
    }
}

/// This is the result of a RaceCell read
#[derive(Debug, Eq, PartialEq)]
pub enum Racey<U: AtomicData> {
    /// The RaceCell was internally consistent, and its content was copied
    Consistent(U),

    /// The RaceCell was internally inconsistent: a data race has occurred
    Inconsistent,
}

/// Requirements on the data held by a RaceCell
pub trait AtomicData: Clone + Eq + Sized {
    /// Atomic wrapper type for this data implementing relaxed atomic load/store
    type AtomicWrapper: AtomicLoadStore<Content = Self>;
}
///
/// Atomic wrapper type for a certain kind of value
///
/// For the implementation of RaceCell not to be considered as undefined
/// behaviour and trashed by the Rust compiler in release mode, the underlying
/// type must be loaded and stored atomically. This requires synchronizing
/// accesses to it using things like the std::sync::atomic::AtomicXyz wrappers.
///
/// The only guarantee that we need is that loads and stores are atomic. We do
/// not need any other memory ordering guarantee. This is why we allow for
/// more wrapper type implementation freedom by not specifying memory orderings,
/// and internally relying only on relaxed ordering.
///
pub trait AtomicLoadStore: Sized {
    /// Type of data that is being wrapped
    type Content: AtomicData<AtomicWrapper = Self>;

    /// Create an atomic wrapper for a value of type U
    fn new(v: Self::Content) -> Self;

    /// Atomically load a value from the wrapper
    fn relaxed_load(&self) -> Self::Content;

    /// Atomically store a new value into the wrapper
    fn relaxed_store(&self, val: Self::Content);
}
///
/// This macro implements support for non-generic standard atomic types
///
macro_rules! impl_atomic_data {
    ($($data:ty => $wrapper:ty),*) => ($(
        impl AtomicData for $data {
            type AtomicWrapper = $wrapper;
        }

        impl AtomicLoadStore for $wrapper {
            type Content = $data;

            fn new(v: $data) -> $wrapper {
                <$wrapper>::new(v)
            }

            fn relaxed_load(&self) -> $data {
                <$wrapper>::load(self, Ordering::Relaxed)
            }

            fn relaxed_store(&self, val: $data) {
                <$wrapper>::store(self, val, Ordering::Relaxed)
            }
        }
    )*)
}
//
impl_atomic_data! {
    bool  => AtomicBool,
    i8    => AtomicI8,
    i16   => AtomicI16,
    i32   => AtomicI32,
    i64   => AtomicI64,
    isize => AtomicIsize,
    u8    => AtomicU8,
    u16   => AtomicU16,
    u32   => AtomicU32,
    u64   => AtomicU64,
    usize => AtomicUsize
}
//
// Atomic pointers are a bit special as they are generic, for now we will just
// treat them as a special case.
//
impl<V> AtomicData for *mut V {
    type AtomicWrapper = AtomicPtr<V>;
}
///
impl<V> AtomicLoadStore for AtomicPtr<V> {
    type Content = *mut V;

    fn new(v: *mut V) -> AtomicPtr<V> {
        <AtomicPtr<V>>::new(v)
    }

    fn relaxed_load(&self) -> *mut V {
        <AtomicPtr<V>>::load(self, Ordering::Relaxed)
    }

    fn relaxed_store(&self, val: *mut V) {
        <AtomicPtr<V>>::store(self, val, Ordering::Relaxed)
    }
}

// FIXME: The astute reader will have noted that any data could be theoretically
//        put in a RaceCell by using a Mutex as the AtomicWrapper. However, this
//        will only be implemented once Rust has specialization, to avoid
//        pessimizing the common case where a primitive type is enough.

/// Here are some RaceCell tests
#[cfg(test)]
mod tests {
    use super::{AtomicLoadStore, RaceCell, Racey};
    use std::sync::{Arc, Mutex};

    /// A RaceCell should be created in a consistent and correct state
    #[test]
    fn initial_state() {
        let cell = RaceCell::new(true);
        assert_eq!(cell.local_contents.relaxed_load(), true);
        assert_eq!(cell.remote_version.relaxed_load(), true);
    }

    /// Reading a consistent RaceCell should work as expected
    #[test]
    fn consistent_read() {
        let cell = RaceCell::new(-42_isize);
        assert_eq!(cell.get(), Racey::Consistent(-42));
    }

    /// Reading an inconsistent RaceCell should work as expected
    #[test]
    fn inconsistent_read() {
        let cell = RaceCell::new(0xbad_usize);
        cell.local_contents.relaxed_store(0xdead);
        assert_eq!(cell.get(), Racey::Inconsistent);
    }

    /// RaceCells should be cloned as-is, even if in an inconsistent state
    #[test]
    fn clone() {
        let cell = RaceCell::new(0xbeef_usize);
        cell.local_contents.relaxed_store(0xdeaf);
        let clone = cell.clone();
        assert_eq!(clone.local_contents.relaxed_load(), 0xdeaf);
        assert_eq!(clone.remote_version.relaxed_load(), 0xbeef);
    }

    /// Unprotected concurrent reads and writes to a RaceCell should trigger
    /// detectable race conditions, illustrating its non-atomic nature.
    ///
    /// To maximize the odds of race conditions, this kind of test should be run
    /// in single-threaded mode.
    ///
    #[test]
    #[ignore]
    fn unprotected_race() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 100_000_000;

        // RaceCell in which the writes will be carried out
        let initial_value = 0usize;
        let cell1 = Arc::new(RaceCell::new(initial_value));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does expose existing data races, with a
        // detection probability better than 1% for very obvious ones :)
        crate::concurrent_test_2(
            move || {
                for i in 1..=WRITES_COUNT {
                    cell1.set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                print!("{} races detected: ", data_race_count);
                assert!(data_race_count > WRITES_COUNT / 100);
            },
        );
    }

    /// Appropriately protected concurrent reads and writes to a RaceCell should
    /// not yield any detectable race conditions.
    ///
    /// To maximize the odds of race conditions, this kind of test should be run
    /// in single-threaded mode.
    ///
    #[test]
    #[ignore]
    fn protected_transaction() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 10_000_000;

        // Mutex-protected RaceCell in which the writes will be carried out
        let initial_value = 0usize;
        let cell1 = Arc::new(Mutex::new(RaceCell::new(initial_value)));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does not incorrectly detect race conditions
        crate::concurrent_test_2(
            move || {
                for i in 1..=WRITES_COUNT {
                    cell1.lock().unwrap().set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.lock().unwrap().get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                assert_eq!(data_race_count, 0);
            },
        );
    }
}
<commit_msg>Module doc tweak<commit_after>//! Shareable mutable containers easing detection of race conditions in thread
//! synchronization testing code.
//!
//! # Motivation
//!
//! The main purpose of a thread synchronization protocol is to ensure that
//! some operations which are not atomic in hardware, such as writing to two
//! unrelated memory locations, appear to occur as atomic transactions from the
//! point of view of other threads: at any point of time, either a given
//! operation appears to be done, or it appears not to have started.
//!
//! Testing a thread synchronization primitive involves showing that
//! inconsistent states (where an operation appears to be half-performed) have a
//! negligible probability of being exposed to the outside world in all expected
//! usage scenarios. It is typically done by showing that a given non-atomic
//! operation is properly encapsulated by the transactional semantics of the
//! synchronization protocol, and will never appear as half-done to observers.
//!
//! Non-atomic operations are easier said than done, however, when the set of
//! operations which can be atomic in hardware is larger than most people think
//! (at the time of writing, current Intel CPUs can access memory in blocks of
//! 128 bits, and current NVidia GPUs can do so in blocks of 1024 bits), not
//! well-defined by the architecture (and thus subjected to increase in future
//! hardware), and highly dependent on the compiler's optimization choices in a
//! high-level programming language such as Rust.
//!
//! Which is why I think we need some types whose operations are guaranteed to
//! be non-atomic under a set of reasonable assumptions, and which can easily be
//! observed to be in an inconsistent state.
//!
//! # Functionality
//!
//! This module provides the RaceCell type, which can hold a value of a
//! certain type T like a `Cell<T>` would, but is guaranteed **not** to be read
//! or written to in a single atomic operation, even if the corresponding type T
//! can be atomically read or written to in hardware.
//!
//! Furthermore, a RaceCell can detect scenarios where it is read at the same
//! time as it is being written (which constitutes a read-after-write race
//! condition) and report them to the reader thread.
//!
//! Such "controlled data races" can, in turn, be used to detect failures in
//! thread synchronization protocols, manifesting as inconsistent shared states
//! being exposed to the outside world.
//!
//! # Requirements on T
//!
//! In principle, any Clone + Eq type T whose equality operator and clone()
//! implementation behave well even if the inner data is in a inconsistent state
//! (e.g. filled with random bits) could be used. This is true of all primitive
//! integral types and aggregates thereof, for example.
//!
//! However, in practice, unsynchronized concurrent read/write access to
//! arbitrary data from multiple threads constitutes a data race, which is
//! undefined behaviour in Rust even when it occurs inside an UnsafeCell. This
//! is problematic because rustc's optimizer allows itself to transform code
//! which relies on undefined behaviour however it likes, leading to breakages
//! in release builds such as infinite loops appearing out of nowhere.
//!
//! For this reason, we currently only support some specific types T which have
//! atomic load and store operations, implemented as part of an atomic wrapper.
//! Note that although individual loads and stores to T are atomic, loads and
//! stores to RaceCell<T> are still guaranteed not to be atomic.

#![deny(missing_docs)]

use std::sync::atomic::{
    AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicPtr, AtomicU16,
    AtomicU32, AtomicU64, AtomicU8, AtomicUsize, Ordering,
};

/// Shareable mutable container for triggering and detecting write-after-read
/// data races in a well-controlled fashion.
#[derive(Debug, Default)]
pub struct RaceCell<T: AtomicData> {
    /// Two copies of a value of type T are made. One is stored on the stack...
    local_contents: T::AtomicWrapper,

    /// ...and one is stored on the heap, which in all popular OSs is too far
    /// away from the stack to allow any significant probability of the hardware
    /// writing both copies in a single atomic transactions.
    ///
    /// Of course, a malicious optimizer could still use hardware transactional
    /// memory or a software emulation thereof to achieve this effect, but there
    /// are no performance benefits in doing so, and in fact it will rather have
    /// an averse effect on performance, so a realistic optimizer won't do it.
    ///
    remote_version: Box<T::AtomicWrapper>,
}
//
impl<T: AtomicData> RaceCell<T> {
    /// Create a new RaceCell with a certain initial content
    pub fn new(value: T) -> Self {
        RaceCell {
            local_contents: T::AtomicWrapper::new(value.clone()),
            remote_version: Box::new(T::AtomicWrapper::new(value)),
        }
    }

    /// Update the internal contents of the RaceCell in a non-atomic fashion
    pub fn set(&self, value: T) {
        self.local_contents.relaxed_store(value.clone());
        self.remote_version.relaxed_store(value);
    }

    /// Read the current contents of the RaceCell, detecting any data race
    /// caused by a concurrently occurring write along the way.
    pub fn get(&self) -> Racey<T> {
        let local_data = self.local_contents.relaxed_load();
        let remote_data = self.remote_version.relaxed_load();
        if local_data == remote_data {
            Racey::Consistent(local_data)
        } else {
            Racey::Inconsistent
        }
    }
}
//
impl<T: AtomicData> Clone for RaceCell<T> {
    /// Making RaceCells cloneable allows putting them in concurrent containers
    fn clone(&self) -> Self {
        let local_copy = self.local_contents.relaxed_load();
        let remote_copy = self.remote_version.relaxed_load();
        RaceCell {
            local_contents: T::AtomicWrapper::new(local_copy),
            remote_version: Box::new(T::AtomicWrapper::new(remote_copy)),
        }
    }
}

/// This is the result of a RaceCell read
#[derive(Debug, Eq, PartialEq)]
pub enum Racey<U: AtomicData> {
    /// The RaceCell was internally consistent, and its content was copied
    Consistent(U),

    /// The RaceCell was internally inconsistent: a data race has occurred
    Inconsistent,
}

/// Requirements on the data held by a RaceCell
pub trait AtomicData: Clone + Eq + Sized {
    /// Atomic wrapper type for this data implementing relaxed atomic load/store
    type AtomicWrapper: AtomicLoadStore<Content = Self>;
}
///
/// Atomic wrapper type for a certain kind of value
///
/// For the implementation of RaceCell not to be considered as undefined
/// behaviour and trashed by the Rust compiler in release mode, the underlying
/// type must be loaded and stored atomically. This requires synchronizing
/// accesses to it using things like the std::sync::atomic::AtomicXyz wrappers.
///
/// The only guarantee that we need is that loads and stores are atomic. We do
/// not need any other memory ordering guarantee. This is why we allow for
/// more wrapper type implementation freedom by not specifying memory orderings,
/// and internally relying only on relaxed ordering.
///
pub trait AtomicLoadStore: Sized {
    /// Type of data that is being wrapped
    type Content: AtomicData<AtomicWrapper = Self>;

    /// Create an atomic wrapper for a value of type U
    fn new(v: Self::Content) -> Self;

    /// Atomically load a value from the wrapper
    fn relaxed_load(&self) -> Self::Content;

    /// Atomically store a new value into the wrapper
    fn relaxed_store(&self, val: Self::Content);
}
///
/// This macro implements support for non-generic standard atomic types
///
macro_rules! impl_atomic_data {
    ($($data:ty => $wrapper:ty),*) => ($(
        impl AtomicData for $data {
            type AtomicWrapper = $wrapper;
        }

        impl AtomicLoadStore for $wrapper {
            type Content = $data;

            fn new(v: $data) -> $wrapper {
                <$wrapper>::new(v)
            }

            fn relaxed_load(&self) -> $data {
                <$wrapper>::load(self, Ordering::Relaxed)
            }

            fn relaxed_store(&self, val: $data) {
                <$wrapper>::store(self, val, Ordering::Relaxed)
            }
        }
    )*)
}
//
impl_atomic_data! {
    bool  => AtomicBool,
    i8    => AtomicI8,
    i16   => AtomicI16,
    i32   => AtomicI32,
    i64   => AtomicI64,
    isize => AtomicIsize,
    u8    => AtomicU8,
    u16   => AtomicU16,
    u32   => AtomicU32,
    u64   => AtomicU64,
    usize => AtomicUsize
}
//
// Atomic pointers are a bit special as they are generic, for now we will just
// treat them as a special case.
//
impl<V> AtomicData for *mut V {
    type AtomicWrapper = AtomicPtr<V>;
}
///
impl<V> AtomicLoadStore for AtomicPtr<V> {
    type Content = *mut V;

    fn new(v: *mut V) -> AtomicPtr<V> {
        <AtomicPtr<V>>::new(v)
    }

    fn relaxed_load(&self) -> *mut V {
        <AtomicPtr<V>>::load(self, Ordering::Relaxed)
    }

    fn relaxed_store(&self, val: *mut V) {
        <AtomicPtr<V>>::store(self, val, Ordering::Relaxed)
    }
}

// FIXME: The astute reader will have noted that any data could be theoretically
//        put in a RaceCell by using a Mutex as the AtomicWrapper. However, this
//        will only be implemented once Rust has specialization, to avoid
//        pessimizing the common case where a primitive type is enough.

/// Here are some RaceCell tests
#[cfg(test)]
mod tests {
    use super::{AtomicLoadStore, RaceCell, Racey};
    use std::sync::{Arc, Mutex};

    /// A RaceCell should be created in a consistent and correct state
    #[test]
    fn initial_state() {
        let cell = RaceCell::new(true);
        assert_eq!(cell.local_contents.relaxed_load(), true);
        assert_eq!(cell.remote_version.relaxed_load(), true);
    }

    /// Reading a consistent RaceCell should work as expected
    #[test]
    fn consistent_read() {
        let cell = RaceCell::new(-42_isize);
        assert_eq!(cell.get(), Racey::Consistent(-42));
    }

    /// Reading an inconsistent RaceCell should work as expected
    #[test]
    fn inconsistent_read() {
        let cell = RaceCell::new(0xbad_usize);
        cell.local_contents.relaxed_store(0xdead);
        assert_eq!(cell.get(), Racey::Inconsistent);
    }

    /// RaceCells should be cloned as-is, even if in an inconsistent state
    #[test]
    fn clone() {
        let cell = RaceCell::new(0xbeef_usize);
        cell.local_contents.relaxed_store(0xdeaf);
        let clone = cell.clone();
        assert_eq!(clone.local_contents.relaxed_load(), 0xdeaf);
        assert_eq!(clone.remote_version.relaxed_load(), 0xbeef);
    }

    /// Unprotected concurrent reads and writes to a RaceCell should trigger
    /// detectable race conditions, illustrating its non-atomic nature.
    ///
    /// To maximize the odds of race conditions, this kind of test should be run
    /// in single-threaded mode.
    ///
    #[test]
    #[ignore]
    fn unprotected_race() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 100_000_000;

        // RaceCell in which the writes will be carried out
        let initial_value = 0usize;
        let cell1 = Arc::new(RaceCell::new(initial_value));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does expose existing data races, with a
        // detection probability better than 1% for very obvious ones :)
        crate::concurrent_test_2(
            move || {
                for i in 1..=WRITES_COUNT {
                    cell1.set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                print!("{} races detected: ", data_race_count);
                assert!(data_race_count > WRITES_COUNT / 100);
            },
        );
    }

    /// Appropriately protected concurrent reads and writes to a RaceCell should
    /// not yield any detectable race conditions.
    ///
    /// To maximize the odds of race conditions, this kind of test should be run
    /// in single-threaded mode.
    ///
    #[test]
    #[ignore]
    fn protected_transaction() {
        // Amount of writes to carry out
        const WRITES_COUNT: usize = 10_000_000;

        // Mutex-protected RaceCell in which the writes will be carried out
        let initial_value = 0usize;
        let cell1 = Arc::new(Mutex::new(RaceCell::new(initial_value)));
        let cell2 = cell1.clone();

        // Make sure that RaceCell does not incorrectly detect race conditions
        crate::concurrent_test_2(
            move || {
                for i in 1..=WRITES_COUNT {
                    cell1.lock().unwrap().set(i);
                }
            },
            move || {
                let mut last_value = 0;
                let mut data_race_count = 0usize;
                while last_value != WRITES_COUNT {
                    match cell2.lock().unwrap().get() {
                        Racey::Consistent(value) => last_value = value,
                        Racey::Inconsistent => data_race_count += 1,
                    }
                }
                assert_eq!(data_race_count, 0);
            },
        );
    }
}
<|endoftext|>


<commit_before>pub(crate) use imp::*;

#[cfg(not(feature = "std"))]
mod imp {
    use alloc::sync::Arc;
    use core::sync::atomic::{AtomicPtr, Ordering};
    use core::{mem, ptr};

    #[derive(Debug, Default)]
    pub(crate) struct LazyArc<T> {
        // Only written once with a value obtained from `Arc<T>::into_raw`.
        // This holds a ref count for the `Arc`, so it is always safe to
        // clone the `Arc` given a reference to the `LazyArc`.
        value: AtomicPtr<T>,
    }

    impl<T> Drop for LazyArc<T> {
        fn drop(&mut self) {
            let value_ptr = self.value.load(Ordering::Acquire);
            if !value_ptr.is_null() {
                // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`.
                drop(unsafe { Arc::from_raw(value_ptr) });
            }
        }
    }

    impl<T> LazyArc<T> {
        pub(crate) fn get<E, F: FnOnce() -> Result<T, E>>(&self, f: F) -> Result<Arc<T>, E> {
            // Clone an `Arc` given a pointer obtained from `Arc::into_raw`.
            // SAFETY: `value_ptr` must be a valid pointer obtained from `Arc<T>::into_raw`.
            unsafe fn clone_arc_ptr<T>(value_ptr: *const T) -> Arc<T> {
                let value = Arc::from_raw(value_ptr);
                let clone = Arc::clone(&value);
                mem::forget(value);
                clone
            }

            // Return the existing value if already computed.
            // `Ordering::Acquire` is needed so that the content of the loaded `Arc` is
            // visible to this thread.
            let value_ptr = self.value.load(Ordering::Acquire);
            if !value_ptr.is_null() {
                // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`.
                return Ok(unsafe { clone_arc_ptr(value_ptr) });
            }

            // Race to compute and set the value.
            let value = f().map(Arc::new)?;
            let value_ptr = Arc::into_raw(value);
            match self.value.compare_exchange(
                ptr::null_mut(),
                value_ptr as *mut T,
                // Success: `Ordering::Release` is needed so that the content of the stored `Arc`
                // is visible to other threads. No ordering is required for the null ptr that is
                // loaded.
                Ordering::Release,
                // Failure: `Ordering::Acquire` is needed so that the content of the loaded `Arc`
                // is visible to this thread.
                Ordering::Acquire,
            ) {
                Ok(_) => {
                    // Return the value we computed.
                    // SAFETY: `value_ptr` was obtained from `Arc::into_raw`.
                    Ok(unsafe { clone_arc_ptr(value_ptr) })
                }
                Err(existing_value_ptr) => {
                    // We lost the race, drop unneeded `value_ptr`.
                    // SAFETY: `value_ptr` was obtained from `Arc::into_raw`.
                    drop(unsafe { Arc::from_raw(value_ptr) });
                    // Return the existing value.
                    // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`.
                    Ok(unsafe { clone_arc_ptr(existing_value_ptr) })
                }
            }
        }
    }
}

#[cfg(feature = "std")]
mod imp {
    use std::sync::{Arc, Mutex};

    #[derive(Debug, Default)]
    pub(crate) struct LazyArc<T> {
        value: Mutex<Option<Arc<T>>>,
    }

    impl<T> LazyArc<T> {
        pub(crate) fn get<E, F: FnOnce() -> Result<T, E>>(&self, f: F) -> Result<Arc<T>, E> {
            let mut lock = self.value.lock().unwrap();
            if let Some(value) = &*lock {
                return Ok(value.clone());
            }
            let value = f().map(Arc::new)?;
            *lock = Some(value.clone());
            Ok(value)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn lazy_arc() {
        let lazy = LazyArc::default();
        let value = lazy.get(|| Err(()));
        assert_eq!(value, Err(()));
        let value = lazy.get(|| Ok::<i32, ()>(3)).unwrap();
        assert_eq!(*value, 3);
        let value = lazy.get(|| Err(())).unwrap();
        assert_eq!(*value, 3);
    }
}
<commit_msg>Fix atomic ordering in LazyArc<commit_after>pub(crate) use imp::*;

#[cfg(not(feature = "std"))]
mod imp {
    use alloc::sync::Arc;
    use core::sync::atomic::{AtomicPtr, Ordering};
    use core::{mem, ptr};

    #[derive(Debug, Default)]
    pub(crate) struct LazyArc<T> {
        // Only written once with a value obtained from `Arc<T>::into_raw`.
        // This holds a ref count for the `Arc`, so it is always safe to
        // clone the `Arc` given a reference to the `LazyArc`.
        value: AtomicPtr<T>,
    }

    impl<T> Drop for LazyArc<T> {
        fn drop(&mut self) {
            let value_ptr = self.value.load(Ordering::Acquire);
            if !value_ptr.is_null() {
                // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`.
                drop(unsafe { Arc::from_raw(value_ptr) });
            }
        }
    }

    impl<T> LazyArc<T> {
        pub(crate) fn get<E, F: FnOnce() -> Result<T, E>>(&self, f: F) -> Result<Arc<T>, E> {
            // Clone an `Arc` given a pointer obtained from `Arc::into_raw`.
            // SAFETY: `value_ptr` must be a valid pointer obtained from `Arc<T>::into_raw`.
            unsafe fn clone_arc_ptr<T>(value_ptr: *const T) -> Arc<T> {
                let value = Arc::from_raw(value_ptr);
                let clone = Arc::clone(&value);
                mem::forget(value);
                clone
            }

            // Return the existing value if already computed.
            // `Ordering::Acquire` is needed so that the content of the loaded `Arc` is
            // visible to this thread.
            let value_ptr = self.value.load(Ordering::Acquire);
            if !value_ptr.is_null() {
                // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`.
                return Ok(unsafe { clone_arc_ptr(value_ptr) });
            }

            // Race to compute and set the value.
            let value = f().map(Arc::new)?;
            let value_ptr = Arc::into_raw(value);
            match self.value.compare_exchange(
                ptr::null_mut(),
                value_ptr as *mut T,
                // Success: `Ordering::Release` is needed so that the content of the stored `Arc`
                // is visible to other threads. No ordering is required for the null ptr that is
                // loaded, but older rust versions (< 1.64) require that its ordering must not
                // be weaker than the failure ordering, so we use `Ordering::AcqRel`.
                Ordering::AcqRel,
                // Failure: `Ordering::Acquire` is needed so that the content of the loaded `Arc`
                // is visible to this thread.
                Ordering::Acquire,
            ) {
                Ok(_) => {
                    // Return the value we computed.
                    // SAFETY: `value_ptr` was obtained from `Arc::into_raw`.
                    Ok(unsafe { clone_arc_ptr(value_ptr) })
                }
                Err(existing_value_ptr) => {
                    // We lost the race, drop unneeded `value_ptr`.
                    // SAFETY: `value_ptr` was obtained from `Arc::into_raw`.
                    drop(unsafe { Arc::from_raw(value_ptr) });
                    // Return the existing value.
                    // SAFETY: all writes to `self.value` are pointers obtained from `Arc::into_raw`.
                    Ok(unsafe { clone_arc_ptr(existing_value_ptr) })
                }
            }
        }
    }
}

#[cfg(feature = "std")]
mod imp {
    use std::sync::{Arc, Mutex};

    #[derive(Debug, Default)]
    pub(crate) struct LazyArc<T> {
        value: Mutex<Option<Arc<T>>>,
    }

    impl<T> LazyArc<T> {
        pub(crate) fn get<E, F: FnOnce() -> Result<T, E>>(&self, f: F) -> Result<Arc<T>, E> {
            let mut lock = self.value.lock().unwrap();
            if let Some(value) = &*lock {
                return Ok(value.clone());
            }
            let value = f().map(Arc::new)?;
            *lock = Some(value.clone());
            Ok(value)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn lazy_arc() {
        let lazy = LazyArc::default();
        let value = lazy.get(|| Err(()));
        assert_eq!(value, Err(()));
        let value = lazy.get(|| Ok::<i32, ()>(3)).unwrap();
        assert_eq!(*value, 3);
        let value = lazy.get(|| Err(())).unwrap();
        assert_eq!(*value, 3);
    }
}
<|endoftext|>


<commit_before>//! Scheduling game play.

use state::Player;
use state::{Action, State, SerializableState};

use std::mem::replace;

/// A `Scheduler` collects actions from all players, and then broadcasts the
/// full list once everyone has submitted their moves for that turn.
///
/// When a player submits their moves, they provide a `Sender` on which
/// `Scheduler` should send the full move list once it is available.
pub struct Scheduler {
    // The number of the last turn we broadcast out.
    turn: usize,

    // A scheduler actually maintains its own copy of the game state, for
    // generating checksums to send to clients.
    state: State,

    // A vector recording submitted actions and reply channels for every joined
    // player; the `i`'th element is for `Player(i)`. Once this has actions for
    // every joined player, we apply all the actions to our state in a given
    // order, compute the new state's checksum, and then transmit the collected
    // moves to all the players.
    pending_actions: Vec<Option<(PlayerActions, Box<Notifier + Send>)>>
}

/// Something that can notify a player of a turn's actions when they have been
/// collected.
pub trait Notifier {
    fn notify(self: Box<Self>, turn: CollectedActions);
}

impl Scheduler {
    pub fn new(initial_state: State) -> Scheduler {
        Scheduler { turn: 0, state: initial_state, pending_actions: vec![] }
    }

    // Add another player to the game. If there is room, return the player's
    // number and a representation of the current game state. Return `None` if
    // there is no room for more players.
    pub fn player_join(&mut self) -> Option<(Player, SerializableState)> {
        if self.pending_actions.len() >= self.state.max_players() {
            None
        } else {
            self.pending_actions.push(None);
            Some((Player(self.pending_actions.len() - 1), self.state.serializable()))
        }
    }

    // Submit `actions` to be carried out as soon as possible. When all players'
    // actions have been collected, send the full list to `reply_to`.
    pub fn submit_actions(&mut self,
                          actions: PlayerActions,
                          reply_to: Box<Notifier + Send>) {
        assert_eq!(actions.turn, self.turn);
        assert!(self.pending_actions[actions.player.0].is_none());
        let player = actions.player.0;
        self.pending_actions[player] = Some((actions, reply_to));

        // Have all the players that have joined finally submitted an action?
        if self.pending_actions.iter().all(|o| o.is_some()) {
            // Grab the list of pending actions and reset it for the next turn.
            let pendings = replace(&mut self.pending_actions, vec![]);

            // Collect all the actions into a single vector,
            // collect all the reply-to's in another vector,
            // and apply all the actions to our state.
            let mut collected_reply_tos = Vec::new();
            let mut collected_actions = Vec::new();

            for player in pendings {
                let (player_actions, reply_to) = player.unwrap();
                for action in player_actions.actions {
                    self.state.take_action(&action);
                    collected_actions.push(action);
                }
                collected_reply_tos.push(reply_to);
                self.pending_actions.push(None);
            }
            self.state.advance();

            let state_checksum = self.state.checksum();

            // We are now in the new turn.
            self.turn += 1;

            let collected = CollectedActions {
                turn: self.turn,
                actions: collected_actions,
                state_checksum
            };

            // Broadcast out the new state of the world to all players.
            for reply_to in collected_reply_tos {
                reply_to.notify(collected.clone());
            }
        }
    }
}

/// A set of actions submitted by a single player on a single turn.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PlayerActions {
    // The player submitting these actions.
    pub player: Player,

    // The turn number they believe they're on.
    pub turn: usize,

    // The actions they wish to submit.
    pub actions: Vec<Action>,
}

/// A collection of all actions submitted by all players.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CollectedActions {
    // The turn these moves produce when applied.
    pub turn: usize,

    // The actions to apply to the prior state.
    pub actions: Vec<Action>,

    // The hash value of the State that should result, as a checksum.
    pub state_checksum: u64
}
<commit_msg>Fix timing. Never make moves faster than 60fps.<commit_after>//! Scheduling game play.

use state::Player;
use state::{Action, State, SerializableState};

use std::mem::replace;
use std::thread;
use std::time::{Duration, Instant};

/// The shortest amount of time a turn is allowed to take, in nanoseconds.
const MIN_DELAY_NS: u32 = 016_000_000;

/// A `Scheduler` collects actions from all players, and then broadcasts the
/// full list once everyone has submitted their moves for that turn.
///
/// When a player submits their moves, they provide a `Sender` on which
/// `Scheduler` should send the full move list once it is available.
pub struct Scheduler {
    /// The number of the last turn we broadcast out.
    turn: usize,

    /// A scheduler actually maintains its own copy of the game state, for
    /// generating checksums to send to clients.
    state: State,

    /// A vector recording submitted actions and reply channels for every joined
    /// player; the `i`'th element is for `Player(i)`. Once this has actions for
    /// every joined player, we apply all the actions to our state in a given
    /// order, compute the new state's checksum, and then transmit the collected
    /// moves to all the players.
    pending_actions: Vec<Option<(PlayerActions, Box<Notifier + Send>)>>,

    /// The last time we broadcast out turns to everyone. We make sure not
    /// to send out the next move until at least MIN_DELAY_NS after this time.
    last_broadcast: Instant,
}

/// Something that can notify a player of a turn's actions when they have been
/// collected.
pub trait Notifier {
    fn notify(self: Box<Self>, turn: CollectedActions);
}

impl Scheduler {
    pub fn new(initial_state: State) -> Scheduler {
        Scheduler { turn: 0, state: initial_state, pending_actions: vec![],
                    last_broadcast: Instant::now()
        }
    }

    // Add another player to the game. If there is room, return the player's
    // number and a representation of the current game state. Return `None` if
    // there is no room for more players.
    pub fn player_join(&mut self) -> Option<(Player, SerializableState)> {
        if self.pending_actions.len() >= self.state.max_players() {
            None
        } else {
            self.pending_actions.push(None);
            Some((Player(self.pending_actions.len() - 1), self.state.serializable()))
        }
    }

    // Submit `actions` to be carried out as soon as possible. When all players'
    // actions have been collected, send the full list to `reply_to`.
    pub fn submit_actions(&mut self,
                          actions: PlayerActions,
                          reply_to: Box<Notifier + Send>) {
        assert_eq!(actions.turn, self.turn);
        assert!(self.pending_actions[actions.player.0].is_none());
        let player = actions.player.0;
        self.pending_actions[player] = Some((actions, reply_to));

        // Have all the players that have joined finally submitted an action?
        if self.pending_actions.iter().all(|o| o.is_some()) {

            // Make sure at least MIN_DELAY_NS nanoseconds have elapsed since
            // our last broadcast.
            let now = Instant::now();
            let since_last = now - self.last_broadcast;
            if since_last < Duration::new(0, MIN_DELAY_NS) {
                thread::sleep(Duration::new(0, MIN_DELAY_NS) - since_last);
            }

            // Grab the list of pending actions and reset it for the next turn.
            let pendings = replace(&mut self.pending_actions, vec![]);

            // Collect all the actions into a single vector,
            // collect all the reply-to's in another vector,
            // and apply all the actions to our state.
            let mut collected_reply_tos = Vec::new();
            let mut collected_actions = Vec::new();

            for player in pendings {
                let (player_actions, reply_to) = player.unwrap();
                for action in player_actions.actions {
                    self.state.take_action(&action);
                    collected_actions.push(action);
                }
                collected_reply_tos.push(reply_to);
                self.pending_actions.push(None);
            }
            self.state.advance();

            let state_checksum = self.state.checksum();

            // We are now in the new turn.
            self.turn += 1;

            let collected = CollectedActions {
                turn: self.turn,
                actions: collected_actions,
                state_checksum
            };

            // Broadcast out the new state of the world to all players.
            for reply_to in collected_reply_tos {
                reply_to.notify(collected.clone());
            }

            self.last_broadcast = now;
        }
    }
}

/// A set of actions submitted by a single player on a single turn.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PlayerActions {
    // The player submitting these actions.
    pub player: Player,

    // The turn number they believe they're on.
    pub turn: usize,

    // The actions they wish to submit.
    pub actions: Vec<Action>,
}

/// A collection of all actions submitted by all players.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CollectedActions {
    // The turn these moves produce when applied.
    pub turn: usize,

    // The actions to apply to the prior state.
    pub actions: Vec<Action>,

    // The hash value of the State that should result, as a checksum.
    pub state_checksum: u64
}
<|endoftext|>


<commit_before>#[derive(PartialEq, Debug, Clone)]
pub enum Token {
    Word(String),

    //characters
    LeftParenthesis,
    RightParenthesis,
    SemiColon,
    SingleQuote,
    Colon
}

pub struct Lexer {
    src: Vec<char>,
}

impl Lexer {

    pub fn new(line: &str) -> Lexer {
        Lexer {
            src: line.chars().collect::<Vec<char>>()
        }
    }

    pub fn next_lexem(&mut self) -> Option<Token> {
        self.remove_front_spaces();
        if self.src.is_empty() {
            None
        }
        else {
            Some(self.parse_lexem())
        }
    }

    fn parse_lexem(&mut self) -> Token {
        if self.has_lexem_in_begining() {
            let s = self.src.remove(0);
            println!("38 s - {:?}", s);
            match s {
                '(' => return Token::LeftParenthesis,
                ',' => return Token::Colon,
                ')' => return Token::RightParenthesis,
                ';' => return Token::SemiColon,
                _ => {}
            }
        }
        let mut i = 0;
        while i < self.src.len() {
            let s = self.src[i];
            println!("50 s - {:?}", s);
            match s {
                'a'...'z' |
                'A'...'Z' |
                '0'...'9' |
                '_' => i += 1,
                '\'' => {
                    if i == 0 {
                        self.src = self.src.split_off(1);
                        return Token::SingleQuote;
                    }
                    else if self.src[i] == '\''
                            && self.src[i+1] == '\'' {
                        self.src.remove(i);
                        i += 1;
                    }
                    else {
                        break;
                    }
                },
                ' ' | '\t' | '\n' => { if i == 0 { self.src.remove(0); } else { break; } },
                '-' => {
                    if i == 0 && self.src[1] == '-' {
                        let mut j = 2;
                        let mut c = self.src[j];
                        while c != '\n' {
                            j += 1;
                            c = self.src[j];
                        }
                        self.src = self.src.split_off(j);
                    }
                }
                _ => break,
            }
        }
        let mut v = self.src.clone();
        self.src = v.split_off(i);
        Token::Word(v.iter().map(|c| *c).collect::<String>().to_lowercase())
    }

    fn has_lexem_in_begining(&self) -> bool {
        match self.src[0] {
            '(' | ')' | ',' | ';' => true,
            _ => false,
        }
    }

    fn remove_front_spaces(&mut self) {
        while !self.src.is_empty()
                && (self.src[0] == ' '
                || self.src[0] == '\t'
                || self.src[0] == '\n') {
            self.src.remove(0);
        }
    }
}
<commit_msg>impl: bunch of single quotes<commit_after>#[derive(PartialEq, Debug, Clone)]
pub enum Token {
    Word(String),

    //characters
    LeftParenthesis,
    RightParenthesis,
    SemiColon,
    SingleQuote,
    Colon
}

pub struct Lexer {
    src: Vec<char>,
    string_expr: bool
}

impl Lexer {

    pub fn new(line: &str) -> Lexer {
        Lexer {
            src: line.chars().collect::<Vec<char>>(),
            string_expr: false
        }
    }

    pub fn next_lexem(&mut self) -> Option<Token> {
        self.remove_front_spaces();
        if self.src.is_empty() {
            None
        }
        else {
            Some(self.parse_lexem())
        }
    }

    fn parse_lexem(&mut self) -> Token {
        if self.has_lexem_in_begining() {
            let s = self.src.remove(0);
            println!("38 s - {:?}", s);
            match s {
                '(' => return Token::LeftParenthesis,
                ',' => return Token::Colon,
                ')' => return Token::RightParenthesis,
                ';' => return Token::SemiColon,
                _ => {}
            }
        }
        let mut i = 0;
        while i < self.src.len() {
            let s = self.src[i];
            match s {
                'a'...'z' |
                'A'...'Z' |
                '0'...'9' |
                '_' => i += 1,
                '\'' => {
                    if i == 0 && !self.string_expr {
                        self.src = self.src.split_off(1);
                        println!("60 s - {:?}", s);
                        self.string_expr = !self.string_expr;
                        return Token::SingleQuote;
                    }
                    else if self.src.len() - i > 1
                            && self.src[i] == '\''
                            && self.src[i+1] == '\''
                            && self.string_expr {
                        println!("67 s - {:?}", s);
                        println!("68 [i] - {:?}", self.src[i]);
                        self.src.remove(i);
                        i += 1;
                    }
                    else {
                        self.string_expr = !self.string_expr;
                        break;
                    }
                },
                ' ' | '\t' | '\n' => {
                    if i == 0 && !self.string_expr {
                        println!("78 s - {:?}", s);
                        self.src.remove(0);
                    }
                    else if self.string_expr {
                        println!("82 s - {:?}", s);
                        i += 1;
                    }
                    else {
                        break;
                    }
                },
                '-' => {
                    if i == 0 && self.src[1] == '-' {
                        let mut j = 2;
                        let mut c = self.src[j];
                        while c != '\n' {
                            j += 1;
                            c = self.src[j];
                        }
                        self.src = self.src.split_off(j);
                    }
                }
                _ => break,
            }
        }
        let mut v = self.src.clone();
        self.src = v.split_off(i);
        Token::Word(v.iter().map(|c| *c).collect::<String>().to_lowercase())
    }

    fn has_lexem_in_begining(&self) -> bool {
        match self.src[0] {
            '(' | ')' | ',' | ';' => true,
            _ => false,
        }
    }

    fn remove_front_spaces(&mut self) {
        while !self.src.is_empty()
                && !self.string_expr
                && (self.src[0] == ' '
                || self.src[0] == '\t'
                || self.src[0] == '\n') {
            self.src.remove(0);
        }
    }
}
<|endoftext|>