<commit_before>use crate::common::BinarySerializable;
use once_cell::sync::Lazy;
use regex::Regex;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Borrow;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter};
use std::io::{self, Read, Write};
use std::str;
use std::string::FromUtf8Error;

const SLASH_BYTE: u8 = b'/';
const ESCAPE_BYTE: u8 = b'\\';

/// BYTE used as a level separation in the binary
/// representation of facets.
pub const FACET_SEP_BYTE: u8 = 0u8;

/// `char` used as a level separation in the binary
/// representation of facets. (It is the null codepoint.)
pub const FACET_SEP_CHAR: char = '\u{0}';

/// A Facet represent a point in a given hierarchy.
///
/// They are typically represented similarly to a filepath.
/// For instance, an e-commerce website could
/// have a `Facet` for `/electronics/tv_and_video/led_tv`.
///
/// A document can be associated to any number of facets.
/// The hierarchy implicitely imply that a document
/// belonging to a facet also belongs to the ancestor of
/// its facet. In the example above, `/electronics/tv_and_video/`
/// and `/electronics`.
#[derive(Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub struct Facet(String);

impl Facet {
    /// Returns a new instance of the "root facet"
    /// Equivalent to `/`.
    pub fn root() -> Facet {
        Facet("".to_string())
    }

    /// Returns true iff the facet is the root facet `/`.
    pub fn is_root(&self) -> bool {
        self.encoded_str().is_empty()
    }

    /// Returns a binary representation of the facet.
    ///
    /// In this representation, `0u8` is used as a separator
    /// and the string parts of the facet are unescaped.
    /// (The first `/` is not encoded at all).
    ///
    /// This representation has the benefit of making it possible to
    /// express "being a child of a given facet" as a range over
    /// the term ordinals.
    pub fn encoded_str(&self) -> &str {
        &self.0
    }

    pub(crate) fn from_encoded_string(facet_string: String) -> Facet {
        Facet(facet_string)
    }

    /// Creates a `Facet` from its binary representation.
    pub fn from_encoded(encoded_bytes: Vec<u8>) -> Result<Facet, FromUtf8Error> {
        // facet bytes validation. `0u8` is used a separator but that is still legal utf-8
        //Ok(Facet(String::from_utf8(encoded_bytes)?))
        String::from_utf8(encoded_bytes).map(Facet)
    }

    /// Parse a text representation of a facet.
    ///
    /// It is conceptually, if one of the steps of this path
    /// contains a `/` or a `\`, it should be escaped
    /// using an anti-slash `/`.
    pub fn from_text<T>(path: &T) -> Facet
    where
        T: ?Sized + AsRef<str>,
    {
        From::from(path)
    }

    /// Returns a `Facet` from an iterator over the different
    /// steps of the facet path.
    ///
    /// The steps are expected to be unescaped.
    pub fn from_path<Path>(path: Path) -> Facet
    where
        Path: IntoIterator,
        Path::Item: ToString,
    {
        let mut facet_string: String = String::with_capacity(100);
        let mut step_it = path.into_iter();
        if let Some(step) = step_it.next() {
            facet_string.push_str(&step.to_string());
        }
        for step in step_it {
            facet_string.push(FACET_SEP_CHAR);
            facet_string.push_str(&step.to_string());
        }
        Facet(facet_string)
    }

    /// Accessor for the inner buffer of the `Facet`.
    pub(crate) fn set_facet_str(&mut self, facet_str: &str) {
        self.0.clear();
        self.0.push_str(facet_str);
    }

    /// Returns `true` iff other is a subfacet of `self`.
    pub fn is_prefix_of(&self, other: &Facet) -> bool {
        let self_str = self.encoded_str();
        let other_str = other.encoded_str();
        self_str.len() < other_str.len()
            && other_str.starts_with(self_str)
            && other_str.as_bytes()[self_str.len()] == FACET_SEP_BYTE
    }
}

impl Borrow<str> for Facet {
    fn borrow(&self) -> &str {
        self.encoded_str()
    }
}

impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for Facet {
    fn from(path_asref: &'a T) -> Facet {
        #[derive(Copy, Clone)]
        enum State {
            Escaped,
            Idle,
        }
        let path: &str = path_asref.as_ref();
        assert!(!path.is_empty());
        assert!(path.starts_with('/'));
        let mut facet_encoded = String::new();
        let mut state = State::Idle;
        let path_bytes = path.as_bytes();
        let mut last_offset = 1;
        for i in 1..path_bytes.len() {
            let c = path_bytes[i];
            match (state, c) {
                (State::Idle, ESCAPE_BYTE) => {
                    facet_encoded.push_str(&path[last_offset..i]);
                    last_offset = i + 1;
                    state = State::Escaped
                }
                (State::Idle, SLASH_BYTE) => {
                    facet_encoded.push_str(&path[last_offset..i]);
                    facet_encoded.push(FACET_SEP_CHAR);
                    last_offset = i + 1;
                }
                (State::Escaped, _escaped_char) => {
                    state = State::Idle;
                }
                (State::Idle, _any_char) => {}
            }
        }
        facet_encoded.push_str(&path[last_offset..]);
        Facet(facet_encoded)
    }
}

impl BinarySerializable for Facet {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        <String as BinarySerializable>::serialize(&self.0, writer)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        Ok(Facet(<String as BinarySerializable>::deserialize(reader)?))
    }
}

impl Display for Facet {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        for step in self.0.split(FACET_SEP_CHAR) {
            write!(f, "/")?;
            write!(f, "{}", escape_slashes(step))?;
        }
        Ok(())
    }
}

fn escape_slashes(s: &str) -> Cow<'_, str> {
    static SLASH_PTN: Lazy<Regex> = Lazy::new(|| Regex::new(r"[\\/]").unwrap());
    SLASH_PTN.replace_all(s, "\\/")
}

impl Serialize for Facet {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

impl<'de> Deserialize<'de> for Facet {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        <&'de str as Deserialize<'de>>::deserialize(deserializer).map(Facet::from)
    }
}

impl Debug for Facet {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "Facet({})", self)?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use super::Facet;

    #[test]
    fn test_root() {
        assert_eq!(Facet::root(), Facet::from("/"));
        assert_eq!(format!("{}", Facet::root()), "/");
        assert!(Facet::root().is_root());
    }

    #[test]
    fn test_from_path() {
        assert_eq!(
            Facet::from_path(vec!["top", "a", "firstdoc"]),
            Facet::from("/top/a/firstdoc")
        );
    }

    #[test]
    fn test_facet_display() {
        {
            let v = ["first", "second", "third"];
            let facet = Facet::from_path(v.iter());
            assert_eq!(format!("{}", facet), "/first/second/third");
        }
        {
            let v = ["first", "sec/ond", "third"];
            let facet = Facet::from_path(v.iter());
            assert_eq!(format!("{}", facet), "/first/sec\\/ond/third");
        }
    }

    #[test]
    fn test_facet_debug() {
        let v = ["first", "second", "third"];
        let facet = Facet::from_path(v.iter());
        assert_eq!(format!("{:?}", facet), "Facet(/first/second/third)");
    }

}
<commit_msg>add to_path for Facet (#604)<commit_after>use crate::common::BinarySerializable;
use once_cell::sync::Lazy;
use regex::Regex;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Borrow;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter};
use std::io::{self, Read, Write};
use std::str;
use std::string::FromUtf8Error;

const SLASH_BYTE: u8 = b'/';
const ESCAPE_BYTE: u8 = b'\\';

/// BYTE used as a level separation in the binary
/// representation of facets.
pub const FACET_SEP_BYTE: u8 = 0u8;

/// `char` used as a level separation in the binary
/// representation of facets. (It is the null codepoint.)
pub const FACET_SEP_CHAR: char = '\u{0}';

/// A Facet represent a point in a given hierarchy.
///
/// They are typically represented similarly to a filepath.
/// For instance, an e-commerce website could
/// have a `Facet` for `/electronics/tv_and_video/led_tv`.
///
/// A document can be associated to any number of facets.
/// The hierarchy implicitely imply that a document
/// belonging to a facet also belongs to the ancestor of
/// its facet. In the example above, `/electronics/tv_and_video/`
/// and `/electronics`.
#[derive(Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub struct Facet(String);

impl Facet {
    /// Returns a new instance of the "root facet"
    /// Equivalent to `/`.
    pub fn root() -> Facet {
        Facet("".to_string())
    }

    /// Returns true iff the facet is the root facet `/`.
    pub fn is_root(&self) -> bool {
        self.encoded_str().is_empty()
    }

    /// Returns a binary representation of the facet.
    ///
    /// In this representation, `0u8` is used as a separator
    /// and the string parts of the facet are unescaped.
    /// (The first `/` is not encoded at all).
    ///
    /// This representation has the benefit of making it possible to
    /// express "being a child of a given facet" as a range over
    /// the term ordinals.
    pub fn encoded_str(&self) -> &str {
        &self.0
    }

    pub(crate) fn from_encoded_string(facet_string: String) -> Facet {
        Facet(facet_string)
    }

    /// Creates a `Facet` from its binary representation.
    pub fn from_encoded(encoded_bytes: Vec<u8>) -> Result<Facet, FromUtf8Error> {
        // facet bytes validation. `0u8` is used a separator but that is still legal utf-8
        //Ok(Facet(String::from_utf8(encoded_bytes)?))
        String::from_utf8(encoded_bytes).map(Facet)
    }

    /// Parse a text representation of a facet.
    ///
    /// It is conceptually, if one of the steps of this path
    /// contains a `/` or a `\`, it should be escaped
    /// using an anti-slash `/`.
    pub fn from_text<T>(path: &T) -> Facet
    where
        T: ?Sized + AsRef<str>,
    {
        From::from(path)
    }

    /// Returns a `Facet` from an iterator over the different
    /// steps of the facet path.
    ///
    /// The steps are expected to be unescaped.
    pub fn from_path<Path>(path: Path) -> Facet
    where
        Path: IntoIterator,
        Path::Item: ToString,
    {
        let mut facet_string: String = String::with_capacity(100);
        let mut step_it = path.into_iter();
        if let Some(step) = step_it.next() {
            facet_string.push_str(&step.to_string());
        }
        for step in step_it {
            facet_string.push(FACET_SEP_CHAR);
            facet_string.push_str(&step.to_string());
        }
        Facet(facet_string)
    }

    /// Accessor for the inner buffer of the `Facet`.
    pub(crate) fn set_facet_str(&mut self, facet_str: &str) {
        self.0.clear();
        self.0.push_str(facet_str);
    }

