<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A very simple bit-vector that serves the needs of `primal`.

use std::cmp;
use std::fmt;
use std::hash;
use std::iter::repeat;
use std::ops::Index;

const BITS: usize = 32;

static TRUE: bool = true;
static FALSE: bool = false;

/// The bitvector type.
pub struct BitVec {
    /// Internal representation of the bit vector
    storage: Vec<u32>,
    /// The number of valid bits in the internal representation
    nbits: usize
}

impl Index<usize> for BitVec {
    type Output = bool;

    #[inline]
    fn index(&self, i: usize) -> &bool {
        if self.get(i).expect("index out of bounds") {
            &TRUE
        } else {
            &FALSE
        }
    }
}

impl BitVec {
    /// An operation might screw up the unused bits in the last block of the
    /// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up.
    fn fix_last_block(&mut self) {
        let extra_bits = self.len() % BITS;
        if extra_bits > 0 {
            let mask = (1 << extra_bits) - 1;
            let storage_len = self.storage.len();
            self.storage[storage_len - 1] &= mask;
        }
    }

    /// Creates an empty `BitVec`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    /// let mut bv = BitVec::new();
    /// ```
    pub fn new() -> BitVec {
        BitVec { storage: Vec::new(), nbits: 0 }
    }

    #[inline]
    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
        unsafe {
            std::slice::from_raw_parts_mut(self.storage.as_mut_ptr() as *mut _,
                                           (self.nbits + 7) / 8)
        }
    }
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts(self.storage.as_ptr() as *const _,
                                       (self.nbits + 7) / 8)
        }
    }

    /// Creates a `BitVec` that holds `nbits` elements, setting each element
    /// to `bit`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let mut bv = BitVec::from_elem(10, false);
    /// assert_eq!(bv.len(), 10);
    /// for x in bv.iter() {
    ///     assert_eq!(x, false);
    /// }
    /// ```
    pub fn from_elem(nbits: usize, bit: bool) -> BitVec {
        let nblocks = nbits.checked_add(BITS - 1).expect("capacity overflow") / BITS;
        let mut bit_vec = BitVec {
            storage: repeat(if bit { !0 } else { 0 }).take(nblocks).collect(),
            nbits: nbits
        };
        bit_vec.fix_last_block();
        bit_vec
    }

    /// Retrieves the value at index `i`, or `None` if the index is out of bounds.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let bv = BitVec::from_bytes(&[0b01100000]);
    /// assert_eq!(bv.get(0), Some(false));
    /// assert_eq!(bv.get(1), Some(true));
    /// assert_eq!(bv.get(100), None);
    ///
    /// // Can also use array indexing
    /// assert_eq!(bv[1], true);
    /// ```
    #[inline]
    pub fn get(&self, i: usize) -> Option<bool> {
        if i >= self.nbits {
            return None;
        }
        let w = i / BITS;
        let b = i % BITS;
        self.storage.get(w).map(|&block|
            (block & (1 << b)) != 0
        )
    }

    /// Sets the value of a bit at an index `i`.
    ///
    /// # Panics
    ///
    /// Panics if `i` is out of bounds.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let mut bv = BitVec::from_elem(5, false);
    /// bv.set(3, true);
    /// assert_eq!(bv[3], true);
    /// ```
    #[inline]
    pub fn set(&mut self, i: usize, x: bool) {
        assert!(i < self.nbits);
        unsafe {
            self.set_unchecked(i, x)
        }
    }

    #[inline]
    pub unsafe fn set_unchecked(&mut self, i: usize, x: bool) {
        //
        let w = i / BITS;
        let b = i % BITS;
        let flag = 1 << b;
        let ptr = self.storage.get_unchecked_mut(w);
        let val = if x { *ptr | flag } else { *ptr & !flag };
        *ptr = val;
    }

    /// Sets all bits to 1.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let before = 0b01100000;
    /// let after  = 0b11111111;
    ///
    /// let mut bv = BitVec::from_bytes(&[before]);
    /// bv.set_all();
    /// assert_eq!(bv, BitVec::from_bytes(&[after]));
    /// ```
    #[inline]
    pub fn set_all(&mut self) {
        for w in &mut self.storage { *w = !0; }
        self.fix_last_block();
    }

    /// Returns an iterator over the elements of the vector in order.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]);
    /// assert_eq!(bv.iter().filter(|x| *x).count(), 7);
    /// ```
    #[inline]
    pub fn iter(&self) -> Iter {
        Iter { bit_vec: self, next_idx: 0, end_idx: self.nbits }
    }

    /// Returns the total number of bits in this vector
    #[inline]
    pub fn len(&self) -> usize { self.nbits }

    /// Returns true if there are no bits in this vector
    #[inline]
    pub fn is_empty(&self) -> bool { self.len() == 0 }

    /// Clears all bits in this vector.
    #[inline]
    pub fn clear(&mut self) {
        for w in &mut self.storage { *w = 0; }
    }
}

impl Default for BitVec {
    #[inline]
    fn default() -> BitVec { BitVec::new() }
}
impl Clone for BitVec {
    #[inline]
    fn clone(&self) -> BitVec {
        BitVec { storage: self.storage.clone(), nbits: self.nbits }
    }

    #[inline]
    fn clone_from(&mut self, source: &BitVec) {
        self.nbits = source.nbits;
        self.storage.clone_from(&source.storage);
    }
}

impl fmt::Debug for BitVec {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        for bit in self {
            try!(write!(fmt, "{}", if bit { 1 } else { 0 }));
        }
        Ok(())
    }
}

impl hash::Hash for BitVec {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.nbits.hash(state);
        for elem in self.storage.iter().cloned() {
            elem.hash(state);
        }
    }
}

impl cmp::PartialEq for BitVec {
    #[inline]
    fn eq(&self, other: &BitVec) -> bool {
        if self.nbits != other.nbits {
            return false;
        }
        self.storage.iter().cloned().zip(other.storage.iter().cloned()).all(|(w1, w2)| w1 == w2)
    }
}

impl cmp::Eq for BitVec {}

/// An iterator for `BitVec`.
#[derive(Clone)]
pub struct Iter<'a> {
    bit_vec: &'a BitVec,
    next_idx: usize,
    end_idx: usize,
}

impl<'a> Iterator for Iter<'a> {
    type Item = bool;

    #[inline]
    fn next(&mut self) -> Option<bool> {
        if self.next_idx != self.end_idx {
            let idx = self.next_idx;
            self.next_idx += 1;
            Some(self.bit_vec[idx])
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let rem = self.end_idx - self.next_idx;
        (rem, Some(rem))
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<bool> {
        if self.next_idx != self.end_idx {
            self.end_idx -= 1;
            Some(self.bit_vec[self.end_idx])
        } else {
            None
        }
    }
}

impl<'a> ExactSizeIterator for Iter<'a> {}

impl<'a> IntoIterator for &'a BitVec {
    type Item = bool;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}
<commit_msg>bit: switch to u64 internals.<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A very simple bit-vector that serves the needs of `primal`.

use std::cmp;
use std::fmt;
use std::hash;
use std::iter::repeat;
use std::ops::Index;

const BITS: usize = 64;

static TRUE: bool = true;
static FALSE: bool = false;

/// The bitvector type.
pub struct BitVec {
    /// Internal representation of the bit vector
    storage: Vec<u64>,
    /// The number of valid bits in the internal representation
    nbits: usize
}

impl Index<usize> for BitVec {
    type Output = bool;

    #[inline]
    fn index(&self, i: usize) -> &bool {
        if self.get(i).expect("index out of bounds") {
            &TRUE
        } else {
            &FALSE
        }
    }
}

impl BitVec {
    /// An operation might screw up the unused bits in the last block of the
    /// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up.
    fn fix_last_block(&mut self) {
        let extra_bits = self.len() % BITS;
        if extra_bits > 0 {
            let mask = (1 << extra_bits) - 1;
            let storage_len = self.storage.len();
            self.storage[storage_len - 1] &= mask;
        }
    }

    /// Creates an empty `BitVec`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    /// let mut bv = BitVec::new();
    /// ```
    pub fn new() -> BitVec {
        BitVec { storage: Vec::new(), nbits: 0 }
    }

    #[inline]
    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
        unsafe {
            std::slice::from_raw_parts_mut(self.storage.as_mut_ptr() as *mut _,
                                           (self.nbits + 7) / 8)
        }
    }
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts(self.storage.as_ptr() as *const _,
                                       (self.nbits + 7) / 8)
        }
    }

    /// Creates a `BitVec` that holds `nbits` elements, setting each element
    /// to `bit`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let mut bv = BitVec::from_elem(10, false);
    /// assert_eq!(bv.len(), 10);
    /// for x in bv.iter() {
    ///     assert_eq!(x, false);
    /// }
    /// ```
    pub fn from_elem(nbits: usize, bit: bool) -> BitVec {
        let nblocks = nbits.checked_add(BITS - 1).expect("capacity overflow") / BITS;
        let mut bit_vec = BitVec {
            storage: repeat(if bit { !0 } else { 0 }).take(nblocks).collect(),
            nbits: nbits
        };
        bit_vec.fix_last_block();
        bit_vec
    }

    /// Retrieves the value at index `i`, or `None` if the index is out of bounds.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let bv = BitVec::from_bytes(&[0b01100000]);
    /// assert_eq!(bv.get(0), Some(false));
    /// assert_eq!(bv.get(1), Some(true));
    /// assert_eq!(bv.get(100), None);
    ///
    /// // Can also use array indexing
    /// assert_eq!(bv[1], true);
    /// ```
    #[inline]
    pub fn get(&self, i: usize) -> Option<bool> {
        if i >= self.nbits {
            return None;
        }
        let w = i / BITS;
        let b = i % BITS;
        self.storage.get(w).map(|&block|
            (block & (1 << b)) != 0
        )
    }

    /// Sets the value of a bit at an index `i`.
    ///
    /// # Panics
    ///
    /// Panics if `i` is out of bounds.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let mut bv = BitVec::from_elem(5, false);
    /// bv.set(3, true);
    /// assert_eq!(bv[3], true);
    /// ```
    #[inline]
    pub fn set(&mut self, i: usize, x: bool) {
        assert!(i < self.nbits);
        unsafe {
            self.set_unchecked(i, x)
        }
    }

    #[inline]
    pub unsafe fn set_unchecked(&mut self, i: usize, x: bool) {
        //
        let w = i / BITS;
        let b = i % BITS;
        let flag = 1 << b;
        let ptr = self.storage.get_unchecked_mut(w);
        let val = if x { *ptr | flag } else { *ptr & !flag };
        *ptr = val;
    }

    /// Sets all bits to 1.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let before = 0b01100000;
    /// let after  = 0b11111111;
    ///
    /// let mut bv = BitVec::from_bytes(&[before]);
    /// bv.set_all();
    /// assert_eq!(bv, BitVec::from_bytes(&[after]));
    /// ```
    #[inline]
    pub fn set_all(&mut self) {
        for w in &mut self.storage { *w = !0; }
        self.fix_last_block();
    }

    /// Returns an iterator over the elements of the vector in order.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]);
    /// assert_eq!(bv.iter().filter(|x| *x).count(), 7);
    /// ```
    #[inline]
    pub fn iter(&self) -> Iter {
        Iter { bit_vec: self, next_idx: 0, end_idx: self.nbits }
    }

    /// Returns the total number of bits in this vector
    #[inline]
    pub fn len(&self) -> usize { self.nbits }

    /// Returns true if there are no bits in this vector
    #[inline]
    pub fn is_empty(&self) -> bool { self.len() == 0 }

    /// Clears all bits in this vector.
    #[inline]
    pub fn clear(&mut self) {
        for w in &mut self.storage { *w = 0; }
    }
}