    /// Returns `true` iff other is a subfacet of `self`.
    pub fn is_prefix_of(&self, other: &Facet) -> bool {
        let self_str = self.encoded_str();
        let other_str = other.encoded_str();
        self_str.len() < other_str.len()
            && other_str.starts_with(self_str)
            && other_str.as_bytes()[self_str.len()] == FACET_SEP_BYTE
    }

    /// Extract path from the `Facet`.
    pub fn to_path(&self) -> Vec<&str> {
        self.encoded_str()
            .split(|c| c == FACET_SEP_CHAR)
            .collect()
    }
}

impl Borrow<str> for Facet {
    fn borrow(&self) -> &str {
        self.encoded_str()
    }
}

impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for Facet {
    fn from(path_asref: &'a T) -> Facet {
        #[derive(Copy, Clone)]
        enum State {
            Escaped,
            Idle,
        }
        let path: &str = path_asref.as_ref();
        assert!(!path.is_empty());
        assert!(path.starts_with('/'));
        let mut facet_encoded = String::new();
        let mut state = State::Idle;
        let path_bytes = path.as_bytes();
        let mut last_offset = 1;
        for i in 1..path_bytes.len() {
            let c = path_bytes[i];
            match (state, c) {
                (State::Idle, ESCAPE_BYTE) => {
                    facet_encoded.push_str(&path[last_offset..i]);
                    last_offset = i + 1;
                    state = State::Escaped
                }
                (State::Idle, SLASH_BYTE) => {
                    facet_encoded.push_str(&path[last_offset..i]);
                    facet_encoded.push(FACET_SEP_CHAR);
                    last_offset = i + 1;
                }
                (State::Escaped, _escaped_char) => {
                    state = State::Idle;
                }
                (State::Idle, _any_char) => {}
            }
        }
        facet_encoded.push_str(&path[last_offset..]);
        Facet(facet_encoded)
    }
}

impl BinarySerializable for Facet {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        <String as BinarySerializable>::serialize(&self.0, writer)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        Ok(Facet(<String as BinarySerializable>::deserialize(reader)?))
    }
}

impl Display for Facet {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        for step in self.0.split(FACET_SEP_CHAR) {
            write!(f, "/")?;
            write!(f, "{}", escape_slashes(step))?;
        }
        Ok(())
    }
}

fn escape_slashes(s: &str) -> Cow<'_, str> {
    static SLASH_PTN: Lazy<Regex> = Lazy::new(|| Regex::new(r"[\\/]").unwrap());
    SLASH_PTN.replace_all(s, "\\/")
}

impl Serialize for Facet {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

impl<'de> Deserialize<'de> for Facet {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        <&'de str as Deserialize<'de>>::deserialize(deserializer).map(Facet::from)
    }
}

impl Debug for Facet {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(f, "Facet({})", self)?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {

    use super::Facet;

    #[test]
    fn test_root() {
        assert_eq!(Facet::root(), Facet::from("/"));
        assert_eq!(format!("{}", Facet::root()), "/");
        assert!(Facet::root().is_root());
    }

    #[test]
    fn test_from_path() {
        assert_eq!(
            Facet::from_path(vec!["top", "a", "firstdoc"]),
            Facet::from("/top/a/firstdoc")
        );
    }

    #[test]
    fn test_facet_display() {
        {
            let v = ["first", "second", "third"];
            let facet = Facet::from_path(v.iter());
            assert_eq!(format!("{}", facet), "/first/second/third");
        }
        {
            let v = ["first", "sec/ond", "third"];
            let facet = Facet::from_path(v.iter());
            assert_eq!(format!("{}", facet), "/first/sec\\/ond/third");
        }
    }

    #[test]
    fn test_facet_debug() {
        let v = ["first", "second", "third"];
        let facet = Facet::from_path(v.iter());
        assert_eq!(format!("{:?}", facet), "Facet(/first/second/third)");
    }

    #[test]
    fn test_to_path() {
        let v = ["first", "second", "third\\/not_fourth"];
        let facet = Facet::from_path(v.iter());
        assert_eq!(facet.to_path(), v);
    }
}
<|endoftext|>


<commit_before>//! PS/2 unfortunately requires a kernel driver to prevent race conditions due
//! to how status is utilized
use core::str;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use crate::arch::debug::Writer;
use crate::event;
use crate::scheme::*;
use crate::sync::WaitQueue;
use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use crate::syscall::scheme::Scheme;

static SCHEME_ID: AtomicSchemeId = AtomicSchemeId::default();

static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

/// Input queue
static INPUT: [Once<WaitQueue<u8>>; 2] = [Once::new(), Once::new()];

/// Initialize input queue, called if needed
fn init_input() -> WaitQueue<u8> {
    WaitQueue::new()
}

#[derive(Clone, Copy)]
struct Handle {
    index: usize,
    flags: usize,
}

static HANDLES: Once<RwLock<BTreeMap<usize, Handle>>> = Once::new();

fn init_handles() -> RwLock<BTreeMap<usize, Handle>> {
    RwLock::new(BTreeMap::new())
}

fn handles() -> RwLockReadGuard<'static, BTreeMap<usize, Handle>> {
    HANDLES.call_once(init_handles).read()
}

fn handles_mut() -> RwLockWriteGuard<'static, BTreeMap<usize, Handle>> {
    HANDLES.call_once(init_handles).write()
}

/// Add to the input queue
pub fn serio_input(index: usize, data: u8) {
    INPUT[index].call_once(init_input).send(data);
    for (id, _handle) in handles().iter() {
        event::trigger(SCHEME_ID.load(Ordering::SeqCst), *id, EVENT_READ);
    }
}

pub struct SerioScheme;

impl SerioScheme {
    pub fn new(scheme_id: SchemeId) -> Self {
        SCHEME_ID.store(scheme_id, Ordering::SeqCst);
        Self
    }
}

impl Scheme for SerioScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        if uid != 0 {
            return Err(Error::new(EPERM));
        }

        let index = str::from_utf8(path)
            .map_err(|err| Error::new(ENOENT))?
            .parse::<usize>()
            .map_err(|err| Error::new(ENOENT))?;
        if index >= INPUT.len() {
            return Err(Error::new(ENOENT));
        }

        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        handles_mut().insert(id, Handle {
            index,
            flags: flags & ! O_ACCMODE
        });

        Ok(id)
    }

    /// Read the file `number` into the `buffer`
    ///
    /// Returns the number of bytes read
    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        INPUT[handle.index].call_once(init_input)
            .receive_into(buf, handle.flags & O_NONBLOCK != O_NONBLOCK, "SerioScheme::read")
            .ok_or(Error::new(EINTR))
    }

    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
        let mut handles = handles_mut();
        if let Some(handle) = handles.get_mut(&id) {
            match cmd {
                F_GETFL => Ok(handle.flags),
                F_SETFL => {
                    handle.flags = arg & ! O_ACCMODE;
                    Ok(0)
                },
                _ => Err(Error::new(EINVAL))
            }
        } else {
            Err(Error::new(EBADF))
        }
    }

    fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
        let _handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(EventFlags::empty())
    }

    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let mut i = 0;
        let scheme_path = b"serio:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        let file_path = format!("{}", handle.index).into_bytes();
        let mut j = 0;
        while i < buf.len() && j < file_path.len() {
            buf[i] = file_path[j];
            j += 1;
        }

        Ok(i)
    }

    fn fsync(&self, id: usize) -> Result<usize> {
        let _handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }

    /// Close the file `number`
    fn close(&self, id: usize) -> Result<usize> {
        let _handle = {
            let mut handles = handles_mut();
            handles.remove(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }
}
<commit_msg>Remove unused import<commit_after>//! PS/2 unfortunately requires a kernel driver to prevent race conditions due
//! to how status is utilized
use core::str;
use core::sync::atomic::{AtomicUsize, Ordering};
use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard};

use crate::event;
use crate::scheme::*;
use crate::sync::WaitQueue;
use crate::syscall::flag::{EventFlags, EVENT_READ, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
use crate::syscall::scheme::Scheme;

static SCHEME_ID: AtomicSchemeId = AtomicSchemeId::default();

static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

/// Input queue
static INPUT: [Once<WaitQueue<u8>>; 2] = [Once::new(), Once::new()];

/// Initialize input queue, called if needed
fn init_input() -> WaitQueue<u8> {
    WaitQueue::new()
}

#[derive(Clone, Copy)]
struct Handle {
    index: usize,
    flags: usize,
}

static HANDLES: Once<RwLock<BTreeMap<usize, Handle>>> = Once::new();

fn init_handles() -> RwLock<BTreeMap<usize, Handle>> {
    RwLock::new(BTreeMap::new())
}

fn handles() -> RwLockReadGuard<'static, BTreeMap<usize, Handle>> {
    HANDLES.call_once(init_handles).read()
}

fn handles_mut() -> RwLockWriteGuard<'static, BTreeMap<usize, Handle>> {
    HANDLES.call_once(init_handles).write()
}

/// Add to the input queue
pub fn serio_input(index: usize, data: u8) {
    INPUT[index].call_once(init_input).send(data);
    for (id, _handle) in handles().iter() {
        event::trigger(SCHEME_ID.load(Ordering::SeqCst), *id, EVENT_READ);
    }
}

pub struct SerioScheme;

impl SerioScheme {
    pub fn new(scheme_id: SchemeId) -> Self {
        SCHEME_ID.store(scheme_id, Ordering::SeqCst);
        Self
    }
}

impl Scheme for SerioScheme {
    fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result<usize> {
        if uid != 0 {
            return Err(Error::new(EPERM));
        }

        let index = str::from_utf8(path)
            .map_err(|err| Error::new(ENOENT))?
            .parse::<usize>()
            .map_err(|err| Error::new(ENOENT))?;
        if index >= INPUT.len() {
            return Err(Error::new(ENOENT));
        }

        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        handles_mut().insert(id, Handle {
            index,
            flags: flags & ! O_ACCMODE
        });

        Ok(id)
    }