impl Default for BitVec {
    #[inline]
    fn default() -> BitVec { BitVec::new() }
}
impl Clone for BitVec {
    #[inline]
    fn clone(&self) -> BitVec {
        BitVec { storage: self.storage.clone(), nbits: self.nbits }
    }

    #[inline]
    fn clone_from(&mut self, source: &BitVec) {
        self.nbits = source.nbits;
        self.storage.clone_from(&source.storage);
    }
}

impl fmt::Debug for BitVec {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        for bit in self {
            try!(write!(fmt, "{}", if bit { 1 } else { 0 }));
        }
        Ok(())
    }
}

impl hash::Hash for BitVec {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.nbits.hash(state);
        for elem in self.storage.iter().cloned() {
            elem.hash(state);
        }
    }
}

impl cmp::PartialEq for BitVec {
    #[inline]
    fn eq(&self, other: &BitVec) -> bool {
        if self.nbits != other.nbits {
            return false;
        }
        self.storage.iter().cloned().zip(other.storage.iter().cloned()).all(|(w1, w2)| w1 == w2)
    }
}

impl cmp::Eq for BitVec {}

/// An iterator for `BitVec`.
#[derive(Clone)]
pub struct Iter<'a> {
    bit_vec: &'a BitVec,
    next_idx: usize,
    end_idx: usize,
}

impl<'a> Iterator for Iter<'a> {
    type Item = bool;

    #[inline]
    fn next(&mut self) -> Option<bool> {
        if self.next_idx != self.end_idx {
            let idx = self.next_idx;
            self.next_idx += 1;
            Some(self.bit_vec[idx])
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let rem = self.end_idx - self.next_idx;
        (rem, Some(rem))
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<bool> {
        if self.next_idx != self.end_idx {
            self.end_idx -= 1;
            Some(self.bit_vec[self.end_idx])
        } else {
            None
        }
    }
}

impl<'a> ExactSizeIterator for Iter<'a> {}

impl<'a> IntoIterator for &'a BitVec {
    type Item = bool;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

fn gurobi_home() -> String {
  let gurobi_home = env::var("GUROBI_HOME").unwrap();
  assert!(Path::new(gurobi_home.as_str()).exists());
  gurobi_home
}

fn append_path(addpath: &str) {
  if let Some(path) = env::var_os("PATH") {
    let mut paths = env::split_paths(&path).collect::<Vec<_>>();
    paths.push(PathBuf::from(addpath));
    let new_path = env::join_paths(paths).unwrap();
    env::set_var("PATH", &new_path);
  }
}

fn get_version_triple() -> (i32, i32, i32) {
  let mut binpath = PathBuf::from(gurobi_home());
  binpath.push("bin");
  append_path(binpath.to_str().unwrap());

  let output = Command::new("gurobi_cl").arg("--version").output().expect("failed to execute gurobi_cl");
  let verno: Vec<_> = String::from_utf8(output.stdout)
    .unwrap()
    .split_whitespace()
    .nth(3)
    .unwrap()
    .split(".")
    .map(|s| s.parse().unwrap())
    .collect();

  (verno[0], verno[1], verno[2])
}

fn main() {
  let mut libpath: PathBuf = PathBuf::from(gurobi_home());
  libpath.push("lib");
  let libpath = libpath.to_str().unwrap();

  let (major, minor, _) = get_version_triple();
  let libname = format!("gurobi{}{}", major, minor);

  println!("cargo:rustc-link-search=native={}", libpath);
  println!("cargo:rustc-link-lib={}", libname);
}
<commit_msg>gurobi_sys: avoid to print linker options if GUROBI_HOME does not exist<commit_after>use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::io::{self, Error, ErrorKind};

fn gurobi_home() -> io::Result<String> {
  env::var("GUROBI_HOME")
    .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
    .and_then(|p| if Path::new(p.as_str()).exists() {
      Ok(p)
    } else {
      Err(Error::new(ErrorKind::Other, "".to_owned()))
    })
}

fn append_path(addpath: &str) {
  if let Some(path) = env::var_os("PATH") {
    let mut paths = env::split_paths(&path).collect::<Vec<_>>();
    paths.push(PathBuf::from(addpath));
    let new_path = env::join_paths(paths).unwrap();
    env::set_var("PATH", &new_path);
  }
}

fn get_version_triple() -> (i32, i32, i32) {
  let mut binpath = PathBuf::from(gurobi_home().unwrap());
  binpath.push("bin");
  append_path(binpath.to_str().unwrap());

  let output = Command::new("gurobi_cl").arg("--version").output().expect("failed to execute gurobi_cl");
  let verno: Vec<_> = String::from_utf8(output.stdout)
    .unwrap()
    .split_whitespace()
    .nth(3)
    .unwrap()
    .split(".")
    .map(|s| s.parse().unwrap())
    .collect();

  (verno[0], verno[1], verno[2])
}

fn main() {
  if let Ok(gurobi_home) = gurobi_home() {
    let mut libpath: PathBuf = PathBuf::from(gurobi_home);
    libpath.push("lib");
    let libpath = libpath.to_str().unwrap();

    let (major, minor, _) = get_version_triple();
    let libname = format!("gurobi{}{}", major, minor);

    println!("cargo:rustc-link-search=native={}", libpath);
    println!("cargo:rustc-link-lib={}", libname);
  }
}
<|endoftext|>


<commit_before>//!
//! Implementation of the [`Session`](::backend::session::Session) trait through the libseat.
//!
//! This requires libseat to be available on the system.

use libseat::{Seat, SeatEvent};
use std::{
    cell::RefCell,
    collections::HashMap,
    os::unix::io::RawFd,
    path::Path,
    rc::{Rc, Weak},
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use nix::{errno::Errno, fcntl::OFlag, unistd::close};

use calloop::{EventSource, Poll, PostAction, Readiness, Token, TokenFactory};

use crate::{
    backend::session::{AsErrno, Session, Signal as SessionSignal},
    utils::signaling::Signaler,
};

use slog::{debug, error, o};

#[derive(Debug)]
struct LibSeatSessionImpl {
    seat: RefCell<Seat>,
    active: Arc<AtomicBool>,
    devices: RefCell<HashMap<RawFd, i32>>,
    logger: ::slog::Logger,
}

impl Drop for LibSeatSessionImpl {
    fn drop(&mut self) {
        debug!(self.logger, "Closing seat")
    }
}

/// [`Session`] via the libseat
#[derive(Debug, Clone)]
pub struct LibSeatSession {
    internal: Weak<LibSeatSessionImpl>,
    seat_name: String,
}

/// [`SessionNotifier`] via the libseat
#[derive(Debug)]
pub struct LibSeatSessionNotifier {
    internal: Rc<LibSeatSessionImpl>,
    signaler: Signaler<SessionSignal>,
    token: Token,
}

impl LibSeatSession {
    /// Tries to create a new session via libseat.
    pub fn new<L>(logger: L) -> Result<(LibSeatSession, LibSeatSessionNotifier), Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let logger = crate::slog_or_fallback(logger)
            .new(o!("smithay_module" => "backend_session", "session_type" => "libseat"));

        let active = Arc::new(AtomicBool::new(false));
        let signaler = Signaler::new();

        let seat = {
            let log = logger.clone();
            let active = active.clone();
            let signaler = signaler.clone();

            Seat::open(
                move |seat, event| match event {
                    SeatEvent::Enable => {
                        debug!(log, "Enable callback called");
                        active.store(true, Ordering::SeqCst);
                        signaler.signal(SessionSignal::ActivateSession);
                    }
                    SeatEvent::Disable => {
                        debug!(log, "Disable callback called");
                        active.store(false, Ordering::SeqCst);
                        signaler.signal(SessionSignal::PauseSession);
                        seat.disable().unwrap();
                    }
                },
                logger.clone(),
            )
        };

        seat.map(|mut seat| {
            // In some cases enable_seat event is avalible right after startup
            // so, we can dispatch it
            seat.dispatch(0).unwrap();

            let seat_name = seat.name().to_owned();

            let internal = Rc::new(LibSeatSessionImpl {
                seat: RefCell::new(seat),
                active,
                devices: RefCell::new(HashMap::new()),
                logger,
            });

            (
                LibSeatSession {
                    internal: Rc::downgrade(&internal),
                    seat_name,
                },
                LibSeatSessionNotifier {
                    internal,
                    signaler,
                    token: Token::invalid(),
                },
            )
        })
        .map_err(|err| Error::FailedToOpenSession(Errno::from_i32(err.into())))
    }
}

impl Session for LibSeatSession {
    type Error = Error;

    fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd, Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Opening device: {:?}", path);

            session
                .seat
                .borrow_mut()
                .open_device(&path)
                .map(|(id, fd)| {
                    session.devices.borrow_mut().insert(fd, id);
                    fd
                })
                .map_err(|err| Error::FailedToOpenDevice(Errno::from_i32(err.into())))
        } else {
            Err(Error::SessionLost)
        }
    }

    fn close(&mut self, fd: RawFd) -> Result<(), Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Closing device: {:?}", fd);

            let dev = session.devices.borrow().get(&fd).map(|fd| *fd);

            let out = if let Some(dev) = dev {
                session
                    .seat
                    .borrow_mut()
                    .close_device(dev)
                    .map_err(|err| Error::FailedToCloseDevice(Errno::from_i32(err.into())))
            } else {
                Ok(())
            };

            close(fd).unwrap();

            out
        } else {
            Err(Error::SessionLost)
        }
    }

    fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Session switch: {:?}", vt);
            session
                .seat
                .borrow_mut()
                .switch_session(vt)
                .map_err(|err| Error::FailedToChangeVt(Errno::from_i32(err.into())))
        } else {
            Err(Error::SessionLost)
        }
    }

    fn is_active(&self) -> bool {
        if let Some(internal) = self.internal.upgrade() {
            internal.active.load(Ordering::SeqCst)
        } else {
            false
        }
    }

    fn seat(&self) -> String {
        self.seat_name.clone()
    }
}

impl LibSeatSessionNotifier {
    /// Creates a new session object belonging to this notifier.
    pub fn session(&self) -> LibSeatSession {
        LibSeatSession {
            internal: Rc::downgrade(&self.internal),
            seat_name: self.internal.seat.borrow_mut().name().to_owned(),
        }
    }

    /// Get a handle to the Signaler of this session.
    ///
    /// You can use it to listen for signals generated by the session.
    pub fn signaler(&self) -> Signaler<SessionSignal> {
        self.signaler.clone()
    }
}

impl EventSource for LibSeatSessionNotifier {
    type Event = ();
    type Metadata = ();
    type Ret = ();

    fn process_events<F>(&mut self, _readiness: Readiness, token: Token, _: F) -> std::io::Result<PostAction>
    where
        F: FnMut((), &mut ()),
    {
        if token == self.token {
            self.internal.seat.borrow_mut().dispatch(0).unwrap();
        }
        Ok(PostAction::Continue)
    }

    fn register(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> std::io::Result<()> {
        self.token = factory.token();
        poll.register(
            self.internal.seat.borrow_mut().get_fd().unwrap(),
            calloop::Interest::READ,
            calloop::Mode::Level,
            self.token,
        )
        .unwrap();
        Ok(())
    }

    fn reregister(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> std::io::Result<()> {
        self.token = factory.token();
        poll.reregister(
            self.internal.seat.borrow_mut().get_fd().unwrap(),
            calloop::Interest::READ,
            calloop::Mode::Level,
            self.token,
        )
        .unwrap();
        Ok(())
    }

    fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {
        self.token = Token::invalid();
        poll.unregister(self.internal.seat.borrow_mut().get_fd().unwrap())
            .unwrap();
        Ok(())
    }
}

/// Errors related to direct/tty sessions
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// Failed to open session
    #[error("Failed to open session: {0}")]
    FailedToOpenSession(Errno),

    /// Failed to open device
    #[error("Failed to open device: {0}")]
    FailedToOpenDevice(Errno),

    /// Failed to close device
    #[error("Failed to close device: {0}")]
    FailedToCloseDevice(Errno),

    /// Failed to close device
    #[error("Failed to change vt: {0}")]
    FailedToChangeVt(Errno),

    /// Session is already closed,
    #[error("Session is already closed")]
    SessionLost,
}

impl AsErrno for Error {
    fn as_errno(&self) -> Option<i32> {
        match self {
            &Self::FailedToOpenSession(errno)
            | &Self::FailedToOpenDevice(errno)
            | &Self::FailedToCloseDevice(errno)
            | &Self::FailedToChangeVt(errno) => Some(errno as i32),
            _ => None,
        }
    }
}
<commit_msg>backend.libseat: Fix dispatch double borrow<commit_after>//!
//! Implementation of the [`Session`](::backend::session::Session) trait through the libseat.
//!
//! This requires libseat to be available on the system.

use libseat::{Seat, SeatEvent};
use std::{
    cell::RefCell,
    collections::HashMap,
    os::unix::io::RawFd,
    path::Path,
    rc::{Rc, Weak},
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use nix::{errno::Errno, fcntl::OFlag, unistd::close};

use calloop::{
    channel::{self, Channel},
    EventSource, Poll, PostAction, Readiness, Token, TokenFactory,
};

use crate::{
    backend::session::{AsErrno, Session, Signal as SessionSignal},
    utils::signaling::Signaler,
};

use slog::{debug, error, o};

#[derive(Debug)]
struct LibSeatSessionImpl {
    seat: RefCell<Seat>,
    active: Arc<AtomicBool>,
    devices: RefCell<HashMap<RawFd, i32>>,
    logger: ::slog::Logger,
}

impl Drop for LibSeatSessionImpl {
    fn drop(&mut self) {
        debug!(self.logger, "Closing seat")
    }
}

/// [`Session`] via the libseat
#[derive(Debug, Clone)]
pub struct LibSeatSession {
    internal: Weak<LibSeatSessionImpl>,
    seat_name: String,
}

/// [`SessionNotifier`] via the libseat
#[derive(Debug)]
pub struct LibSeatSessionNotifier {
    internal: Rc<LibSeatSessionImpl>,
    signaler: Signaler<SessionSignal>,
    rx: Channel<SeatEvent>,
    token: Token,
}

impl LibSeatSession {
    /// Tries to create a new session via libseat.
    pub fn new<L>(logger: L) -> Result<(LibSeatSession, LibSeatSessionNotifier), Error>
    where
        L: Into<Option<::slog::Logger>>,
    {
        let logger = crate::slog_or_fallback(logger)
            .new(o!("smithay_module" => "backend_session", "session_type" => "libseat"));

        let (tx, rx) = calloop::channel::channel();

        let seat = {
            let log = logger.clone();

            Seat::open(
                move |_seat, event| match event {
                    SeatEvent::Enable => {
                        debug!(log, "Enable callback called");
                        tx.send(event).unwrap();
                    }
                    SeatEvent::Disable => {
                        debug!(log, "Disable callback called");
                        tx.send(event).unwrap();
                    }
                },
                logger.clone(),
            )
        };

        seat.map(|mut seat| {
            let seat_name = seat.name().to_owned();

            // In some cases enable_seat event is avalible right after startup
            // so, we can dispatch it
            seat.dispatch(0).unwrap();

            let internal = Rc::new(LibSeatSessionImpl {
                seat: RefCell::new(seat),
                active: Arc::new(AtomicBool::new(false)),
                devices: RefCell::new(HashMap::new()),
                logger,
            });

            let session = LibSeatSession {
                internal: Rc::downgrade(&internal),
                seat_name,
            };

            let notifier = LibSeatSessionNotifier {
                internal,
                signaler: Signaler::new(),
                rx,
                token: Token::invalid(),
            };

            (session, notifier)
        })
        .map_err(|err| Error::FailedToOpenSession(Errno::from_i32(err.into())))
    }
}

impl Session for LibSeatSession {
    type Error = Error;

    fn open(&mut self, path: &Path, _flags: OFlag) -> Result<RawFd, Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Opening device: {:?}", path);

            session
                .seat
                .borrow_mut()
                .open_device(&path)
                .map(|(id, fd)| {
                    session.devices.borrow_mut().insert(fd, id);
                    fd
                })
                .map_err(|err| Error::FailedToOpenDevice(Errno::from_i32(err.into())))
        } else {
            Err(Error::SessionLost)
        }
    }

    fn close(&mut self, fd: RawFd) -> Result<(), Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Closing device: {:?}", fd);

            let dev = session.devices.borrow().get(&fd).copied();

            let out = if let Some(dev) = dev {
                session
                    .seat
                    .borrow_mut()
                    .close_device(dev)
                    .map_err(|err| Error::FailedToCloseDevice(Errno::from_i32(err.into())))
            } else {
                Ok(())
            };

            close(fd).unwrap();

            out
        } else {
            Err(Error::SessionLost)
        }
    }

    fn change_vt(&mut self, vt: i32) -> Result<(), Self::Error> {
        if let Some(session) = self.internal.upgrade() {
            debug!(session.logger, "Session switch: {:?}", vt);
            session
                .seat
                .borrow_mut()
                .switch_session(vt)
                .map_err(|err| Error::FailedToChangeVt(Errno::from_i32(err.into())))
        } else {
            Err(Error::SessionLost)
        }
    }

    fn is_active(&self) -> bool {
        if let Some(internal) = self.internal.upgrade() {
            internal.active.load(Ordering::SeqCst)
        } else {
            false
        }
    }

    fn seat(&self) -> String {
        self.seat_name.clone()
    }
}

impl LibSeatSessionNotifier {
    /// Creates a new session object belonging to this notifier.
    pub fn session(&self) -> LibSeatSession {
        LibSeatSession {
            internal: Rc::downgrade(&self.internal),
            seat_name: self.internal.seat.borrow_mut().name().to_owned(),
        }
    }

    /// Get a handle to the Signaler of this session.
    ///
    /// You can use it to listen for signals generated by the session.
    pub fn signaler(&self) -> Signaler<SessionSignal> {
        self.signaler.clone()
    }
}

impl EventSource for LibSeatSessionNotifier {
    type Event = ();
    type Metadata = ();
    type Ret = ();

    fn process_events<F>(&mut self, readiness: Readiness, token: Token, _: F) -> std::io::Result<PostAction>
    where
        F: FnMut((), &mut ()),
    {
        if token == self.token {
            self.internal.seat.borrow_mut().dispatch(0).unwrap();
        }

        let internal = &self.internal;
        let signaler = &self.signaler;

        self.rx.process_events(readiness, token, |event, _| match event {
            channel::Event::Msg(event) => match event {
                SeatEvent::Enable => {
                    internal.active.store(true, Ordering::SeqCst);
                    signaler.signal(SessionSignal::ActivateSession);
                }
                SeatEvent::Disable => {
                    internal.active.store(false, Ordering::SeqCst);
                    signaler.signal(SessionSignal::PauseSession);
                    internal.seat.borrow_mut().disable().unwrap();
                }
            },
            channel::Event::Closed => {
                // Tx is stored inside of Seat, and Rc<Seat> is stored in LibSeatSessionNotifier so this is unreachable
            }
        })
    }