    /// Read the file `number` into the `buffer`
    ///
    /// Returns the number of bytes read
    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        INPUT[handle.index].call_once(init_input)
            .receive_into(buf, handle.flags & O_NONBLOCK != O_NONBLOCK, "SerioScheme::read")
            .ok_or(Error::new(EINTR))
    }

    fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
        let mut handles = handles_mut();
        if let Some(handle) = handles.get_mut(&id) {
            match cmd {
                F_GETFL => Ok(handle.flags),
                F_SETFL => {
                    handle.flags = arg & ! O_ACCMODE;
                    Ok(0)
                },
                _ => Err(Error::new(EINVAL))
            }
        } else {
            Err(Error::new(EBADF))
        }
    }

    fn fevent(&self, id: usize, _flags: EventFlags) -> Result<EventFlags> {
        let _handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(EventFlags::empty())
    }

    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        let handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        let mut i = 0;
        let scheme_path = b"serio:";
        while i < buf.len() && i < scheme_path.len() {
            buf[i] = scheme_path[i];
            i += 1;
        }

        let file_path = format!("{}", handle.index).into_bytes();
        let mut j = 0;
        while i < buf.len() && j < file_path.len() {
            buf[i] = file_path[j];
            j += 1;
        }

        Ok(i)
    }

    fn fsync(&self, id: usize) -> Result<usize> {
        let _handle = {
            let handles = handles();
            *handles.get(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }

    /// Close the file `number`
    fn close(&self, id: usize) -> Result<usize> {
        let _handle = {
            let mut handles = handles_mut();
            handles.remove(&id).ok_or(Error::new(EBADF))?
        };

        Ok(0)
    }
}
<|endoftext|>


<commit_before>extern crate collections;

//use collections::HashMap;
use std::rand;

#[deriving(Clone)]
pub enum Value {
  Float(f64),
  Range(f64,f64)
}

// Set of parameters
#[deriving(Clone)]
pub struct Params {
  pp : collections::HashMap<~str, Value>
}

impl Params {
  #[allow(dead_code)]
  pub fn new() -> Params {
    Params{ pp: collections::HashMap::new() }
  }

  #[allow(dead_code)]
  pub fn insert(&mut self, tag: &str, value: Value) {
    self.pp.insert(tag.to_owned(), value);
  }

  #[allow(dead_code)]
  pub fn get(&self, tag: &str) -> Value {
    *self.pp.find_equiv(&tag).unwrap()
  }

  #[allow(dead_code)]
  pub fn get_float(&self, tag: &str) -> f64 {
    let value=self.pp.find_equiv(&tag);
    match value.unwrap() {
      &Float(f) => { f },
      _ => { fail!(); }
    }
  }

  #[allow(dead_code)]
  pub fn set(&mut self, tag: &str, val: Value) {
    if self.pp.contains_key_equiv(&tag) {
      self.pp.insert(tag.to_owned(), val);
    }
    else {
      fail!();
    }
  }

  #[allow(dead_code)]
  pub fn realize(&self) -> Params {
    let mut hash : collections::HashMap<~str, Value> = collections::HashMap::new();
    for (key, value) in self.pp.iter() {
      match *value {
        Float(f) => { hash.insert(key.to_owned(), Float(f)); },
        Range(f1, f2) => {
          let t=rand::random::<f64>();
          hash.insert(key.to_owned(), Float(t*f1+(1.0-t)*f2));
        }
      }
    }
    Params{ pp: hash }
  }

  #[allow(dead_code)]
  pub fn print(&self) {
    for (key, value) in self.pp.iter() {
      match *value {
        Float(f) => {println!("{} = {:f}", *key, f);}
        Range(f1,f2) => {println!("{} in [{:f}, {:f}]", *key, f1, f2);}
      }
    }
  }

  #[allow(dead_code)]
  pub fn len(&self) -> uint {
    self.pp.len()
  }

  pub fn keys<'s>(&'s self) -> ~[&'s str] {
    let mut res : ~[&str]=~[];
    for (key, _) in self.pp.iter() {
      res.push(key.slice_from(0));
    }
    res
  }

  pub fn varying_keys<'s>(&'s self) -> ~[&'s str] {
   let mut res : ~[&str]=~[];
   for (key, value) in self.pp.iter() {
      match *value {
        Float(_) => {},
        Range(_,_) => { res.push(key.slice_from(0)); }
      }
   }
   res
  }
}

#[test]
fn test_keys() {
  let mut pp=Params::new();
  pp.insert("alpha", Float(1.0)); pp.insert("beta", Float(1.0));

  let lst=pp.keys();
  assert!((lst==~[&"alpha", &"beta"])||(lst==~[&"beta", &"alpha"]));
}

#[test]
fn test_varying_keys() {
 let mut pp=Params::new();
 pp.insert("alpha", Range(0.0, 1.0)); pp.insert("beta", Float(1.0));

 let lst=pp.varying_keys();
 assert_eq!(lst.len(), 1u);
 assert_eq!(lst, ~[&"alpha"]);
}

#[test]
fn test_realize() {
  let mut pp=Params::new();
  pp.insert("alpha", Float(1.0)); pp.insert("beta", Range(0.0,1.0));
  let ppr=pp.realize();

  assert_eq!(ppr.len(), 2u);
  assert_eq!(ppr.get_float("alpha"), 1.0);
  assert!( (ppr.get_float("beta")>=0.0) && (ppr.get_float("beta")<=1.0));
}
<commit_msg>Update for master<commit_after>extern crate collections;
extern crate rand;

//use collections::HashMap;

#[deriving(Clone)]
pub enum Value {
  Float(f64),
  Range(f64,f64)
}

// Set of parameters
#[deriving(Clone)]
pub struct Params {
  pp : collections::HashMap<~str, Value>
}

impl Params {
  #[allow(dead_code)]
  pub fn new() -> Params {
    Params{ pp: collections::HashMap::new() }
  }

  #[allow(dead_code)]
  pub fn insert(&mut self, tag: &str, value: Value) {
    self.pp.insert(tag.to_owned(), value);
  }

  #[allow(dead_code)]
  pub fn get(&self, tag: &str) -> Value {
    *self.pp.find_equiv(&tag).unwrap()
  }

  #[allow(dead_code)]
  pub fn get_float(&self, tag: &str) -> f64 {
    let value=self.pp.find_equiv(&tag);
    match value.unwrap() {
      &Float(f) => { f },
      _ => { fail!(); }
    }
  }

  #[allow(dead_code)]
  pub fn set(&mut self, tag: &str, val: Value) {
    if self.pp.contains_key_equiv(&tag) {
      self.pp.insert(tag.to_owned(), val);
    }
    else {
      fail!();
    }
  }

  #[allow(dead_code)]
  pub fn realize(&self) -> Params {
    let mut hash : collections::HashMap<~str, Value> = collections::HashMap::new();
    for (key, value) in self.pp.iter() {
      match *value {
        Float(f) => { hash.insert(key.to_owned(), Float(f)); },
        Range(f1, f2) => {
          let t=rand::random::<f64>();
          hash.insert(key.to_owned(), Float(t*f1+(1.0-t)*f2));
        }
      }
    }
    Params{ pp: hash }
  }

  #[allow(dead_code)]
  pub fn print(&self) {
    for (key, value) in self.pp.iter() {
      match *value {
        Float(f) => {println!("{} = {:f}", *key, f);}
        Range(f1,f2) => {println!("{} in [{:f}, {:f}]", *key, f1, f2);}
      }
    }
  }

  #[allow(dead_code)]
  pub fn len(&self) -> uint {
    self.pp.len()
  }

  pub fn keys<'s>(&'s self) -> ~[&'s str] {
    let mut res : ~[&str]=~[];
    for (key, _) in self.pp.iter() {
      res.push(key.slice_from(0));
    }
    res
  }

  pub fn varying_keys<'s>(&'s self) -> ~[&'s str] {
   let mut res : ~[&str]=~[];
   for (key, value) in self.pp.iter() {
      match *value {
        Float(_) => {},
        Range(_,_) => { res.push(key.slice_from(0)); }
      }
   }
   res
  }
}

#[test]
fn test_keys() {
  let mut pp=Params::new();
  pp.insert("alpha", Float(1.0)); pp.insert("beta", Float(1.0));

  let lst=pp.keys();
  assert!((lst==~[&"alpha", &"beta"])||(lst==~[&"beta", &"alpha"]));
}

#[test]
fn test_varying_keys() {
 let mut pp=Params::new();
 pp.insert("alpha", Range(0.0, 1.0)); pp.insert("beta", Float(1.0));

 let lst=pp.varying_keys();
 assert_eq!(lst.len(), 1u);
 assert_eq!(lst, ~[&"alpha"]);
}

#[test]
fn test_realize() {
  let mut pp=Params::new();
  pp.insert("alpha", Float(1.0)); pp.insert("beta", Range(0.0,1.0));
  let ppr=pp.realize();

  assert_eq!(ppr.len(), 2u);
  assert_eq!(ppr.get_float("alpha"), 1.0);
  assert!( (ppr.get_float("beta")>=0.0) && (ppr.get_float("beta")<=1.0));
}
<|endoftext|>


<commit_before>use crate::breakpoint::*;
use crate::config::Config;
use crate::errors::RunError;
use crate::ptrace_control::*;
use crate::traces::*;
use log::{debug, warn, trace};
use nix::errno::Errno;
use nix::sys::signal::Signal;
use nix::sys::wait::*;
use nix::unistd::Pid;
use nix::Error as NixErr;
use std::collections::HashMap;
use std::time::Instant;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TestState {
    /// Start state. Wait for test to appear and track time to enable timeout
    Start { start_time: Instant },
    /// Initialise: once test process appears instrument
    Initialise,
    /// Waiting for breakpoint to be hit or test to end
    Waiting { start_time: Instant },
    /// Test process stopped, check coverage
    Stopped,
    /// Test exited normally. Includes the exit code of the test executable.
    End(i32),
}

/// Tracing a process on an OS will have platform specific code.
/// Structs containing the platform specific datastructures should
/// provide this trait with an implementation of the handling of
/// the given states.
pub trait StateData {
    /// Starts the tracing. Returns None while waiting for
    /// start. Statemachine then checks timeout
    fn start(&mut self) -> Result<Option<TestState>, RunError>;
    /// Initialises test for tracing returns next state
    fn init(&mut self) -> Result<TestState, RunError>;
    /// Waits for notification from test executable that there's
    /// something to do. Selects the next appropriate state if there's
    /// something to do otherwise None
    fn wait(&mut self) -> Result<Option<TestState>, RunError>;
    /// Handle a stop in the test executable. Coverage data will
    /// be collected here as well as other OS specific functions
    fn stop(&mut self) -> Result<TestState, RunError>;
}

impl TestState {
    /// Convenience function used to check if the test has finished or errored
    pub fn is_finished(self) -> bool {
        match self {
            TestState::End(_) => true,
            _ => false,
        }
    }

    /// Convenience function for creating start states
    fn start_state() -> TestState {
        TestState::Start {
            start_time: Instant::now(),
        }
    }

    /// Convenience function for creating wait states
    fn wait_state() -> TestState {
        TestState::Waiting {
            start_time: Instant::now(),
        }
    }

    /// Updates the state machine state
    pub fn step<T: StateData>(self, data: &mut T, config: &Config) -> Result<TestState, RunError> {
        match self {
            TestState::Start { start_time } => {
                if let Some(s) = data.start()? {
                    Ok(s)
                } else if start_time.elapsed() >= config.test_timeout {
                    Err(RunError::TestRuntime(
                        "Error: Timed out when starting test".to_string(),
                    ))
                } else {
                    Ok(TestState::Start { start_time })
                }
            }
            TestState::Initialise => data.init(),
            TestState::Waiting { start_time } => {
                if let Some(s) = data.wait()? {
                    Ok(s)
                } else if start_time.elapsed() >= config.test_timeout {
                    Err(RunError::TestRuntime(
                        "Error: Timed out waiting for test response".to_string(),
                    ))
                } else {
                    Ok(TestState::Waiting { start_time })
                }
            }
            TestState::Stopped => data.stop(),
            _ => {
                // Unhandled
                if config.verbose {
                    println!("Tarpaulin error: unhandled test state");
                }
                Ok(TestState::End(-1))
            }
        }
    }
}

pub fn create_state_machine<'a>(
    test: Pid,
    traces: &'a mut TraceMap,
    config: &'a Config,
) -> (TestState, LinuxData<'a>) {
    let mut data = LinuxData::new(traces, config);
    data.parent = test;
    (TestState::start_state(), data)
}

/// Handle to linux process state
pub struct LinuxData<'a> {
    /// Recent result from waitpid to be handled by statemachine
    wait: WaitStatus,
    /// Current Pid to process
    current: Pid,
    /// Parent PID of test process
    parent: Pid,
    /// Map of addresses to breakpoints
    breakpoints: HashMap<u64, Breakpoint>,
    /// Instrumentation points in code with associated coverage data
    traces: &'a mut TraceMap,
    /// Program config
    config: &'a Config,
    /// Thread count. Hopefully getting rid of in future
    thread_count: isize,
    /// Used to show anomalies noticed so hit counts disabled
    force_disable_hit_count: bool,
}

impl<'a> StateData for LinuxData<'a> {
    fn start(&mut self) -> Result<Option<TestState>, RunError> {
        match waitpid(self.current, Some(WaitPidFlag::WNOHANG)) {
            Ok(WaitStatus::StillAlive) => Ok(None),
            Ok(sig @ WaitStatus::Stopped(_, Signal::SIGTRAP)) => {
                if let WaitStatus::Stopped(child, _) = sig {
                    self.current = child;
                }
                self.wait = sig;
                trace!("Caught inferior transitioning to Initialise state");
                Ok(Some(TestState::Initialise))
            }
            Ok(_) => Err(RunError::TestRuntime(
                "Unexpected signal when starting test".to_string(),
            )),
            Err(e) => Err(RunError::TestRuntime(format!(
                "Error when starting test: {}",
                e
            ))),
        }
    }

    fn init(&mut self) -> Result<TestState, RunError> {
        trace_children(self.current)?;
        for trace in self.traces.all_traces() {
            if let Some(addr) = trace.address {
                match Breakpoint::new(self.current, addr) {
                    Ok(bp) => {
                        let _ = self.breakpoints.insert(addr, bp);
                    }
                    Err(e) if e == NixErr::Sys(Errno::EIO) => {
                        return Err(RunError::TestRuntime(
                            "ERROR: Tarpaulin cannot find code addresses \
                             check that pie is disabled for your linker. \
                             If linking with gcc try adding -C link-args=-no-pie \
                             to your rust flags"
                                .to_string(),
                        ));
                    }
                    Err(NixErr::UnsupportedOperation) => {
                        debug!("Instrumentation address clash, ignoring 0x{:x}", addr);
                    }
                    Err(_) => {
                        return Err(RunError::TestRuntime(
                            "Failed to instrument test executable".to_string(),
                        ));
                    }
                }
            }
        }

        if continue_exec(self.parent, None).is_ok() {
            trace!("Initialised inferior, transitioning to wait state");
            Ok(TestState::wait_state())
        } else {
            Err(RunError::TestRuntime(
                "Test didn't launch correctly".to_string(),
            ))
        }
    }

    fn wait(&mut self) -> Result<Option<TestState>, RunError> {
        let wait = waitpid(
            Pid::from_raw(-1),
            Some(WaitPidFlag::WNOHANG | WaitPidFlag::__WALL),
        );
        match wait {
            Ok(WaitStatus::StillAlive) => {
                self.wait = WaitStatus::StillAlive;
                Ok(None)
            }
            Ok(s) => {
                self.wait = s;
                Ok(Some(TestState::Stopped))
            }
            Err(e) => Err(RunError::TestRuntime(format!(
                "An error occurred while waiting for response from test: {}",
                e
            ))),
        }
    }

    fn stop(&mut self) -> Result<TestState, RunError> {
        trace!("Caught signal {:?}", self.wait);
        match self.wait {
            WaitStatus::PtraceEvent(c, s, e) => match self.handle_ptrace_event(c, s, e) {
                Ok(s) => Ok(s),
                Err(e) => Err(RunError::TestRuntime(format!(
                    "Error occurred when handling ptrace event: {}",
                    e
                ))),
            },
            WaitStatus::Stopped(c, Signal::SIGTRAP) => {
                self.current = c;
                match self.collect_coverage_data() {
                    Ok(s) => Ok(s),
                    Err(e) => Err(RunError::TestRuntime(format!(
                        "Error when collecting coverage: {}",
                        e
                    ))),
                }
            }
            WaitStatus::Stopped(child, Signal::SIGSTOP) => match continue_exec(child, None) {
                Ok(_) => Ok(TestState::wait_state()),
                Err(e) => Err(RunError::TestRuntime(format!(
                    "Error processing SIGSTOP: {}",
                    e.to_string()
                ))),
            },
            WaitStatus::Stopped(_, Signal::SIGSEGV) => Err(RunError::TestRuntime(
                "A segfault occurred while executing tests".to_string(),
            )),
            WaitStatus::Stopped(c, s) => {
                let sig = if self.config.forward_signals {
                    Some(s)
                } else {
                    None
                };
                let _ = continue_exec(c, sig);
                Ok(TestState::wait_state())
            }
            WaitStatus::Signaled(_, _, _) => {
                if let Ok(s) = self.handle_signaled() {
                    Ok(s)
                } else {
                    Err(RunError::TestRuntime(
                        "Attempting to handle tarpaulin being signaled".to_string(),
                    ))
                }
            }
            WaitStatus::Exited(child, ec) => {
                for ref mut value in self.breakpoints.values_mut() {
                    value.thread_killed(child);
                }
                if child == self.parent {
                    Ok(TestState::End(ec))
                } else {
                    // Process may have already been destroyed. This is just incase
                    let _ = continue_exec(self.parent, None);
                    Ok(TestState::wait_state())
                }
            }
            _ => Err(RunError::TestRuntime(
                "An unexpected signal has been caught by tarpaulin!".to_string(),
            )),
        }
    }
}

impl<'a> LinuxData<'a> {
    pub fn new(traces: &'a mut TraceMap, config: &'a Config) -> LinuxData<'a> {
        LinuxData {
            wait: WaitStatus::StillAlive,
            current: Pid::from_raw(0),
            parent: Pid::from_raw(0),
            breakpoints: HashMap::new(),
            traces,
            config,
            thread_count: 0,
            force_disable_hit_count: config.count,
        }
    }

    fn handle_ptrace_event(
        &mut self,
        child: Pid,
        sig: Signal,
        event: i32,
    ) -> Result<TestState, RunError> {
        use nix::libc::*;

        if sig == Signal::SIGTRAP {
            trace!("Handling ptrace event {}", event);
            match event {
                PTRACE_EVENT_CLONE => {
                    match get_event_data(child) {
                        Ok(t) => {
                            trace!("New thread spawned {}", t);
                            self.thread_count += 1;
                            continue_exec(child, None)?;
                            Ok(TestState::wait_state())
                        },
                        Err(e) => {
                            trace!("Error in clone event {:?}", e);
                            Err(RunError::TestRuntime(
                                "Error occurred upon test executable thread creation".to_string(),
                            ))
                        }
                    }
                }
                PTRACE_EVENT_FORK | PTRACE_EVENT_VFORK => {
                    continue_exec(child, None)?;
                    Ok(TestState::wait_state())
                }
                PTRACE_EVENT_EXEC => {
                    detach_child(child)?;
                    Ok(TestState::wait_state())
                }
                PTRACE_EVENT_EXIT => {
                    self.thread_count -= 1;
                    continue_exec(child, None)?;
                    Ok(TestState::wait_state())
                }
                _ => Err(RunError::TestRuntime(format!(
                    "Unrecognised ptrace event {}",
                    event
                ))),
            }
        } else {
            trace!("Unexpected signal with ptrace event {}", event);
            trace!("Signal: {:?}", sig);
            Err(RunError::TestRuntime("Unexpected signal".to_string()))
        }
    }

    fn collect_coverage_data(&mut self) -> Result<TestState, RunError> {
        if let Ok(rip) = current_instruction_pointer(self.current) {
            let rip = (rip - 1) as u64;
            trace!("Hit address 0x{:x}", rip);
            if self.breakpoints.contains_key(&rip) {
                let bp = &mut self.breakpoints.get_mut(&rip).unwrap();
                let enable = self.config.count && self.thread_count < 2;
                if !enable && self.force_disable_hit_count {
                    warn!("Code is mulithreaded, disabling hit count");
                    warn!("Results may be improved by not using the '--count' option when running tarpaulin");
                    self.force_disable_hit_count = false;
                }
                // Don't reenable if multithreaded as can't yet sort out segfault issue
                let updated = if let Ok(x) = bp.process(self.current, enable) {
                    x
                } else {
                    // So failed to process a breakpoint.. Still continue to avoid
                    // stalling
                    continue_exec(self.current, None)?;
                    false
                };
                if updated {
                    if let Some(ref mut t) = self.traces.get_trace_mut(rip) {
                        if let CoverageStat::Line(ref mut x) = t.stats {
                            trace!("Incrementing hit count for trace");
                            *x += 1;
                        }
                    }
                }
            } else {
                continue_exec(self.current, None)?;
            }
        } else {
            continue_exec(self.current, None)?;
        }
        Ok(TestState::wait_state())
    }

    fn handle_signaled(&mut self) -> Result<TestState, RunError> {
        match self.wait {
            WaitStatus::Signaled(child, Signal::SIGTRAP, true) => {
                continue_exec(child, None)?;
                Ok(TestState::wait_state())
            }
            _ => Err(RunError::StateMachine("Unexpected stop".to_string())),
        }
    }
}
<commit_msg>Added messages for state machine<commit_after>use crate::breakpoint::*;
use crate::config::Config;
use crate::errors::RunError;
use crate::ptrace_control::*;
use crate::traces::*;
use log::{debug, warn, trace};
use nix::errno::Errno;
use nix::sys::signal::Signal;
use nix::sys::wait::*;
use nix::unistd::Pid;
use nix::Error as NixErr;
use std::collections::HashMap;
use std::time::Instant;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TestState {
    /// Start state. Wait for test to appear and track time to enable timeout
    Start { start_time: Instant },
    /// Initialise: once test process appears instrument
    Initialise,
    /// Waiting for breakpoint to be hit or test to end
    Waiting { start_time: Instant },
    /// Test process stopped, check coverage
    Stopped,
    /// Test exited normally. Includes the exit code of the test executable.
    End(i32),
}