    fn register(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> std::io::Result<()> {
        self.rx.register(poll, factory)?;

        self.token = factory.token();
        poll.register(
            self.internal.seat.borrow_mut().get_fd().unwrap(),
            calloop::Interest::READ,
            calloop::Mode::Level,
            self.token,
        )
    }

    fn reregister(&mut self, poll: &mut Poll, factory: &mut TokenFactory) -> std::io::Result<()> {
        self.rx.reregister(poll, factory)?;

        self.token = factory.token();
        poll.reregister(
            self.internal.seat.borrow_mut().get_fd().unwrap(),
            calloop::Interest::READ,
            calloop::Mode::Level,
            self.token,
        )
    }

    fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {
        self.rx.unregister(poll)?;

        self.token = Token::invalid();
        poll.unregister(self.internal.seat.borrow_mut().get_fd().unwrap())
    }
}

/// Errors related to direct/tty sessions
#[derive(thiserror::Error, Debug)]
pub enum Error {
    /// Failed to open session
    #[error("Failed to open session: {0}")]
    FailedToOpenSession(Errno),

    /// Failed to open device
    #[error("Failed to open device: {0}")]
    FailedToOpenDevice(Errno),

    /// Failed to close device
    #[error("Failed to close device: {0}")]
    FailedToCloseDevice(Errno),

    /// Failed to close device
    #[error("Failed to change vt: {0}")]
    FailedToChangeVt(Errno),