/// Tracing a process on an OS will have platform specific code.
/// Structs containing the platform specific datastructures should
/// provide this trait with an implementation of the handling of
/// the given states.
pub trait StateData {
    /// Starts the tracing. Returns None while waiting for
    /// start. Statemachine then checks timeout
    fn start(&mut self) -> Result<Option<TestState>, RunError>;
    /// Initialises test for tracing returns next state
    fn init(&mut self) -> Result<TestState, RunError>;
    /// Waits for notification from test executable that there's
    /// something to do. Selects the next appropriate state if there's
    /// something to do otherwise None
    fn wait(&mut self) -> Result<Option<TestState>, RunError>;
    /// Handle a stop in the test executable. Coverage data will
    /// be collected here as well as other OS specific functions
    fn stop(&mut self) -> Result<TestState, RunError>;
}

impl TestState {
    /// Convenience function used to check if the test has finished or errored
    pub fn is_finished(self) -> bool {
        match self {
            TestState::End(_) => true,
            _ => false,
        }
    }

    /// Convenience function for creating start states
    fn start_state() -> TestState {
        TestState::Start {
            start_time: Instant::now(),
        }
    }

    /// Convenience function for creating wait states
    fn wait_state() -> TestState {
        TestState::Waiting {
            start_time: Instant::now(),
        }
    }

    /// Updates the state machine state
    pub fn step<T: StateData>(self, data: &mut T, config: &Config) -> Result<TestState, RunError> {
        match self {
            TestState::Start { start_time } => {
                if let Some(s) = data.start()? {
                    Ok(s)
                } else if start_time.elapsed() >= config.test_timeout {
                    Err(RunError::TestRuntime(
                        "Error: Timed out when starting test".to_string(),
                    ))
                } else {
                    Ok(TestState::Start { start_time })
                }
            }
            TestState::Initialise => data.init(),
            TestState::Waiting { start_time } => {
                if let Some(s) = data.wait()? {
                    Ok(s)
                } else if start_time.elapsed() >= config.test_timeout {
                    Err(RunError::TestRuntime(
                        "Error: Timed out waiting for test response".to_string(),
                    ))
                } else {
                    Ok(TestState::Waiting { start_time })
                }
            }
            TestState::Stopped => data.stop(),
            _ => {
                // Unhandled
                if config.verbose {
                    println!("Tarpaulin error: unhandled test state");
                }
                Ok(TestState::End(-1))
            }
        }
    }
}

pub fn create_state_machine<'a>(
    test: Pid,
    traces: &'a mut TraceMap,
    config: &'a Config,
) -> (TestState, LinuxData<'a>) {
    let mut data = LinuxData::new(traces, config);
    data.parent = test;
    (TestState::start_state(), data)
}

/// Handle to linux process state
pub struct LinuxData<'a> {
    /// Recent result from waitpid to be handled by statemachine
    wait: WaitStatus,
    /// Current Pid to process
    current: Pid,
    /// Parent PID of test process
    parent: Pid,
    /// Map of addresses to breakpoints
    breakpoints: HashMap<u64, Breakpoint>,
    /// Instrumentation points in code with associated coverage data
    traces: &'a mut TraceMap,
    /// Program config
    config: &'a Config,
    /// Thread count. Hopefully getting rid of in future
    thread_count: isize,
    /// Used to show anomalies noticed so hit counts disabled
    force_disable_hit_count: bool,
}

impl<'a> StateData for LinuxData<'a> {
    fn start(&mut self) -> Result<Option<TestState>, RunError> {
        match waitpid(self.current, Some(WaitPidFlag::WNOHANG)) {
            Ok(WaitStatus::StillAlive) => Ok(None),
            Ok(sig @ WaitStatus::Stopped(_, Signal::SIGTRAP)) => {
                if let WaitStatus::Stopped(child, _) = sig {
                    self.current = child;
                }
                self.wait = sig;
                trace!("Caught inferior transitioning to Initialise state");
                Ok(Some(TestState::Initialise))
            }
            Ok(_) => Err(RunError::TestRuntime(
                "Unexpected signal when starting test".to_string(),
            )),
            Err(e) => Err(RunError::TestRuntime(format!(
                "Error when starting test: {}",
                e
            ))),
        }
    }

    fn init(&mut self) -> Result<TestState, RunError> {
        trace_children(self.current)?;
        for trace in self.traces.all_traces() {
            if let Some(addr) = trace.address {
                match Breakpoint::new(self.current, addr) {
                    Ok(bp) => {
                        let _ = self.breakpoints.insert(addr, bp);
                    }
                    Err(e) if e == NixErr::Sys(Errno::EIO) => {
                        return Err(RunError::TestRuntime(
                            "ERROR: Tarpaulin cannot find code addresses \
                             check that pie is disabled for your linker. \
                             If linking with gcc try adding -C link-args=-no-pie \
                             to your rust flags"
                                .to_string(),
                        ));
                    }
                    Err(NixErr::UnsupportedOperation) => {
                        debug!("Instrumentation address clash, ignoring 0x{:x}", addr);
                    }
                    Err(_) => {
                        return Err(RunError::TestRuntime(
                            "Failed to instrument test executable".to_string(),
                        ));
                    }
                }
            }
        }

        if continue_exec(self.parent, None).is_ok() {
            trace!("Initialised inferior, transitioning to wait state");
            Ok(TestState::wait_state())
        } else {
            Err(RunError::TestRuntime(
                "Test didn't launch correctly".to_string(),
            ))
        }
    }

    fn wait(&mut self) -> Result<Option<TestState>, RunError> {
        let wait = waitpid(
            Pid::from_raw(-1),
            Some(WaitPidFlag::WNOHANG | WaitPidFlag::__WALL),
        );
        match wait {
            Ok(WaitStatus::StillAlive) => {
                self.wait = WaitStatus::StillAlive;
                Ok(None)
            }
            Ok(s) => {
                self.wait = s;
                Ok(Some(TestState::Stopped))
            }
            Err(e) => Err(RunError::TestRuntime(format!(
                "An error occurred while waiting for response from test: {}",
                e
            ))),
        }
    }

    fn stop(&mut self) -> Result<TestState, RunError> {
        trace!("Caught signal {:?}", self.wait);
        match self.wait {
            WaitStatus::PtraceEvent(c, s, e) => match self.handle_ptrace_event(c, s, e) {
                Ok(s) => Ok(s),
                Err(e) => Err(RunError::TestRuntime(format!(
                    "Error occurred when handling ptrace event: {}",
                    e
                ))),
            },
            WaitStatus::Stopped(c, Signal::SIGTRAP) => {
                self.current = c;
                match self.collect_coverage_data() {
                    Ok(s) => Ok(s),
                    Err(e) => Err(RunError::TestRuntime(format!(
                        "Error when collecting coverage: {}",
                        e
                    ))),
                }
            }
            WaitStatus::Stopped(child, Signal::SIGSTOP) => {
                match continue_exec(child, None) {
                    Ok(_) => Ok(TestState::wait_state()),
                    Err(e) => Err(RunError::TestRuntime(format!(
                        "Error processing SIGSTOP: {}",
                        e.to_string()
                    ))),
                }
            },
            WaitStatus::Stopped(_, Signal::SIGSEGV) => Err(RunError::TestRuntime(
                "A segfault occurred while executing tests".to_string(),
            )),
            WaitStatus::Stopped(child, Signal::SIGILL) => {
                Err(RunError::TestRuntime(format!("Error running test - SIGILL raised in {}", child)))
            },
            WaitStatus::Stopped(c, s) => {
                let sig = if self.config.forward_signals {
                    Some(s)
                } else {
                    None
                };
                let _ = continue_exec(c, sig);
                Ok(TestState::wait_state())
            }
            WaitStatus::Signaled(_, _, _) => {
                if let Ok(s) = self.handle_signaled() {
                    Ok(s)
                } else {
                    Err(RunError::TestRuntime(
                        "Attempting to handle tarpaulin being signaled".to_string(),
                    ))
                }
            }
            WaitStatus::Exited(child, ec) => {
                for ref mut value in self.breakpoints.values_mut() {
                    value.thread_killed(child);
                }
                if child == self.parent {
                    Ok(TestState::End(ec))
                } else {
                    // Process may have already been destroyed. This is just incase
                    let _ = continue_exec(self.parent, None);
                    Ok(TestState::wait_state())
                }
            }
            _ => Err(RunError::TestRuntime(
                "An unexpected signal has been caught by tarpaulin!".to_string(),
            )),
        }
    }
}

impl<'a> LinuxData<'a> {
    pub fn new(traces: &'a mut TraceMap, config: &'a Config) -> LinuxData<'a> {
        LinuxData {
            wait: WaitStatus::StillAlive,
            current: Pid::from_raw(0),
            parent: Pid::from_raw(0),
            breakpoints: HashMap::new(),
            traces,
            config,
            thread_count: 0,
            force_disable_hit_count: config.count,
        }
    }

    fn handle_ptrace_event(
        &mut self,
        child: Pid,
        sig: Signal,
        event: i32,
    ) -> Result<TestState, RunError> {
        use nix::libc::*;

        if sig == Signal::SIGTRAP {
            match event {
                PTRACE_EVENT_CLONE => {
                    match get_event_data(child) {
                        Ok(t) => {
                            trace!("New thread spawned {}", t);
                            self.thread_count += 1;
                            continue_exec(child, None)?;
                            Ok(TestState::wait_state())
                        },
                        Err(e) => {
                            trace!("Error in clone event {:?}", e);
                            Err(RunError::TestRuntime(
                                "Error occurred upon test executable thread creation".to_string(),
                            ))
                        }
                    }
                }
                PTRACE_EVENT_FORK | PTRACE_EVENT_VFORK => {
                    trace!("Caught fork event");
                    continue_exec(child, None)?;
                    Ok(TestState::wait_state())
                }
                PTRACE_EVENT_EXEC => {
                    trace!("Child execed other process - detaching ptrace");
                    detach_child(child)?;
                    Ok(TestState::wait_state())
                }
                PTRACE_EVENT_EXIT => {
                    trace!("Child exiting");
                    self.thread_count -= 1;
                    continue_exec(child, None)?;
                    Ok(TestState::wait_state())
                }
                _ => Err(RunError::TestRuntime(format!(
                    "Unrecognised ptrace event {}",
                    event
                ))),
            }
        } else {
            trace!("Unexpected signal with ptrace event {}", event);
            trace!("Signal: {:?}", sig);
            Err(RunError::TestRuntime("Unexpected signal".to_string()))
        }
    }

    fn collect_coverage_data(&mut self) -> Result<TestState, RunError> {
        if let Ok(rip) = current_instruction_pointer(self.current) {
            let rip = (rip - 1) as u64;
            trace!("Hit address 0x{:x}", rip);
            if self.breakpoints.contains_key(&rip) {
                let bp = &mut self.breakpoints.get_mut(&rip).unwrap();
                let enable = self.config.count && self.thread_count < 2;
                if !enable && self.force_disable_hit_count {
                    warn!("Code is mulithreaded, disabling hit count");
                    warn!("Results may be improved by not using the '--count' option when running tarpaulin");
                    self.force_disable_hit_count = false;
                }
                // Don't reenable if multithreaded as can't yet sort out segfault issue
                let updated = if let Ok(x) = bp.process(self.current, enable) {
                    x
                } else {
                    // So failed to process a breakpoint.. Still continue to avoid
                    // stalling
                    continue_exec(self.current, None)?;
                    false
                };
                if updated {
                    if let Some(ref mut t) = self.traces.get_trace_mut(rip) {
                        if let CoverageStat::Line(ref mut x) = t.stats {
                            trace!("Incrementing hit count for trace");
                            *x += 1;
                        }
                    }
                }
            } else {
                continue_exec(self.current, None)?;
            }
        } else {
            continue_exec(self.current, None)?;
        }
        Ok(TestState::wait_state())
    }

    fn handle_signaled(&mut self) -> Result<TestState, RunError> {
        match self.wait {
            WaitStatus::Signaled(child, Signal::SIGTRAP, true) => {
                continue_exec(child, None)?;
                Ok(TestState::wait_state())
            }
            _ => Err(RunError::StateMachine("Unexpected stop".to_string())),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use std::os::unix::io::RawFd;
use nix::sys::socket;
use handle_table::{Handle};

macro_rules! try_syscall {
    ($expr:expr) => (
        {
            let result;
            loop {
                match $expr {
                    Ok(v) => {
                        result = v;
                        break;
                    }
                    Err(e) if e.errno() == ::nix::Errno::EINTR => continue,
                    Err(e) => return Err(::std::convert::From::from(e))
                }
            }
            result
        }
    )
}

#[cfg(target_os = "macos")]
pub mod kqueue;

#[cfg(target_os = "linux")]
pub mod epoll;

#[cfg(target_os = "macos")]
pub type Reactor = kqueue::Reactor;

#[cfg(target_os = "linux")]
pub type Reactor = epoll::Reactor;

pub struct FdObserver {
    read_fulfiller: Option<PromiseFulfiller<(), ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<(), ::std::io::Error>>,
}

impl FdObserver {
    pub fn when_becomes_readable(&mut self) -> Promise<(), ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_becomes_writable(&mut self) -> Promise<(), ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: socket::SockAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr) -> SocketAddressInner {
        SocketAddressInner {
            reactor: reactor,
            addr: socket::SockAddr::Inet(socket::InetAddr::from_std(&addr))
        }
    }

    pub fn new_unix<P: AsRef<::std::path::Path>>(reactor: Rc<RefCell<Reactor>>, addr: P)
                                                 -> Result<SocketAddressInner, ::std::io::Error>
    {
        // In what situations does this fail?
        Ok(SocketAddressInner {
            reactor: reactor,
            addr: ::nix::sys::socket::SockAddr::Unix(
                                   try!(::nix::sys::socket::UnixAddr::new(addr.as_ref())))

        })
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        let reactor = self.reactor.clone();
        let addr = self.addr;
        Promise::ok(()).then(move |()| {
            let reactor = reactor;
            let fd = pry!(::nix::sys::socket::socket(addr.family(), ::nix::sys::socket::SockType::Stream,
                                                     ::nix::sys::socket::SOCK_NONBLOCK, 0));
            loop {
                match ::nix::sys::socket::connect(fd, &addr) {
                    Ok(()) => break,
                    Err(e) if e.errno() == ::nix::Errno::EINTR => continue,
                    Err(e) if e.errno() == ::nix::Errno::EINPROGRESS => break,
                    Err(e) => return Promise::err(e.into()),
                }
            }

            let handle = pry!(reactor.borrow_mut().new_observer(fd));

            // TODO: if we're not already connected, maybe only register writable interest,
            // and then reregister with read/write interested once we successfully connect.

            let promise = reactor.borrow_mut().observers[handle].when_becomes_writable();
            promise.map(move |()| {

                let errno = try_syscall!(::nix::sys::socket::getsockopt(
                    fd,
                    ::nix::sys::socket::sockopt::SocketError));
                if errno != 0 {
                    Err(::std::io::Error::from_raw_os_error(errno))
                } else {
                    Ok(SocketStreamInner::new(reactor, handle, fd))
                }
            })
        })
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error>
    {
        let fd = try!(socket::socket(self.addr.family(), socket::SockType::Stream,
                                                 socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC,
                                                 0));

        try_syscall!(socket::setsockopt(fd, socket::sockopt::ReuseAddr, &true));
        try_syscall!(socket::bind(fd, &self.addr));
        try_syscall!(socket::listen(fd, 1024));

        let handle = try!(self.reactor.borrow_mut().new_observer(fd));
        Ok(SocketListenerInner::new(self.reactor.clone(), handle, fd))
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    handle: Handle,
    descriptor: RawFd,
    pub queue: Option<Promise<(),()>>,
}

impl Drop for SocketListenerInner {
    fn drop(&mut self) {
        let _ = ::nix::unistd::close(self.descriptor);
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<::sys::Reactor>>, handle: Handle, descriptor: RawFd)
           -> SocketListenerInner
    {
        SocketListenerInner {
            reactor: reactor,
            handle: handle,
            descriptor: descriptor,
            queue: None,
        }
    }

    pub fn local_addr(&self) -> Result<::std::net::SocketAddr, ::std::io::Error> {
        match try_syscall!(socket::getsockname(self.descriptor)) {
            socket::SockAddr::Inet(inet_addr) => Ok(inet_addr.to_std()),
            _ => Err(::std::io::Error::new(::std::io::ErrorKind::Other,
                                           "cannot take local_addr of a non-inet socket")),
        }
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                       -> Promise<SocketStreamInner, ::std::io::Error>
    {
        let fd = inner.borrow_mut().descriptor;
        loop {
            match ::nix::sys::socket::accept4(fd, socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC) {
                Ok(fd) => {
                    let reactor = inner.borrow().reactor.clone();
                    let handle = pry!(reactor.borrow_mut().new_observer(fd));
                    return Promise::ok(SocketStreamInner::new(reactor, handle, fd));
                }
                Err(e) => {
                    match e.errno() {
                        ::nix::Errno::EINTR => continue,
                        ::nix::Errno::EAGAIN => {
                            let handle = inner.borrow().handle;
                            let promise = {
                                let reactor = &inner.borrow().reactor;
                                let promise = // LOL borrow checker fail.
                                    reactor.borrow_mut().observers[handle].when_becomes_readable();
                                promise
                            };
                            return promise.then(|()| {
                                SocketListenerInner::accept_internal(inner)
                            });
                        }
                        _ => {
                            return Promise::err(e.into());
                        }
                    }
                }
            }
        }
    }

}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    handle: Handle,
    descriptor: RawFd,

    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl Drop for SocketStreamInner {
    fn drop(&mut self) {
        let _ = ::nix::unistd::close(self.descriptor);
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, handle: Handle, descriptor: RawFd) -> SocketStreamInner {
        SocketStreamInner {
                reactor: reactor,
                handle: handle,
                descriptor: descriptor,
                read_queue: None,
                write_queue: None,
        }
    }

    pub fn new_pair(reactor: Rc<RefCell<Reactor>>)
                    -> Result<(SocketStreamInner, SocketStreamInner), ::std::io::Error>
    {
        let (fd0, fd1) = try_syscall!(socket::socketpair(socket::AddressFamily::Unix,
                                                         socket::SockType::Stream,
                                                         0,
                                                         socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC));
        let handle0 = try!(reactor.borrow_mut().new_observer(fd0));
        let handle1 = try!(reactor.borrow_mut().new_observer(fd1));
        Ok((SocketStreamInner::new(reactor.clone(), handle0, fd0),
            SocketStreamInner::new(reactor, handle1, fd1)))
    }

    pub fn wrap_raw_socket_descriptor(reactor: Rc<RefCell<Reactor>>, fd: RawFd)
                    -> Result<SocketStreamInner, ::std::io::Error>
    {
        try_syscall!(::nix::fcntl::fcntl(fd, ::nix::fcntl::FcntlArg::F_SETFL(::nix::fcntl::O_NONBLOCK)));
        let handle = try!(reactor.borrow_mut().new_observer(fd));

        Ok(SocketStreamInner::new(reactor, handle, fd))
    }

    pub fn socket_spawn<F>(reactor: Rc<RefCell<Reactor>>, start_func: F)
                           -> Result<(::std::thread::JoinHandle<()>, SocketStreamInner), Box<::std::error::Error>>
        where F: FnOnce(::SocketStream, &::gj::WaitScope, ::EventPort) -> Result<(), Box<::std::error::Error>>,
              F: Send + 'static
    {
        use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};

        let (fd0, fd1) =
            try_syscall!(socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC));

        let handle0 = try!(reactor.borrow_mut().new_observer(fd0));

        let join_handle = ::std::thread::spawn(move || {
            let _result = ::gj::EventLoop::top_level(move |wait_scope| {
                let event_port = try!(::EventPort::new());
                let network = event_port.get_network();
                let socket_stream = try!(unsafe { network.wrap_raw_socket_descriptor(fd1) });
                start_func(socket_stream, &wait_scope, event_port)
            });
        });

        Ok((join_handle, SocketStreamInner::new(reactor, handle0, fd0)))
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                            mut buf: T,
                            mut already_read: usize,
                            min_bytes: usize)
                            -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        while already_read < min_bytes {
            let descriptor = inner.borrow().descriptor;
            match ::nix::unistd::read(descriptor, &mut buf.as_mut()[already_read..]) {
                Ok(0) => {
                    // EOF
                    return Promise::ok((buf, already_read));
                }
                Ok(n) => {
                    already_read += n;
                }
                Err(e) => {
                    match e.errno() {
                        ::nix::Errno::EINTR => continue,
                        ::nix::Errno::EAGAIN => {
                            let handle = inner.borrow().handle;
                            let promise = {
                                let reactor = &inner.borrow().reactor;
                                let promise = // LOL borrow checker fail.
                                    reactor.borrow_mut().observers[handle].when_becomes_readable();
                                promise
                            };

                            return promise.then_else(move |r| match r {
                                Ok(()) => SocketStreamInner::try_read_internal(inner, buf, already_read, min_bytes),
                                Err(e) => Promise::err(e)
                            });
                        }
                        _ => {
                            return Promise::err(e.into())
                        }
                    }
                }
            }
        }
        Promise::ok((buf, already_read))
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                         buf: T,
                         mut already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        while already_written < buf.as_ref().len() {
            let descriptor = inner.borrow().descriptor;
            match ::nix::unistd::write(descriptor, &buf.as_ref()[already_written..]) {
                Ok(n) => {
                    already_written += n;
                }
                Err(e) => {
                    match e.errno() {
                        ::nix::Errno::EINTR => continue,
                        ::nix::Errno::EAGAIN => {
                            let handle = inner.borrow().handle;
                            let promise = {
                                let reactor = &inner.borrow().reactor;
                                let promise = // LOL borrow checker fail.
                                    reactor.borrow_mut().observers[handle].when_becomes_writable();
                                promise
                            };
                            return promise.then_else(move |r| match r {
                                Ok(()) => SocketStreamInner::write_internal(inner, buf, already_written),
                                Err(e) => Promise::err(e),
                            })
                        }
                        _ => {
                            return Promise::err(e.into());
                        }
                    }
                }
            }
        }
        Promise::ok(buf)
    }
}

<commit_msg>Be more careful about preventing file descriptor leaks.<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use std::os::unix::io::RawFd;
use nix::sys::socket;
use handle_table::{Handle};

macro_rules! try_syscall {
    ($expr:expr) => (
        {
            let result;
            loop {
                match $expr {
                    Ok(v) => {
                        result = v;
                        break;
                    }
                    Err(e) if e.errno() == ::nix::Errno::EINTR => continue,
                    Err(e) => return Err(::std::convert::From::from(e))
                }
            }
            result
        }
    )
}

#[cfg(target_os = "macos")]
pub mod kqueue;

#[cfg(target_os = "linux")]
pub mod epoll;

#[cfg(target_os = "macos")]
pub type Reactor = kqueue::Reactor;

#[cfg(target_os = "linux")]
pub type Reactor = epoll::Reactor;

pub struct AutoCloseFd(RawFd);

impl Drop for AutoCloseFd {
    fn drop(&mut self) {
        let _ = ::nix::unistd::close(self.0);
    }
}

pub struct FdObserver {
    read_fulfiller: Option<PromiseFulfiller<(), ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<(), ::std::io::Error>>,
}

impl FdObserver {
    pub fn when_becomes_readable(&mut self) -> Promise<(), ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_becomes_writable(&mut self) -> Promise<(), ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: socket::SockAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr) -> SocketAddressInner {
        SocketAddressInner {
            reactor: reactor,
            addr: socket::SockAddr::Inet(socket::InetAddr::from_std(&addr))
        }
    }

    pub fn new_unix<P: AsRef<::std::path::Path>>(reactor: Rc<RefCell<Reactor>>, addr: P)
                                                 -> Result<SocketAddressInner, ::std::io::Error>
    {
        // In what situations does this fail?
        Ok(SocketAddressInner {
            reactor: reactor,
            addr: ::nix::sys::socket::SockAddr::Unix(
                                   try!(::nix::sys::socket::UnixAddr::new(addr.as_ref())))

        })
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        let reactor = self.reactor.clone();
        let addr = self.addr;
        Promise::ok(()).then(move |()| {
            let reactor = reactor;
            let fd = AutoCloseFd(pry!(::nix::sys::socket::socket(addr.family(),
                                                                 ::nix::sys::socket::SockType::Stream,
                                                                 ::nix::sys::socket::SOCK_NONBLOCK, 0)));
            loop {
                match ::nix::sys::socket::connect(fd.0, &addr) {
                    Ok(()) => break,
                    Err(e) if e.errno() == ::nix::Errno::EINTR => continue,
                    Err(e) if e.errno() == ::nix::Errno::EINPROGRESS => break,
                    Err(e) => return Promise::err(e.into()),
                }
            }

            let handle = pry!(reactor.borrow_mut().new_observer(fd.0));

            // TODO: if we're not already connected, maybe only register writable interest,
            // and then reregister with read/write interested once we successfully connect.

            let promise = reactor.borrow_mut().observers[handle].when_becomes_writable();
            promise.map(move |()| {

                let errno = try_syscall!(::nix::sys::socket::getsockopt(
                    fd.0,
                    ::nix::sys::socket::sockopt::SocketError));
                if errno != 0 {
                    Err(::std::io::Error::from_raw_os_error(errno))
                } else {
                    Ok(SocketStreamInner::new(reactor, handle, fd))
                }
            })
        })
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error>
    {
        let fd = AutoCloseFd(try!(socket::socket(self.addr.family(), socket::SockType::Stream,
                                                 socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC,
                                                 0)));

        try_syscall!(socket::setsockopt(fd.0, socket::sockopt::ReuseAddr, &true));
        try_syscall!(socket::bind(fd.0, &self.addr));
        try_syscall!(socket::listen(fd.0, 1024));

        let handle = try!(self.reactor.borrow_mut().new_observer(fd.0));
        Ok(SocketListenerInner::new(self.reactor.clone(), handle, fd))
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    handle: Handle,
    descriptor: AutoCloseFd,
    pub queue: Option<Promise<(),()>>,
}

impl Drop for SocketListenerInner {
    fn drop(&mut self) {
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<::sys::Reactor>>, handle: Handle, descriptor: AutoCloseFd)
           -> SocketListenerInner
    {
        SocketListenerInner {
            reactor: reactor,
            handle: handle,
            descriptor: descriptor,
            queue: None,
        }
    }

    pub fn local_addr(&self) -> Result<::std::net::SocketAddr, ::std::io::Error> {
        match try_syscall!(socket::getsockname(self.descriptor.0)) {
            socket::SockAddr::Inet(inet_addr) => Ok(inet_addr.to_std()),
            _ => Err(::std::io::Error::new(::std::io::ErrorKind::Other,
                                           "cannot take local_addr of a non-inet socket")),
        }
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                       -> Promise<SocketStreamInner, ::std::io::Error>
    {
        let fd = inner.borrow_mut().descriptor.0;
        loop {
            match ::nix::sys::socket::accept4(fd, socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC) {
                Ok(fd) => {
                    let new_fd = AutoCloseFd(fd);
                    let reactor = inner.borrow().reactor.clone();
                    let handle = pry!(reactor.borrow_mut().new_observer(new_fd.0));
                    return Promise::ok(SocketStreamInner::new(reactor, handle, new_fd));
                }
                Err(e) => {
                    match e.errno() {
                        ::nix::Errno::EINTR => continue,
                        ::nix::Errno::EAGAIN => {
                            let handle = inner.borrow().handle;
                            let promise = {
                                let reactor = &inner.borrow().reactor;
                                let promise = // LOL borrow checker fail.
                                    reactor.borrow_mut().observers[handle].when_becomes_readable();
                                promise
                            };
                            return promise.then(|()| {
                                SocketListenerInner::accept_internal(inner)
                            });
                        }
                        _ => {
                            return Promise::err(e.into());
                        }
                    }
                }
            }
        }
    }

}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    handle: Handle,
    descriptor: AutoCloseFd,

    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl Drop for SocketStreamInner {
    fn drop(&mut self) {
        self.reactor.borrow_mut().observers.remove(self.handle);
    }
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, handle: Handle, descriptor: AutoCloseFd) -> SocketStreamInner {
        SocketStreamInner {
                reactor: reactor,
                handle: handle,
                descriptor: descriptor,
                read_queue: None,
                write_queue: None,
        }
    }

    pub fn new_pair(reactor: Rc<RefCell<Reactor>>)
                    -> Result<(SocketStreamInner, SocketStreamInner), ::std::io::Error>
    {
        let (fd0, fd1) = try_syscall!(socket::socketpair(socket::AddressFamily::Unix,
                                                         socket::SockType::Stream,
                                                         0,
                                                         socket::SOCK_NONBLOCK | socket::SOCK_CLOEXEC));
        let (fd0, fd1) = (AutoCloseFd(fd0), AutoCloseFd(fd1));
        let handle0 = try!(reactor.borrow_mut().new_observer(fd0.0));
        let handle1 = try!(reactor.borrow_mut().new_observer(fd1.0));
        Ok((SocketStreamInner::new(reactor.clone(), handle0, fd0),
            SocketStreamInner::new(reactor, handle1, fd1)))
    }

    pub fn wrap_raw_socket_descriptor(reactor: Rc<RefCell<Reactor>>, fd: RawFd)
                    -> Result<SocketStreamInner, ::std::io::Error>
    {
        let fd = AutoCloseFd(fd);
        try_syscall!(::nix::fcntl::fcntl(fd.0, ::nix::fcntl::FcntlArg::F_SETFL(::nix::fcntl::O_NONBLOCK)));
        let handle = try!(reactor.borrow_mut().new_observer(fd.0));

        Ok(SocketStreamInner::new(reactor, handle, fd))
    }

    pub fn socket_spawn<F>(reactor: Rc<RefCell<Reactor>>, start_func: F)
                           -> Result<(::std::thread::JoinHandle<()>, SocketStreamInner), Box<::std::error::Error>>
        where F: FnOnce(::SocketStream, &::gj::WaitScope, ::EventPort) -> Result<(), Box<::std::error::Error>>,
              F: Send + 'static
    {
        use nix::sys::socket::{socketpair, AddressFamily, SockType, SOCK_CLOEXEC, SOCK_NONBLOCK};

        let (fd0, fd1) =
            try_syscall!(socketpair(AddressFamily::Unix, SockType::Stream, 0, SOCK_NONBLOCK | SOCK_CLOEXEC));
        let (fd0, fd1) = (AutoCloseFd(fd0), AutoCloseFd(fd1));

        let handle0 = try!(reactor.borrow_mut().new_observer(fd0.0));

        let join_handle = ::std::thread::spawn(move || {
            let _result = ::gj::EventLoop::top_level(move |wait_scope| {
                let event_port = try!(::EventPort::new());
                let network = event_port.get_network();
                let handle1 = try!(network.reactor.borrow_mut().new_observer(fd1.0));
                let socket_stream = ::SocketStream::new(SocketStreamInner::new(network.reactor.clone(),
                                                                               handle1, fd1));
                start_func(socket_stream, &wait_scope, event_port)
            });
        });

        Ok((join_handle, SocketStreamInner::new(reactor, handle0, fd0)))
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                            mut buf: T,
                            mut already_read: usize,
                            min_bytes: usize)
                            -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        while already_read < min_bytes {
            let descriptor = inner.borrow().descriptor.0;
            match ::nix::unistd::read(descriptor, &mut buf.as_mut()[already_read..]) {
                Ok(0) => {
                    // EOF
                    return Promise::ok((buf, already_read));
                }
                Ok(n) => {
                    already_read += n;
                }
                Err(e) => {
                    match e.errno() {
                        ::nix::Errno::EINTR => continue,
                        ::nix::Errno::EAGAIN => {
                            let handle = inner.borrow().handle;
                            let promise = {
                                let reactor = &inner.borrow().reactor;
                                let promise = // LOL borrow checker fail.
                                    reactor.borrow_mut().observers[handle].when_becomes_readable();
                                promise
                            };

                            return promise.then_else(move |r| match r {
                                Ok(()) => SocketStreamInner::try_read_internal(inner, buf, already_read, min_bytes),
                                Err(e) => Promise::err(e)
                            });
                        }
                        _ => {
                            return Promise::err(e.into())
                        }
                    }
                }
            }
        }
        Promise::ok((buf, already_read))
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                         buf: T,
                         mut already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        while already_written < buf.as_ref().len() {
            let descriptor = inner.borrow().descriptor.0;
            match ::nix::unistd::write(descriptor, &buf.as_ref()[already_written..]) {
                Ok(n) => {
                    already_written += n;
                }
                Err(e) => {
                    match e.errno() {
                        ::nix::Errno::EINTR => continue,
                        ::nix::Errno::EAGAIN => {
                            let handle = inner.borrow().handle;
                            let promise = {
                                let reactor = &inner.borrow().reactor;
                                let promise = // LOL borrow checker fail.
                                    reactor.borrow_mut().observers[handle].when_becomes_writable();
                                promise
                            };
                            return promise.then_else(move |r| match r {
                                Ok(()) => SocketStreamInner::write_internal(inner, buf, already_written),
                                Err(e) => Promise::err(e),
                            })
                        }
                        _ => {
                            return Promise::err(e.into());
                        }
                    }
                }
            }
        }
        Promise::ok(buf)
    }
}

<|endoftext|>


<commit_before>mod event;
mod input;
use std::mem;
use std::fs::{File, OpenOptions};
use std::io::{self, Write, Read};
use std::os::unix::io::AsRawFd;
use libc::{TCSANOW, TIOCGWINSZ, termios, winsize, c_int, c_ulong};

pub use self::input::*;
pub use self::event::*;

extern {
    fn tcgetattr(filedes: c_int, termptr: *mut termios) -> c_int;
    fn tcsetattr(filedes: c_int, opt: c_int, termptr: *const termios) -> c_int;
    fn cfmakeraw(termptr: *mut termios);
    fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
}

#[derive(Debug)]
pub enum Error {
    TcGetAttr,
    TcSetAttr
}

pub struct Terminal {
    file: File,
    prev_termios: Option<termios>,
    pub max_width: usize,
    pub max_height: usize
}

impl Terminal {
    /// Creates a new Terminal from the provided filename
    pub fn from(filename: &str) -> io::Result<Terminal> {
        let file = OpenOptions::new().write(true).read(true).open(filename)?;
        let fd = file.as_raw_fd();

        let mut terminal = Terminal {
            file: file,
            prev_termios: None,
            max_width: 80,
            max_height: 25
        };

        unsafe {
            let mut ws: winsize = mem::zeroed();
            if ioctl(fd, TIOCGWINSZ, &mut ws) != -1 {
                terminal.max_width = ws.ws_col as usize;
                terminal.max_height = ws.ws_row as usize;
            }
        }

        Ok(terminal)
    }

    pub fn set_raw_mode(&mut self) -> Result<(), Error> {
        let fd = self.file.as_raw_fd();

        unsafe {
            let mut ios: termios = mem::zeroed();

            // get the existing termios
            let result = tcgetattr(fd, &mut ios);
            if result != 0 {
                return Err(Error::TcGetAttr);
            }

            self.prev_termios = Some(ios);

            // enable raw mode
            cfmakeraw(&mut ios);

            // apply the raw mode termios
            let result = tcsetattr(fd, TCSANOW, &ios);
            if result != 0 {
                return Err(Error::TcSetAttr);
            }
        }

        Ok(())
    }

    pub fn reset(&mut self) -> Result<(), Error> {
        if let Some(opts) = self.prev_termios {
            let fd = self.file.as_raw_fd();

            // disable raw mode, by setting the original termios
            unsafe {
                let result = tcsetattr(fd, TCSANOW, &opts);
                if result != 0 {
                    return Err(Error::TcSetAttr);
                }
            }
        }

        Ok(())
    }

    pub fn events(&self) -> io::Result<Events<File>> {
        self.file.try_clone().map(Events::new)
    }
}

impl Read for Terminal {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.file.read(buf)
    }
}