    /// Session is already closed,
    #[error("Session is already closed")]
    SessionLost,
}

impl AsErrno for Error {
    fn as_errno(&self) -> Option<i32> {
        match self {
            &Self::FailedToOpenSession(errno)
            | &Self::FailedToOpenDevice(errno)
            | &Self::FailedToCloseDevice(errno)
            | &Self::FailedToChangeVt(errno) => Some(errno as i32),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>use crate::error::Error;
use crate::instance::{InstanceHandle, RunResult, State, TerminationDetails};
use crate::val::{UntypedRetVal, Val};
use crate::vmctx::{Vmctx, VmctxInternal};
use std::any::Any;
use std::future::Future;
use std::pin::Pin;

/// This is the same type defined by the `futures` library, but we don't need the rest of the
/// library for this purpose.
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

/// A unique type that wraps a boxed future with a boxed return value.
///
/// Type and lifetime guarantees are maintained by `Vmctx::block_on` and `Instance::run_async`. The
/// user never sees this type.
struct YieldedFuture(BoxFuture<'static, ResumeVal>);

/// A unique type for a boxed return value. The user never sees this type.
pub struct ResumeVal(Box<dyn Any + Send + 'static>);

unsafe impl Send for ResumeVal {}

impl Vmctx {
    /// Block on the result of an `async` computation from an instance run by `Instance::run_async`.
    ///
    /// Lucet hostcalls are synchronous `extern "C" fn` functions called from WebAssembly. In that
    /// context, we cannot use `.await` directly because the hostcall is not `async`. While we could
    /// block on an executor using `futures::executor::block_on` or
    /// `tokio::runtime::Runtime::block_on`, that has two drawbacks:
    ///
    /// - If the Lucet instance was originally invoked from an async context, trying to block on the
    ///   same runtime will fail if the executor cannot be nested (all executors we know of have this
    ///   restriction).
    ///
    /// - The current OS thread would be blocked on the result of the computation, rather than being
    ///   able to run other async tasks while awaiting. This means an application will need more
    ///   threads than otherwise would be necessary.
    ///
    /// Instead, this block_on operator is designed to work only when called within an invocation
    /// of [`Instance::run_async`]. The `run_async` method executes instance code within a
    /// trampoline, itself running within an async context, making it possible to temporarily pause
    /// guest execution, jump back to the trampoline, and await there. The future given to block_on
    /// is in passed back to that trampoline, and runs on the same runtime that invoked
    /// `run_async`, avoiding problems of nesting, and allowing the current OS thread to continue
    /// performing other async work.
    ///
    /// Note that this method may only be used if `Instance::run_async` was used to run the VM,
    /// otherwise it will terminate the instance with `TerminationDetails::AwaitNeedsAsync`.
    pub fn block_on<'a, R>(&'a self, f: impl Future<Output = R> + Send + 'a) -> R
    where
        R: Any + Send + 'static,
    {
        // Die if we aren't in Instance::run_async
        match self.instance().state {
            State::Running { async_context } => {
                if !async_context {
                    panic!(TerminationDetails::AwaitNeedsAsync)
                }
            }
            _ => unreachable!("Access to vmctx implies instance is Running"),
        }
        // Wrap the Output of `f` as a boxed ResumeVal. Then, box the entire
        // async computation.
        let f = Box::pin(async move { ResumeVal(Box::new(f.await)) });
        // Change the lifetime of the async computation from `'a` to `'static.
        // We need to lie about this lifetime so that `YieldedFuture` may impl
        // `Any` and be passed through the yield. `Instance::run_async`
        // rehydrates this lifetime to be at most as long as the Vmctx's `'a`.
        // This is safe because the stack frame that `'a` is tied to gets
        // frozen in place as part of `self.yield_val_expecting_val`.
        let f = unsafe {
            std::mem::transmute::<BoxFuture<'a, ResumeVal>, BoxFuture<'static, ResumeVal>>(f)
        };
        // Wrap the computation in `YieldedFuture` so that
        // `Instance::run_async` can catch and run it.  We will get the
        // `ResumeVal` we applied to `f` above.
        let ResumeVal(v) = self.yield_val_expecting_val(YieldedFuture(f));
        // We may now downcast and unbox the returned Box<dyn Any> into an `R`
        // again.
        *v.downcast().expect("run_async broke invariant")
    }
}

pub enum Bounce<'a> {
    Done(UntypedRetVal),
    More(BoxFuture<'a, ResumeVal>),
}

impl InstanceHandle {
    /// Run a WebAssembly function with arguments in the guest context at the given entrypoint.
    ///
    /// This method is similar to `Instance::run()`, but allows the Wasm program to invoke hostcalls
    /// that use `Vmctx::block_on` and provides the trampoline that `.await`s those futures on
    /// behalf of the guest.
    ///
    /// # `Vmctx` Restrictions
    ///
    /// This method permits the use of `Vmctx::block_on`, but disallows all other uses of `Vmctx::
    /// yield_val_expecting_val` and family (`Vmctx::yield_`, `Vmctx::yield_expecting_val`,
    /// `Vmctx::yield_val`).
    ///
    /// # Blocking thread
    ///
    /// The `wrap_blocking` argument is a function that is called with a closure that runs the Wasm
    /// program. Since Wasm may execute for an arbitrarily long time without `await`ing, we need to
    /// make sure that it runs on a thread that is allowed to block.
    ///
    /// This argument is designed with [`tokio::task::block_in_place`][tokio] in mind. The odd type
    /// is a concession to the fact that we don't have rank 2 types in Rust, and so must fall back
    /// to trait objects in order to be able to take an argument that is itself a function that
    /// takes a closure.
    ///
    /// In order to provide an appropriate function, you may have to wrap the library function in
    /// another closure so that the types are compatible. For example:
    ///
    /// ```no_run
    /// # async fn f() {
    /// # let instance: lucet_runtime_internals::instance::InstanceHandle = unimplemented!();
    /// fn block_in_place<F, R>(f: F) -> R
    /// where
    ///     F: FnOnce() -> R,
    /// {
    ///     // ...
    ///     # f()
    /// }
    ///
    /// instance.run_async("entrypoint", &[], |f| block_in_place(f)).await.unwrap();
    /// # }
    /// ```
    ///
    /// [tokio]: https://docs.rs/tokio/0.2.21/tokio/task/fn.block_in_place.html
    pub async fn run_async<'a, F>(
        &'a mut self,
        entrypoint: &'a str,
        args: &'a [Val],
        wrap_blocking: F,
    ) -> Result<UntypedRetVal, Error>
    where
        F: for<'b> Fn(&mut (dyn FnMut() -> Result<Bounce<'b>, Error>)) -> Result<Bounce<'b>, Error>,
    {
        if self.is_yielded() {
            return Err(Error::Unsupported(
                "cannot run_async a yielded instance".to_owned(),
            ));
        }

        // Store the ResumeVal here when we get it.
        let mut resume_val: Option<ResumeVal> = None;
        loop {
            // Run the WebAssembly program
            let bounce = wrap_blocking(&mut || {
                let run_result = if self.is_yielded() {
                    // A previous iteration of the loop stored the ResumeVal in
                    // `resume_val`, send it back to the guest ctx and continue
                    // running:
                    self.resume_with_val_impl(
                        resume_val
                            .take()
                            .expect("is_yielded implies resume_value is some"),
                        true,
                    )
                } else {
                    // This is the first iteration, call the entrypoint:
                    let func = self.module.get_export_func(entrypoint)?;
                    self.run_func(func, args, true)
                };
                match run_result? {
                    RunResult::Returned(rval) => {
                        // Finished running, return UntypedReturnValue
                        return Ok(Bounce::Done(rval));
                    }
                    RunResult::Yielded(yval) => {
                        // Check if the yield came from Vmctx::block_on:
                        if yval.is::<YieldedFuture>() {
                            let YieldedFuture(future) = *yval.downcast::<YieldedFuture>().unwrap();
                            // Rehydrate the lifetime from `'static` to `'a`, which
                            // is morally the same lifetime as was passed into
                            // `Vmctx::block_on`.
                            Ok(Bounce::More(future as BoxFuture<'a, ResumeVal>))
                        } else {
                            // Any other yielded value is not supported - die with an error.
                            Err(Error::Unsupported(
                                "cannot yield anything besides a future in Instance::run_async"
                                    .to_owned(),
                            ))
                        }
                    }
                }
            })?;
            match bounce {
                Bounce::Done(rval) => return Ok(rval),
                Bounce::More(fut) => {
                    // await on the computation. Store its result in
                    // `resume_val`.
                    resume_val = Some(fut.await);
                    // Now we want to `Instance::resume_with_val` and start
                    // this cycle over.
                }
            }
        }
    }
}
<commit_msg>add docs<commit_after>use crate::error::Error;
use crate::instance::{InstanceHandle, RunResult, State, TerminationDetails};
use crate::val::{UntypedRetVal, Val};
use crate::vmctx::{Vmctx, VmctxInternal};
use std::any::Any;
use std::future::Future;
use std::pin::Pin;

/// This is the same type defined by the `futures` library, but we don't need the rest of the
/// library for this purpose.
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

/// A unique type that wraps a boxed future with a boxed return value.
///
/// Type and lifetime guarantees are maintained by `Vmctx::block_on` and `Instance::run_async`. The
/// user never sees this type.
struct YieldedFuture(BoxFuture<'static, ResumeVal>);

/// A unique type for a boxed return value. The user never sees this type.
pub struct ResumeVal(Box<dyn Any + Send + 'static>);

unsafe impl Send for ResumeVal {}

impl Vmctx {
    /// Block on the result of an `async` computation from an instance run by `Instance::run_async`.
    ///
    /// Lucet hostcalls are synchronous `extern "C" fn` functions called from WebAssembly. In that
    /// context, we cannot use `.await` directly because the hostcall is not `async`. While we could
    /// block on an executor using `futures::executor::block_on` or
    /// `tokio::runtime::Runtime::block_on`, that has two drawbacks:
    ///
    /// - If the Lucet instance was originally invoked from an async context, trying to block on the
    ///   same runtime will fail if the executor cannot be nested (all executors we know of have this
    ///   restriction).
    ///
    /// - The current OS thread would be blocked on the result of the computation, rather than being
    ///   able to run other async tasks while awaiting. This means an application will need more
    ///   threads than otherwise would be necessary.
    ///
    /// Instead, this block_on operator is designed to work only when called within an invocation
    /// of [`Instance::run_async`]. The `run_async` method executes instance code within a
    /// trampoline, itself running within an async context, making it possible to temporarily pause
    /// guest execution, jump back to the trampoline, and await there. The future given to block_on
    /// is in passed back to that trampoline, and runs on the same runtime that invoked
    /// `run_async`, avoiding problems of nesting, and allowing the current OS thread to continue
    /// performing other async work.
    ///
    /// Note that this method may only be used if `Instance::run_async` was used to run the VM,
    /// otherwise it will terminate the instance with `TerminationDetails::AwaitNeedsAsync`.
    pub fn block_on<'a, R>(&'a self, f: impl Future<Output = R> + Send + 'a) -> R
    where
        R: Any + Send + 'static,
    {
        // Die if we aren't in Instance::run_async
        match self.instance().state {
            State::Running { async_context } => {
                if !async_context {
                    panic!(TerminationDetails::AwaitNeedsAsync)
                }
            }
            _ => unreachable!("Access to vmctx implies instance is Running"),
        }
        // Wrap the Output of `f` as a boxed ResumeVal. Then, box the entire
        // async computation.
        let f = Box::pin(async move { ResumeVal(Box::new(f.await)) });
        // Change the lifetime of the async computation from `'a` to `'static.
        // We need to lie about this lifetime so that `YieldedFuture` may impl
        // `Any` and be passed through the yield. `Instance::run_async`
        // rehydrates this lifetime to be at most as long as the Vmctx's `'a`.
        // This is safe because the stack frame that `'a` is tied to gets
        // frozen in place as part of `self.yield_val_expecting_val`.
        let f = unsafe {
            std::mem::transmute::<BoxFuture<'a, ResumeVal>, BoxFuture<'static, ResumeVal>>(f)
        };
        // Wrap the computation in `YieldedFuture` so that
        // `Instance::run_async` can catch and run it.  We will get the
        // `ResumeVal` we applied to `f` above.
        let ResumeVal(v) = self.yield_val_expecting_val(YieldedFuture(f));
        // We may now downcast and unbox the returned Box<dyn Any> into an `R`
        // again.
        *v.downcast().expect("run_async broke invariant")
    }
}

/// This enum is used internally to `InstanceHandle::run_async`. It is only
/// `pub` in order for the type signature of a "block_in_place" function to be
/// writable, which is a concession because Rust does not have rank 2 types.
/// The user should never inspect or construct the contents of this enum.
pub enum Bounce<'a> {
    Done(UntypedRetVal),
    More(BoxFuture<'a, ResumeVal>),
}

impl InstanceHandle {
    /// Run a WebAssembly function with arguments in the guest context at the given entrypoint.
    ///
    /// This method is similar to `Instance::run()`, but allows the Wasm program to invoke hostcalls
    /// that use `Vmctx::block_on` and provides the trampoline that `.await`s those futures on
    /// behalf of the guest.
    ///
    /// # `Vmctx` Restrictions
    ///
    /// This method permits the use of `Vmctx::block_on`, but disallows all other uses of `Vmctx::
    /// yield_val_expecting_val` and family (`Vmctx::yield_`, `Vmctx::yield_expecting_val`,
    /// `Vmctx::yield_val`).
    ///
    /// # Blocking thread
    ///
    /// The `wrap_blocking` argument is a function that is called with a closure that runs the Wasm
    /// program. Since Wasm may execute for an arbitrarily long time without `await`ing, we need to
    /// make sure that it runs on a thread that is allowed to block.
    ///
    /// This argument is designed with [`tokio::task::block_in_place`][tokio] in mind. The odd type
    /// is a concession to the fact that we don't have rank 2 types in Rust, and so must fall back
    /// to trait objects in order to be able to take an argument that is itself a function that
    /// takes a closure.
    ///
    /// In order to provide an appropriate function, you may have to wrap the library function in
    /// another closure so that the types are compatible. For example:
    ///
    /// ```no_run
    /// # async fn f() {
    /// # let instance: lucet_runtime_internals::instance::InstanceHandle = unimplemented!();
    /// fn block_in_place<F, R>(f: F) -> R
    /// where
    ///     F: FnOnce() -> R,
    /// {
    ///     // ...
    ///     # f()
    /// }
    ///
    /// instance.run_async("entrypoint", &[], |f| block_in_place(f)).await.unwrap();
    /// # }
    /// ```
    ///
    /// [tokio]: https://docs.rs/tokio/0.2.21/tokio/task/fn.block_in_place.html
    pub async fn run_async<'a, F>(
        &'a mut self,
        entrypoint: &'a str,
        args: &'a [Val],
        wrap_blocking: F,
    ) -> Result<UntypedRetVal, Error>
    where
        F: for<'b> Fn(&mut (dyn FnMut() -> Result<Bounce<'b>, Error>)) -> Result<Bounce<'b>, Error>,
    {
        if self.is_yielded() {
            return Err(Error::Unsupported(
                "cannot run_async a yielded instance".to_owned(),
            ));
        }

        // Store the ResumeVal here when we get it.
        let mut resume_val: Option<ResumeVal> = None;
        loop {
            // Run the WebAssembly program
            let bounce = wrap_blocking(&mut || {
                let run_result = if self.is_yielded() {
                    // A previous iteration of the loop stored the ResumeVal in
                    // `resume_val`, send it back to the guest ctx and continue
                    // running:
                    self.resume_with_val_impl(
                        resume_val
                            .take()
                            .expect("is_yielded implies resume_value is some"),
                        true,
                    )
                } else {
                    // This is the first iteration, call the entrypoint:
                    let func = self.module.get_export_func(entrypoint)?;
                    self.run_func(func, args, true)
                };
                match run_result? {
                    RunResult::Returned(rval) => {
                        // Finished running, return UntypedReturnValue
                        return Ok(Bounce::Done(rval));
                    }
                    RunResult::Yielded(yval) => {
                        // Check if the yield came from Vmctx::block_on:
                        if yval.is::<YieldedFuture>() {
                            let YieldedFuture(future) = *yval.downcast::<YieldedFuture>().unwrap();
                            // Rehydrate the lifetime from `'static` to `'a`, which
                            // is morally the same lifetime as was passed into
                            // `Vmctx::block_on`.
                            Ok(Bounce::More(future as BoxFuture<'a, ResumeVal>))
                        } else {
                            // Any other yielded value is not supported - die with an error.
                            Err(Error::Unsupported(
                                "cannot yield anything besides a future in Instance::run_async"
                                    .to_owned(),
                            ))
                        }
                    }
                }
            })?;
            match bounce {
                Bounce::Done(rval) => return Ok(rval),
                Bounce::More(fut) => {
                    // await on the computation. Store its result in
                    // `resume_val`.
                    resume_val = Some(fut.await);
                    // Now we want to `Instance::resume_with_val` and start
                    // this cycle over.
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains everything needed to instantiate an interpreter.
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.

use std::borrow::{Borrow, Cow};
use std::hash::Hash;

use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::ty::{self, TyCtxt};

use super::{
    Allocation, AllocId, InterpResult, InterpError, Scalar, AllocationExtra,
    InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
};

/// Whether this kind of memory is allowed to leak
pub trait MayLeak: Copy {
    fn may_leak(self) -> bool;
}

/// The functionality needed by memory to manage its allocations
pub trait AllocMap<K: Hash + Eq, V> {
    /// Tests if the map contains the given key.
    /// Deliberately takes `&mut` because that is sufficient, and some implementations
    /// can be more efficient then (using `RefCell::get_mut`).
    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
        where K: Borrow<Q>;

    /// Inserts a new entry into the map.
    fn insert(&mut self, k: K, v: V) -> Option<V>;

    /// Removes an entry from the map.
    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
        where K: Borrow<Q>;

    /// Returns data based the keys and values in the map.
    fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;

    /// Returns a reference to entry `k`. If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_or<E>(
        &self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&V, E>;

    /// Returns a mutable reference to entry `k`. If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_mut_or<E>(
        &mut self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&mut V, E>;

    /// Read-only lookup.
    fn get(&self, k: K) -> Option<&V> {
        match self.get_or(k, || Err(())) {
            Ok(v) => Some(v),
            Err(()) => None,
        }
    }

    /// Mutable lookup.
    fn get_mut(&mut self, k: K) -> Option<&mut V> {
        match self.get_mut_or(k, || Err(())) {
            Ok(v) => Some(v),
            Err(()) => None,
        }
    }
}

/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied.
pub trait Machine<'mir, 'tcx>: Sized {
    /// Additional memory kinds a machine wishes to distinguish from the builtin ones
    type MemoryKinds: ::std::fmt::Debug + MayLeak + Eq + 'static;

    /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows"
    /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
    /// The `default()` is used for pointers to consts, statics, vtables and functions.
    type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static;

    /// Machines can define extra (non-instance) things that represent values of function pointers.
    /// For example, Miri uses this to return a fucntion pointer from `dlsym`
    /// that can later be called to execute the right thing.
    type ExtraFnVal: ::std::fmt::Debug + Copy;

    /// Extra data stored in every call frame.
    type FrameExtra;

    /// Extra data stored in memory. A reference to this is available when `AllocExtra`
    /// gets initialized, so you can e.g., have an `Rc` here if there is global state you
    /// need access to in the `AllocExtra` hooks.
    type MemoryExtra;

    /// Extra data stored in every allocation.
    type AllocExtra: AllocationExtra<Self::PointerTag> + 'static;

    /// Memory's allocation map
    type MemoryMap:
        AllocMap<
            AllocId,
            (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag, Self::AllocExtra>)
        > +
        Default +
        Clone;

    /// The memory kind to use for copied statics -- or None if statics should not be mutated
    /// and thus any such attempt will cause a `ModifiedStatic` error to be raised.
    /// Statics are copied under two circumstances: When they are mutated, and when
    /// `tag_allocation` or `find_foreign_static` (see below) returns an owned allocation
    /// that is added to the memory so that the work is not done twice.
    const STATIC_KIND: Option<Self::MemoryKinds>;

    /// Whether to enforce the validity invariant
    fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

    /// Called before a basic block terminator is executed.
    /// You can use this to detect endlessly running programs.
    fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;

    /// Entry point to all function calls.
    ///
    /// Returns either the mir to use for the call, or `None` if execution should
    /// just proceed (which usually means this hook did all the work that the
    /// called function should usually have done). In the latter case, it is
    /// this hook's responsibility to call `goto_block(ret)` to advance the instruction pointer!
    /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR
    /// nor just jump to `ret`, but instead push their own stack frame.)
    /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
    /// was used.
    fn find_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;

    /// Execute `fn_val`.  it is the hook's responsibility to advance the instruction
    /// pointer as appropriate.
    fn call_extra_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        fn_val: Self::ExtraFnVal,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx>;

    /// Directly process an intrinsic without pushing a stack frame.
    /// If this returns successfully, the engine will take care of jumping to the next block.
    fn call_intrinsic(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx>;

    /// Called for read access to a foreign static item.
    ///
    /// This will only be called once per static and machine; the result is cached in
    /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    ///
    /// This allocation will then be fed to `tag_allocation` to initialize the "extra" state.
    fn find_foreign_static(
        tcx: TyCtxt<'tcx>,
        def_id: DefId,
    ) -> InterpResult<'tcx, Cow<'tcx, Allocation>>;

    /// Called for all binary operations on integer(-like) types when one operand is a pointer
    /// value, and for the `Offset` operation that is inherently about pointers.
    ///
    /// Returns a (value, overflowed) pair if the operation succeeded
    fn ptr_op(
        ecx: &InterpCx<'mir, 'tcx, Self>,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Self::PointerTag>,
        right: ImmTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool)>;

    /// Heap allocations via the `box` keyword.
    fn box_alloc(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx>;

    /// Called to initialize the "extra" state of an allocation and make the pointers
    /// it contains (in relocations) tagged.  The way we construct allocations is
    /// to always first construct it without extra and then add the extra.
    /// This keeps uniform code paths for handling both allocations created by CTFE
    /// for statics, and allocations ceated by Miri during evaluation.
    ///
    /// `kind` is the kind of the allocation being tagged; it can be `None` when
    /// it's a static and `STATIC_KIND` is `None`.
    ///
    /// This should avoid copying if no work has to be done! If this returns an owned
    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    ///
    /// For static allocations, the tag returned must be the same as the one returned by
    /// `tag_static_base_pointer`.
    fn tag_allocation<'b>(
        memory_extra: &Self::MemoryExtra,
        id: AllocId,
        alloc: Cow<'b, Allocation>,
        kind: Option<MemoryKind<Self::MemoryKinds>>,
    ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag);

    /// Return the "base" tag for the given static allocation: the one that is used for direct
    /// accesses to this static/const/fn allocation.
    ///
    /// Be aware that requesting the `Allocation` for that `id` will lead to cycles
    /// for cyclic statics!
    fn tag_static_base_pointer(
        memory_extra: &Self::MemoryExtra,
        id: AllocId,
    ) -> Self::PointerTag;

    /// Executes a retagging operation
    #[inline]
    fn retag(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        _kind: mir::RetagKind,
        _place: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx> {
        Ok(())
    }

    /// Called immediately before a new stack frame got pushed
    fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>;

    /// Called immediately after a stack frame gets popped
    fn stack_pop(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        extra: Self::FrameExtra,
    ) -> InterpResult<'tcx>;

    #[inline(always)]
    fn int_to_ptr(
        _mem: &Memory<'mir, 'tcx, Self>,
        int: u64,
    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
        Err((if int == 0 {
            InterpError::InvalidNullPointerUsage
        } else {
            InterpError::ReadBytesAsPointer
        }).into())
    }

    #[inline(always)]
    fn ptr_to_int(
        _mem: &Memory<'mir, 'tcx, Self>,
        _ptr: Pointer<Self::PointerTag>,
    ) -> InterpResult<'tcx, u64> {
        err!(ReadPointerAsBytes)
    }
}
<commit_msg>replace match by ok()<commit_after>//! This module contains everything needed to instantiate an interpreter.
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.

use std::borrow::{Borrow, Cow};
use std::hash::Hash;

use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc::ty::{self, TyCtxt};

use super::{
    Allocation, AllocId, InterpResult, InterpError, Scalar, AllocationExtra,
    InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
};

/// Whether this kind of memory is allowed to leak
pub trait MayLeak: Copy {
    fn may_leak(self) -> bool;
}

/// The functionality needed by memory to manage its allocations
pub trait AllocMap<K: Hash + Eq, V> {
    /// Tests if the map contains the given key.
    /// Deliberately takes `&mut` because that is sufficient, and some implementations
    /// can be more efficient then (using `RefCell::get_mut`).
    fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
        where K: Borrow<Q>;

    /// Inserts a new entry into the map.
    fn insert(&mut self, k: K, v: V) -> Option<V>;

    /// Removes an entry from the map.
    fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
        where K: Borrow<Q>;

    /// Returns data based the keys and values in the map.
    fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;

    /// Returns a reference to entry `k`. If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_or<E>(
        &self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&V, E>;

    /// Returns a mutable reference to entry `k`. If no such entry exists, call
    /// `vacant` and either forward its error, or add its result to the map
    /// and return a reference to *that*.
    fn get_mut_or<E>(
        &mut self,
        k: K,
        vacant: impl FnOnce() -> Result<V, E>
    ) -> Result<&mut V, E>;

    /// Read-only lookup.
    fn get(&self, k: K) -> Option<&V> {
        self.get_or(k, || Err(())).ok()
    }

    /// Mutable lookup.
    fn get_mut(&mut self, k: K) -> Option<&mut V> {
        self.get_mut_or(k, || Err(())).ok()
    }
}

/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied.
pub trait Machine<'mir, 'tcx>: Sized {
    /// Additional memory kinds a machine wishes to distinguish from the builtin ones
    type MemoryKinds: ::std::fmt::Debug + MayLeak + Eq + 'static;

    /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows"
    /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
    /// The `default()` is used for pointers to consts, statics, vtables and functions.
    type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static;

    /// Machines can define extra (non-instance) things that represent values of function pointers.
    /// For example, Miri uses this to return a fucntion pointer from `dlsym`
    /// that can later be called to execute the right thing.
    type ExtraFnVal: ::std::fmt::Debug + Copy;

    /// Extra data stored in every call frame.
    type FrameExtra;

    /// Extra data stored in memory. A reference to this is available when `AllocExtra`
    /// gets initialized, so you can e.g., have an `Rc` here if there is global state you
    /// need access to in the `AllocExtra` hooks.
    type MemoryExtra;

    /// Extra data stored in every allocation.
    type AllocExtra: AllocationExtra<Self::PointerTag> + 'static;

    /// Memory's allocation map
    type MemoryMap:
        AllocMap<
            AllocId,
            (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag, Self::AllocExtra>)
        > +
        Default +
        Clone;

    /// The memory kind to use for copied statics -- or None if statics should not be mutated
    /// and thus any such attempt will cause a `ModifiedStatic` error to be raised.
    /// Statics are copied under two circumstances: When they are mutated, and when
    /// `tag_allocation` or `find_foreign_static` (see below) returns an owned allocation
    /// that is added to the memory so that the work is not done twice.
    const STATIC_KIND: Option<Self::MemoryKinds>;

    /// Whether to enforce the validity invariant
    fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;

    /// Called before a basic block terminator is executed.
    /// You can use this to detect endlessly running programs.
    fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;

    /// Entry point to all function calls.
    ///
    /// Returns either the mir to use for the call, or `None` if execution should
    /// just proceed (which usually means this hook did all the work that the
    /// called function should usually have done). In the latter case, it is
    /// this hook's responsibility to call `goto_block(ret)` to advance the instruction pointer!
    /// (This is to support functions like `__rust_maybe_catch_panic` that neither find a MIR
    /// nor just jump to `ret`, but instead push their own stack frame.)
    /// Passing `dest`and `ret` in the same `Option` proved very annoying when only one of them
    /// was used.
    fn find_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;

    /// Execute `fn_val`.  it is the hook's responsibility to advance the instruction
    /// pointer as appropriate.
    fn call_extra_fn(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        fn_val: Self::ExtraFnVal,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
        ret: Option<mir::BasicBlock>,
    ) -> InterpResult<'tcx>;

    /// Directly process an intrinsic without pushing a stack frame.
    /// If this returns successfully, the engine will take care of jumping to the next block.
    fn call_intrinsic(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        instance: ty::Instance<'tcx>,
        args: &[OpTy<'tcx, Self::PointerTag>],
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx>;

    /// Called for read access to a foreign static item.
    ///
    /// This will only be called once per static and machine; the result is cached in
    /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    ///
    /// This allocation will then be fed to `tag_allocation` to initialize the "extra" state.
    fn find_foreign_static(
        tcx: TyCtxt<'tcx>,
        def_id: DefId,
    ) -> InterpResult<'tcx, Cow<'tcx, Allocation>>;

    /// Called for all binary operations on integer(-like) types when one operand is a pointer
    /// value, and for the `Offset` operation that is inherently about pointers.
    ///
    /// Returns a (value, overflowed) pair if the operation succeeded
    fn ptr_op(
        ecx: &InterpCx<'mir, 'tcx, Self>,
        bin_op: mir::BinOp,
        left: ImmTy<'tcx, Self::PointerTag>,
        right: ImmTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool)>;

    /// Heap allocations via the `box` keyword.
    fn box_alloc(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        dest: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx>;

    /// Called to initialize the "extra" state of an allocation and make the pointers
    /// it contains (in relocations) tagged.  The way we construct allocations is
    /// to always first construct it without extra and then add the extra.
    /// This keeps uniform code paths for handling both allocations created by CTFE
    /// for statics, and allocations ceated by Miri during evaluation.
    ///
    /// `kind` is the kind of the allocation being tagged; it can be `None` when
    /// it's a static and `STATIC_KIND` is `None`.
    ///
    /// This should avoid copying if no work has to be done! If this returns an owned
    /// allocation (because a copy had to be done to add tags or metadata), machine memory will
    /// cache the result. (This relies on `AllocMap::get_or` being able to add the
    /// owned allocation to the map even when the map is shared.)
    ///
    /// For static allocations, the tag returned must be the same as the one returned by
    /// `tag_static_base_pointer`.
    fn tag_allocation<'b>(
        memory_extra: &Self::MemoryExtra,
        id: AllocId,
        alloc: Cow<'b, Allocation>,
        kind: Option<MemoryKind<Self::MemoryKinds>>,
    ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag);

    /// Return the "base" tag for the given static allocation: the one that is used for direct
    /// accesses to this static/const/fn allocation.
    ///
    /// Be aware that requesting the `Allocation` for that `id` will lead to cycles
    /// for cyclic statics!
    fn tag_static_base_pointer(
        memory_extra: &Self::MemoryExtra,
        id: AllocId,
    ) -> Self::PointerTag;

    /// Executes a retagging operation
    #[inline]
    fn retag(
        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
        _kind: mir::RetagKind,
        _place: PlaceTy<'tcx, Self::PointerTag>,
    ) -> InterpResult<'tcx> {
        Ok(())
    }

    /// Called immediately before a new stack frame got pushed
    fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, Self::FrameExtra>;

    /// Called immediately after a stack frame gets popped
    fn stack_pop(
        ecx: &mut InterpCx<'mir, 'tcx, Self>,
        extra: Self::FrameExtra,
    ) -> InterpResult<'tcx>;

    #[inline(always)]
    fn int_to_ptr(
        _mem: &Memory<'mir, 'tcx, Self>,
        int: u64,
    ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
        Err((if int == 0 {
            InterpError::InvalidNullPointerUsage
        } else {
            InterpError::ReadBytesAsPointer
        }).into())
    }

    #[inline(always)]
    fn ptr_to_int(
        _mem: &Memory<'mir, 'tcx, Self>,
        _ptr: Pointer<Self::PointerTag>,
    ) -> InterpResult<'tcx, u64> {
        err!(ReadPointerAsBytes)
    }
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// arch/amd64/boot.rs
///! Kernel logging framework
///!
///! All kernel logging goes through this module, using the `log_*` macros, each corresponding
///! to a one of the logging levels in `Levels`.
// TODO: Support registerable log sinks, where all >Debug logs go (why not all?)
// > Cache/buffer sink
// > Display sink
// > Serial sink
use _common::*;
use core::fmt::{self,Write};
use arch::sync::Spinlock;

/// Log level, ranging from a kernel panic down to tracing
#[derive(PartialEq,PartialOrd,Copy,Clone)]
pub enum Level
{
	/// Everything broke
	LevelPanic,
	/// Something broke
	LevelError,
	/// Recoverable
	LevelWarning,
 	/// Odd
	LevelNotice,
   	/// Interesting (least important for the user)
	LevelInfo,
    	/// General (highest developer-only level)
	LevelLog,
   	/// What
	LevelDebug,
  	/// Where
	LevelTrace,
}

#[doc(hidden)]
pub enum Colour
{
	Default,
	Red,
	Yellow,
	Green,
	Blue,
	Purple,
	Grey,
}

#[doc(hidden)]
pub struct LoggingFormatter<'a>
{
	lock_handle: ::arch::sync::HeldSpinlock<'a,Sinks>,

	// NOTE: Must be second, forcing interrupts to be reenabled after the lock is released
	_irq_handle: ::arch::sync::HeldInterrupts,
}

/// Wrapper around a &-ptr that prints a hexdump of the passed data.
pub struct HexDump<'a,T:'a>(pub &'a T);

static S_LOGGING_LOCK: Spinlock<Sinks> = spinlock_init!( Sinks { serial: serial::Sink, memory: None, video: None } );

trait Sink
{
	fn start(&mut self, timestamp: ::time::TickCount, level: Level, source: &'static str);
	fn write(&mut self, data: &str);
	fn end(&mut self);
}
struct Sinks
{
	serial: serial::Sink,
	memory: Option<memory::Sink>,
	video: Option<video::Sink>,
}

mod serial
{
	use _common::*;
	use super::{Level,Colour};
	use core::{fmt,ops};
	use core::marker::PhantomData;

	pub struct Sink;
	impl super::Sink for Sink
	{
		fn start(&mut self, timestamp: ::time::TickCount, level: Level, source: &'static str) {
			use core::fmt::Write;
			self.set_colour(level.to_colour());
			write!(self, "{:8}{} [{:6}] - ", timestamp, level, source).unwrap();
		}
		fn write(&mut self, s: &str) {
			::arch::puts(s);
		}
		fn end(&mut self) {
			::arch::puts("\x1b[0m\n");
		}
	}
	impl fmt::Write for Sink
	{
		fn write_str(&mut self, s: &str) -> fmt::Result {
			::arch::puts(s);
			Ok( () )
		}
	}
	impl Sink
	{
		/// Set the output colour of the formatter
		pub fn set_colour(&self, colour: Colour) {
			match colour
			{
			Colour::Default => ::arch::puts("\x1b[0m"),
			Colour::Red     => ::arch::puts("\x1b[31m"),
			Colour::Green   => ::arch::puts("\x1b[32m"),
			Colour::Yellow  => ::arch::puts("\x1b[33m"),
			Colour::Blue    => ::arch::puts("\x1b[34m"),
			Colour::Purple  => ::arch::puts("\x1b[35m"),
			Colour::Grey    => ::arch::puts("\x1b[1;30m"),
			}
		}
	}
}

mod memory
{
	use _common::*;
	use super::Level;
	use core::{fmt,ops};

	pub struct Sink
	{
		lines: ::lib::ring_buffer::RingBuf<LogMessage>,
	}
	struct LogMessage
	{
		time: ::time::TickCount,
		level: Level,
		source: &'static str,
		data: String,
	}
	impl super::Sink for Sink
	{
		fn start(&mut self, timestamp: ::time::TickCount, level: Level, source: &'static str) {
			todo!("MemorySink");
		}
		fn write(&mut self, s: &str) {
			self.lines.back_mut().unwrap().data.push_str(s);
		}
		fn end(&mut self) {
			unimplemented!();
		}
	}
}

mod video
{
	use _common::*;
	use super::Level;
	use core::{fmt,ops};
	use core::marker::PhantomData;

	pub struct Sink;

	pub struct Writer<'a>(PhantomData<&'a mut Sink>);

	impl super::Sink for Sink
	{
		fn start(&mut self, timestamp: ::time::TickCount, level: Level, source: &'static str) {
			todo!("VideoSink");
		}
		fn write(&mut self, s: &str) {
			unimplemented!();
		}
		fn end(&mut self) {
			unimplemented!();
		}
	}
}

impl Level
{
	fn to_flag(&self) -> char
	{
		match *self
		{
		Level::LevelPanic   => 'k',
		Level::LevelError   => 'e',
		Level::LevelWarning => 'w',
		Level::LevelNotice  => 'n',
		Level::LevelInfo    => 'i',
		Level::LevelLog     => 'l',
		Level::LevelDebug   => 'd',
		Level::LevelTrace   => 't',
		}
	}
	fn to_colour(&self) -> Colour
	{
		match *self
		{
		Level::LevelPanic   => Colour::Purple,
		Level::LevelError   => Colour::Red,
		Level::LevelWarning => Colour::Yellow,
		Level::LevelNotice  => Colour::Green,
		Level::LevelLog     => Colour::Blue,
		Level::LevelTrace   => Colour::Grey,
		_ => Colour::Default,
		}
	}
}

impl fmt::Display for Level
{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.to_flag())
	}
}

impl<'a> LoggingFormatter<'a>
{
	/// Create a new logging formatter
	pub fn new(level: Level, modname: &'static str) -> LoggingFormatter<'static>
	{
		let mut rv = LoggingFormatter {
				_irq_handle: ::arch::sync::hold_interrupts(),
				lock_handle: S_LOGGING_LOCK.lock()
			};
		let ts = ::time::ticks();
		rv.lock_handle.serial.start(ts, level, modname);
		rv.lock_handle.memory.as_mut().map(|x| x.start(ts, level, modname) );
		rv.lock_handle.video.as_mut().map(|x| x.start(ts, level, modname) );
		rv
	}
}

impl<'a> fmt::Write for LoggingFormatter<'a>
{
	fn write_str(&mut self, s: &str) -> fmt::Result
	{
		self.lock_handle.serial.write(s);
		self.lock_handle.memory.as_mut().map(|x| x.write(s));
		self.lock_handle.video.as_mut().map(|x| x.write(s));
		Ok( () )
	}
}
impl<'a> ::core::ops::Drop for LoggingFormatter<'a>
{
	fn drop(&mut self)
	{
		self.lock_handle.serial.end();
		self.lock_handle.memory.as_mut().map(|x| x.end());
		self.lock_handle.video.as_mut().map(|x| x.end());
	}
}

impl<'a,T:'a> HexDump<'a,T>
{
	/// Return the wrapped type as a &[u8]
	fn byteslice(&self) -> &[u8]
	{
		let size = ::core::mem::size_of::<T>();
		unsafe {
			::core::mem::transmute(::core::raw::Slice {
				data: self.0 as *const T as *const u8,
				len: size,
			})
		}
	}
}

impl<'a,T:'a> fmt::Debug for HexDump<'a,T>
{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{
		for (idx,v) in self.byteslice().iter().enumerate()
		{
			try!(write!(f, "{:02x} ", *v));
			if idx % 16 == 15 {
				try!(write!(f, "| "));
			}
		}
		Ok( () )
	}
}

//pub fn hex_dump_block(label: &str, data: &[u8])
//{
//	let mut pos = 0;
//	while pos + 16 <= data.len()
//	{
//		log_debug!("{} {:p}: {:?}  {:?}", label, &data[pos], HexDump(&data[pos .. pos+8]), HexDump(&data[pos+8 .. pos+16]));
//	}
//	if pos == data.len()
//	{
//	}
//	else if pos + 8 >= data.len()
//	{
//		//log_debug!("{} {:p}: {:?}", label, &data[pos], HexDump(&data[pos ..]));
//	}
//	else
//	{
//		//log_debug!("{} {:p}: {:?}  {:?}", label, &data[pos], HexDump(&data[pos .. pos+8]), HexDump(&data[pos+8 ..]));
//	}
//}

#[doc(hidden)]
/// Returns true if the passed combination of module and level is enabled
pub fn enabled(level: Level, modname: &str) -> bool
{
	match modname
	{
	"kernel::memory::heap" => (level < Level::LevelDebug),	// Heap only prints higher than debug
	"kernel::memory::phys" => (level < Level::LevelTrace),	// PMM only prints >Trace
	_ => true,
	}
}

#[doc(hidden)]
/// Returns a logging formatter
pub fn getstream(level: Level, modname: &'static str) -> LoggingFormatter
{
	assert!( enabled(level, modname) );
	LoggingFormatter::new(level, modname)
}

// vim: ft=rust

<commit_msg>Core/Logging - Abstract sink iteration<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// arch/amd64/boot.rs
///! Kernel logging framework
///!
///! All kernel logging goes through this module, using the `log_*` macros, each corresponding
///! to a one of the logging levels in `Levels`.
// TODO: Support registerable log sinks, where all >Debug logs go (why not all?)
// > Cache/buffer sink
// > Display sink
// > Serial sink
use _common::*;
use core::fmt::{self,Write};
use arch::sync::Spinlock;

/// Log level, ranging from a kernel panic down to tracing
#[derive(PartialEq,PartialOrd,Copy,Clone)]
pub enum Level
{
	/// Everything broke
	LevelPanic,
	/// Something broke
	LevelError,
	/// Recoverable
	LevelWarning,
 	/// Odd
	LevelNotice,
   	/// Interesting (least important for the user)
	LevelInfo,
    	/// General (highest developer-only level)
	LevelLog,
   	/// What
	LevelDebug,
  	/// Where
	LevelTrace,
}

#[doc(hidden)]
pub enum Colour
{
	Default,
	Red,
	Yellow,
	Green,
	Blue,
	Purple,
	Grey,
}

#[doc(hidden)]
pub struct LoggingFormatter<'a>
{
	lock_handle: ::arch::sync::HeldSpinlock<'a,Sinks>,

	// NOTE: Must be second, forcing interrupts to be reenabled after the lock is released
	_irq_handle: ::arch::sync::HeldInterrupts,
}

/// Wrapper around a &-ptr that prints a hexdump of the passed data.
pub struct HexDump<'a,T:'a>(pub &'a T);

static S_LOGGING_LOCK: Spinlock<Sinks> = spinlock_init!( Sinks { serial: serial::Sink, memory: None, video: None } );

trait Sink
{
	fn start(&mut self, timestamp: ::time::TickCount, level: Level, source: &'static str);
	fn write(&mut self, data: &str);
	fn end(&mut self);
}
struct Sinks
{
	serial: serial::Sink,
	memory: Option<memory::Sink>,
	video: Option<video::Sink>,
}

mod serial
{
	use _common::*;
	use super::{Level,Colour};
	use core::{fmt,ops};
	use core::marker::PhantomData;

	pub struct Sink;
	impl super::Sink for Sink
	{
		fn start(&mut self, timestamp: ::time::TickCount, level: Level, source: &'static str) {
			use core::fmt::Write;
			self.set_colour(level.to_colour());
			write!(self, "{:8}{} [{:6}] - ", timestamp, level, source).unwrap();
		}
		fn write(&mut self, s: &str) {
			::arch::puts(s);
		}
		fn end(&mut self) {
			::arch::puts("\x1b[0m\n");
		}
	}
	impl fmt::Write for Sink
	{
		fn write_str(&mut self, s: &str) -> fmt::Result {
			::arch::puts(s);
			Ok( () )
		}
	}
	impl Sink
	{
		/// Set the output colour of the formatter
		pub fn set_colour(&self, colour: Colour) {
			match colour
			{
			Colour::Default => ::arch::puts("\x1b[0m"),
			Colour::Red     => ::arch::puts("\x1b[31m"),
			Colour::Green   => ::arch::puts("\x1b[32m"),
			Colour::Yellow  => ::arch::puts("\x1b[33m"),
			Colour::Blue    => ::arch::puts("\x1b[34m"),
			Colour::Purple  => ::arch::puts("\x1b[35m"),
			Colour::Grey    => ::arch::puts("\x1b[1;30m"),
			}
		}
	}
}

mod memory
{
	use _common::*;
	use super::Level;
	use core::{fmt,ops};

	pub struct Sink
	{
		lines: ::lib::ring_buffer::RingBuf<LogMessage>,
	}
	struct LogMessage
	{
		time: ::time::TickCount,
		level: Level,
		source: &'static str,
		data: String,
	}
	impl super::Sink for Sink
	{
		fn start(&mut self, timestamp: ::time::TickCount, level: Level, source: &'static str) {
			todo!("MemorySink");
		}
		fn write(&mut self, s: &str) {
			self.lines.back_mut().unwrap().data.push_str(s);
		}
		fn end(&mut self) {
			unimplemented!();
		}
	}
}

mod video
{
	use _common::*;
	use super::Level;
	use core::{fmt,ops};
	use core::marker::PhantomData;

	pub struct Sink;

	pub struct Writer<'a>(PhantomData<&'a mut Sink>);

	impl super::Sink for Sink
	{
		fn start(&mut self, timestamp: ::time::TickCount, level: Level, source: &'static str) {
			todo!("VideoSink");
		}
		fn write(&mut self, s: &str) {
			unimplemented!();
		}
		fn end(&mut self) {
			unimplemented!();
		}
	}
}

impl Level
{
	fn to_flag(&self) -> char
	{
		match *self
		{
		Level::LevelPanic   => 'k',
		Level::LevelError   => 'e',
		Level::LevelWarning => 'w',
		Level::LevelNotice  => 'n',
		Level::LevelInfo    => 'i',
		Level::LevelLog     => 'l',
		Level::LevelDebug   => 'd',
		Level::LevelTrace   => 't',
		}
	}
	fn to_colour(&self) -> Colour
	{
		match *self
		{
		Level::LevelPanic   => Colour::Purple,
		Level::LevelError   => Colour::Red,
		Level::LevelWarning => Colour::Yellow,
		Level::LevelNotice  => Colour::Green,
		Level::LevelLog     => Colour::Blue,
		Level::LevelTrace   => Colour::Grey,
		_ => Colour::Default,
		}
	}
}

impl fmt::Display for Level
{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "{}", self.to_flag())
	}
}

impl<'a> LoggingFormatter<'a>
{
	/// Create a new logging formatter
	pub fn new(level: Level, modname: &'static str) -> LoggingFormatter<'static>
	{
		let mut rv = LoggingFormatter {
				_irq_handle: ::arch::sync::hold_interrupts(),
				lock_handle: S_LOGGING_LOCK.lock()
			};
		let ts = ::time::ticks();
		rv.foreach(|x| x.start(ts, level, modname));
		rv
	}

	fn foreach<Fcn: FnMut(&mut Sink)>(&mut self, mut f: Fcn)
	{
		f(&mut self.lock_handle.serial);
		self.lock_handle.memory.as_mut().map(|x| f(x));
		self.lock_handle.video .as_mut().map(|x| f(x));
	}
}

impl<'a> fmt::Write for LoggingFormatter<'a>
{
	fn write_str(&mut self, s: &str) -> fmt::Result
	{
		self.foreach(|x| x.write(s));
		Ok( () )
	}
}
impl<'a> ::core::ops::Drop for LoggingFormatter<'a>
{
	fn drop(&mut self)
	{
		self.foreach(|x| x.end());
	}
}

impl<'a,T:'a> HexDump<'a,T>
{
	/// Return the wrapped type as a &[u8]
	fn byteslice(&self) -> &[u8]
	{
		let size = ::core::mem::size_of::<T>();
		unsafe {
			::core::mem::transmute(::core::raw::Slice {
				data: self.0 as *const T as *const u8,
				len: size,
			})
		}
	}
}

impl<'a,T:'a> fmt::Debug for HexDump<'a,T>
{
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{
		for (idx,v) in self.byteslice().iter().enumerate()
		{
			try!(write!(f, "{:02x} ", *v));
			if idx % 16 == 15 {
				try!(write!(f, "| "));
			}
		}
		Ok( () )
	}
}

//pub fn hex_dump_block(label: &str, data: &[u8])
//{
//	let mut pos = 0;
//	while pos + 16 <= data.len()
//	{
//		log_debug!("{} {:p}: {:?}  {:?}", label, &data[pos], HexDump(&data[pos .. pos+8]), HexDump(&data[pos+8 .. pos+16]));
//	}
//	if pos == data.len()
//	{
//	}
//	else if pos + 8 >= data.len()
//	{
//		//log_debug!("{} {:p}: {:?}", label, &data[pos], HexDump(&data[pos ..]));
//	}
//	else
//	{
//		//log_debug!("{} {:p}: {:?}  {:?}", label, &data[pos], HexDump(&data[pos .. pos+8]), HexDump(&data[pos+8 ..]));
//	}
//}

#[doc(hidden)]
/// Returns true if the passed combination of module and level is enabled
pub fn enabled(level: Level, modname: &str) -> bool
{
	match modname
	{
	"kernel::memory::heap" => (level < Level::LevelDebug),	// Heap only prints higher than debug
	"kernel::memory::phys" => (level < Level::LevelTrace),	// PMM only prints >Trace
	_ => true,
	}
}

#[doc(hidden)]
/// Returns a logging formatter
pub fn getstream(level: Level, modname: &'static str) -> LoggingFormatter
{
	assert!( enabled(level, modname) );
	LoggingFormatter::new(level, modname)
}

// vim: ft=rust

<|endoftext|>