impl Write for Terminal {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.file.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

impl Drop for Terminal {
    fn drop(&mut self) {
        self.reset().unwrap();
    }
}

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

    #[test]
    fn terminal() {
        let mut term = Terminal::from("/dev/tty").expect("Unable to open /dev/tty");

        // if all is good, this should _not_ break the terminal, because the
        // Drop trait impl will clean up
        term.set_raw_mode().expect("Unable to enable raw mode");

        write!(term, "").unwrap();
        term.flush().unwrap();
    }
}
<commit_msg>Remove unnecessary temporary variables<commit_after>mod event;
mod input;
use std::mem;
use std::fs::{File, OpenOptions};
use std::io::{self, Write, Read};
use std::os::unix::io::AsRawFd;
use libc::{TCSANOW, TIOCGWINSZ, termios, winsize, c_int, c_ulong};

pub use self::input::*;
pub use self::event::*;

extern {
    fn tcgetattr(filedes: c_int, termptr: *mut termios) -> c_int;
    fn tcsetattr(filedes: c_int, opt: c_int, termptr: *const termios) -> c_int;
    fn cfmakeraw(termptr: *mut termios);
    fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
}

#[derive(Debug)]
pub enum Error {
    TcGetAttr,
    TcSetAttr
}

pub struct Terminal {
    file: File,
    prev_termios: Option<termios>,
    pub max_width: usize,
    pub max_height: usize
}

impl Terminal {
    /// Creates a new Terminal from the provided filename
    pub fn from(filename: &str) -> io::Result<Terminal> {
        let file = OpenOptions::new().write(true).read(true).open(filename)?;
        let fd = file.as_raw_fd();

        let mut terminal = Terminal {
            file: file,
            prev_termios: None,
            max_width: 80,
            max_height: 25
        };

        unsafe {
            let mut ws: winsize = mem::zeroed();
            if ioctl(fd, TIOCGWINSZ, &mut ws) != -1 {
                terminal.max_width = ws.ws_col as usize;
                terminal.max_height = ws.ws_row as usize;
            }
        }

        Ok(terminal)
    }

    pub fn set_raw_mode(&mut self) -> Result<(), Error> {
        let fd = self.file.as_raw_fd();

        unsafe {
            let mut ios: termios = mem::zeroed();

            // get the existing termios
            if tcgetattr(fd, &mut ios) != 0 {
                return Err(Error::TcGetAttr);
            }

            self.prev_termios = Some(ios);

            // enable raw mode
            cfmakeraw(&mut ios);

            // apply the raw mode termios
            if tcsetattr(fd, TCSANOW, &ios) != 0 {
                return Err(Error::TcSetAttr);
            }
        }

        Ok(())
    }

    pub fn reset(&mut self) -> Result<(), Error> {
        if let Some(opts) = self.prev_termios {
            let fd = self.file.as_raw_fd();

            // disable raw mode, by setting the original termios
            unsafe {
                if tcsetattr(fd, TCSANOW, &opts) != 0 {
                    return Err(Error::TcSetAttr);
                }
            }
        }

        Ok(())
    }

    pub fn events(&self) -> io::Result<Events<File>> {
        self.file.try_clone().map(Events::new)
    }
}

impl Read for Terminal {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.file.read(buf)
    }
}

impl Write for Terminal {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.file.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.file.flush()
    }
}

impl Drop for Terminal {
    fn drop(&mut self) {
        self.reset().unwrap();
    }
}

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

    #[test]
    fn terminal() {
        let mut term = Terminal::from("/dev/tty").expect("Unable to open /dev/tty");

        // if all is good, this should _not_ break the terminal, because the
        // Drop trait impl will clean up
        term.set_raw_mode().expect("Unable to enable raw mode");

        write!(term, "").unwrap();
        term.flush().unwrap();
    }
}
<|endoftext|>