<commit_before>extern crate serde_json;

#[macro_use]
mod spec;
mod block;
mod view;

use std::borrow::Borrow;
use std::ops::Deref;

use time::Timespec;

use ::crypto::{Hash, hash};
use ::messages::{Precommit, Message, AnyTx, ServiceTx};
use ::storage::{StorageValue, Patch, Database, Fork, Error, Map, List};
use config::view::{StoredConfiguration};

pub use self::block::Block;
pub use self::view::View;

pub trait Blockchain: Sized + Clone + Send + Sync + 'static
    where Self: Deref<Target = <Self as Blockchain>::Database>
{
    type View: View<<<Self as Blockchain>::Database as Database>::Fork, Transaction=Self::Transaction>;
    type Database: Database;
    type Transaction: Message + StorageValue;

    fn last_hash(&self) -> Result<Option<Hash>, Error> {
        self.view().heights().last()
    }

    fn last_block(&self) -> Result<Option<Block>, Error> {
        let view = self.view();
        Ok(match view.heights().last()? {
            Some(hash) => Some(view.blocks().get(&hash)?.unwrap()),
            None => None,
        })
    }

    fn verify_tx(tx: &Self::Transaction) -> bool;
    fn state_hash(fork: &Self::View) -> Result<Hash, Error>;
    fn execute(fork: &Self::View, tx: &Self::Transaction) -> Result<(), Error>;
    // FIXME make private
    fn execute_service_tx(_: &Self::View, _: &ServiceTx) -> Result<(), Error> {
        unimplemented!();
    }

    // TODO use Iterator to avoid memory allocations?
    fn create_patch(&self,
                    height: u64,
                    round: u32,
                    time: Timespec,
                    txs: &[(Hash, AnyTx<Self::Transaction>)])
                    -> Result<(Hash, Vec<Hash>, Patch), Error> {
        // Get last hash
        let last_hash = self.last_hash()?.unwrap_or_else(|| hash(&[]));
        // Create fork
        let fork = self.view();
        // Save & execute transactions
        let mut tx_hashes = Vec::new();
        for &(hash, ref tx) in txs {

            match *tx {
                AnyTx::Application(ref tx) => Self::execute(&fork, tx)?,
                AnyTx::Service(ref tx) => Self::execute_service_tx(&fork, tx)?,
            }

            fork.transactions()
                .put(&hash, tx.clone())
                .unwrap();
            fork.block_txs(height)
                .append(hash)
                .unwrap();
            tx_hashes.push(hash);
        }
        // Get tx hash
        let tx_hash = fork.block_txs(height).root_hash()?;
        // Get state hash
        let state_hash = Self::state_hash(&fork)?;
        // Create block
        let block = Block::new(height, round, time, &last_hash, &tx_hash, &state_hash);
        // Eval block hash
        let block_hash = block.hash();
        // Update height
        // TODO: check that height == propose.height
        fork.heights().append(block_hash).is_ok();
        // Save block
        fork.blocks().put(&block_hash, block).is_ok();
        Ok((block_hash, tx_hashes, fork.changes()))
    }

    fn get_initial_configuration (&mut self) -> Option<StoredConfiguration>;
    fn get_configuration_at_height (&mut self, height: u64) -> Option<StoredConfiguration>;

    fn commit<'a, I: Iterator<Item = &'a Precommit>>(&self,
                                                     block_hash: Hash,
                                                     patch: &Patch,
                                                     precommits: I)
                                                     -> Result<(), Error> {
        let patch = {
            let view = self.view();
            view.merge(patch);

            for precommit in precommits {
                view.precommits(&block_hash).append(precommit.clone())?;
            }

            view.changes()
        };

        self.merge(&patch)
    }

    fn view(&self) -> Self::View {
        Self::View::from_fork(self.borrow().fork())
    }

    fn merge(&self, patch: &Patch) -> Result<(), Error> {
        self.deref().merge(patch)
    }
}
<commit_msg>refactoring<commit_after>extern crate serde_json;

#[macro_use]
mod spec;
mod block;
mod view;

use std::borrow::Borrow;
use std::ops::Deref;

use time::Timespec;

use ::crypto::{Hash, hash};
use ::messages::{Precommit, Message, AnyTx, ServiceTx};
use ::storage::{StorageValue, Patch, Database, Fork, Error, Map, List};
use config::view::{StoredConfiguration};

pub use self::block::Block;
pub use self::view::View;

pub trait Blockchain: Sized + Clone + Send + Sync + 'static
    where Self: Deref<Target = <Self as Blockchain>::Database>
{
    type View: View<<<Self as Blockchain>::Database as Database>::Fork, Transaction=Self::Transaction>;
    type Database: Database;
    type Transaction: Message + StorageValue;

    fn last_hash(&self) -> Result<Option<Hash>, Error> {
        self.view().heights().last()
    }

    fn last_block(&self) -> Result<Option<Block>, Error> {
        let view = self.view();
        Ok(match view.heights().last()? {
            Some(hash) => Some(view.blocks().get(&hash)?.unwrap()),
            None => None,
        })
    }

    fn verify_tx(tx: &Self::Transaction) -> bool;
    fn state_hash(fork: &Self::View) -> Result<Hash, Error>;
    fn execute(fork: &Self::View, tx: &Self::Transaction) -> Result<(), Error>;
    // FIXME make private
    fn execute_service_tx(_: &Self::View, _: &ServiceTx) -> Result<(), Error> {
        unimplemented!();
    }

    // TODO use Iterator to avoid memory allocations?
    fn create_patch(&self,
                    height: u64,
                    round: u32,
                    time: Timespec,
                    txs: &[(Hash, AnyTx<Self::Transaction>)])
                    -> Result<(Hash, Vec<Hash>, Patch), Error> {
        // Get last hash
        let last_hash = self.last_hash()?.unwrap_or_else(|| hash(&[]));
        // Create fork
        let fork = self.view();
        // Save & execute transactions
        let mut tx_hashes = Vec::new();
        for &(hash, ref tx) in txs {

            match *tx {
                AnyTx::Application(ref tx) => Self::execute(&fork, tx)?,
                AnyTx::Service(ref tx) => Self::execute_service_tx(&fork, tx)?,
            }

            fork.transactions()
                .put(&hash, tx.clone())
                .unwrap();
            fork.block_txs(height)
                .append(hash)
                .unwrap();
            tx_hashes.push(hash);

        }
        // Get tx hash
        let tx_hash = fork.block_txs(height).root_hash()?;
        // Get state hash
        let state_hash = Self::state_hash(&fork)?;
        // Create block
        let block = Block::new(height, round, time, &last_hash, &tx_hash, &state_hash);
        // Eval block hash
        let block_hash = block.hash();
        // Update height
        // TODO: check that height == propose.height
        fork.heights().append(block_hash).is_ok();
        // Save block
        fork.blocks().put(&block_hash, block).is_ok();
        Ok((block_hash, tx_hashes, fork.changes()))
    }

    fn get_initial_configuration (&mut self) -> Option<StoredConfiguration>;
    fn get_configuration_at_height (&mut self, height: u64) -> Option<StoredConfiguration>;

    fn commit<'a, I: Iterator<Item = &'a Precommit>>(&self,
                                                     block_hash: Hash,
                                                     patch: &Patch,
                                                     precommits: I)
                                                     -> Result<(), Error> {
        let patch = {
            let view = self.view();
            view.merge(patch);

            for precommit in precommits {
                view.precommits(&block_hash).append(precommit.clone())?;
            }

            view.changes()
        };

        self.merge(&patch)
    }

    fn view(&self) -> Self::View {
        Self::View::from_fork(self.borrow().fork())
    }

    fn merge(&self, patch: &Patch) -> Result<(), Error> {
        self.deref().merge(patch)
    }
}
<|endoftext|>


<commit_before>use failure::{Error, Fail};
use std::env;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use tempfile::TempDir;

#[derive(Debug, Fail)]
pub enum CompileError {
    #[fail(display = "File not found: {}", _0)]
    FileNotFound(String),
    #[fail(display = "Clang reported error: {}", _0)]
    Execution { stdout: String, stderr: String },
    #[fail(display = "Lucetc error: {}", _0)]
    Lucetc {
        #[cause]
        e: Error,
    },
    #[fail(display = "IO error: {}", _0)]
    IO {
        #[cause]
        e: std::io::Error,
    },
}

impl From<std::io::Error> for CompileError {
    fn from(e: std::io::Error) -> CompileError {
        CompileError::IO { e }
    }
}

impl CompileError {
    pub fn check(output: Output, print: bool) -> Result<(), Self> {
        if print {
            std::io::stdout().write_all(&output.stdout).unwrap();
            std::io::stderr().write_all(&output.stderr).unwrap();
        }
        if output.status.success() {
            Ok(())
        } else {
            Err(CompileError::Execution {
                stdout: String::from_utf8_lossy(&output.stdout).to_string(),
                stderr: String::from_utf8_lossy(&output.stderr).to_string(),
            })
        }
    }
}

fn wasi_sdk_clang() -> PathBuf {
    let mut base = PathBuf::from(env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned()));
    base.push("bin");
    base.push("clang");
    base
}

pub struct Compile {
    input: PathBuf,
    cflags: Vec<String>,
    print_output: bool,
}

pub trait CompileOpts {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S);
    fn with_cflag<S: AsRef<str>>(self, cflag: S) -> Self;

    fn include<S: AsRef<str>>(&mut self, include: S);
    fn with_include<S: AsRef<str>>(self, include: S) -> Self;
}

impl CompileOpts for Compile {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S) {
        self.cflags.push(cflag.as_ref().to_owned());
    }

    fn with_cflag<S: AsRef<str>>(mut self, cflag: S) -> Self {
        self.cflag(cflag);
        self
    }

    fn include<S: AsRef<str>>(&mut self, include: S) {
        self.cflags.push(format!("-I{}", include.as_ref()));
    }

    fn with_include<S: AsRef<str>>(mut self, include: S) -> Self {
        self.include(include);
        self
    }
}

impl Compile {
    pub fn new<P: AsRef<Path>>(input: P) -> Self {
        Compile {
            input: PathBuf::from(input.as_ref()),
            cflags: Vec::new(),
            print_output: false,
        }
    }

    pub fn print_output(&mut self, print: bool) {
        self.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn compile<P: AsRef<Path>>(&self, output: P) -> Result<(), CompileError> {
        let clang = wasi_sdk_clang();
        if !clang.exists() {
            Err(CompileError::FileNotFound(
                clang.to_string_lossy().into_owned(),
            ))?;
        }
        if !self.input.exists() {
            Err(CompileError::FileNotFound(
                self.input.to_string_lossy().into_owned(),
            ))?;
        }
        let mut cmd = Command::new(clang);
        cmd.arg("-c");
        cmd.arg(self.input.clone());
        cmd.arg("-o");
        cmd.arg(output.as_ref());
        for cflag in self.cflags.iter() {
            cmd.arg(cflag);
        }
        let run = cmd.output().expect("clang executable exists");
        CompileError::check(run, self.print_output)
    }
}

pub struct Link {
    input: Vec<PathBuf>,
    cflags: Vec<String>,
    ldflags: Vec<String>,
    print_output: bool,
}

impl Link {
    pub fn new<P: AsRef<Path>>(input: &[P]) -> Self {
        Link {
            input: input.iter().map(|p| PathBuf::from(p.as_ref())).collect(),
            cflags: vec![],
            ldflags: vec![],
            print_output: false,
        }
        .with_ldflag("--no-threads")
    }

    pub fn print_output(&mut self, print: bool) {
        self.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn link<P: AsRef<Path>>(&self, output: P) -> Result<(), CompileError> {
        let clang = wasi_sdk_clang();
        if !clang.exists() {
            Err(CompileError::FileNotFound(
                clang.to_string_lossy().into_owned(),
            ))?;
        }
        let mut cmd = Command::new(clang);
        for input in self.input.iter() {
            if !input.exists() {
                Err(CompileError::FileNotFound(
                    input.to_string_lossy().into_owned(),
                ))?;
            }
            cmd.arg(input.clone());
        }
        cmd.arg("-o");
        cmd.arg(output.as_ref());
        for cflag in self.cflags.iter() {
            cmd.arg(cflag);
        }
        for ldflag in self.ldflags.iter() {
            cmd.arg(format!("-Wl,{}", ldflag));
        }
        let run = cmd.output().expect("clang executable exists");
        CompileError::check(run, self.print_output)
    }
}

pub trait AsLink {
    fn as_link(&mut self) -> &mut Link;
}

impl AsLink for Link {
    fn as_link(&mut self) -> &mut Link {
        self
    }
}

pub trait LinkOpts {
    fn ldflag<S: AsRef<str>>(&mut self, ldflag: S);
    fn with_ldflag<S: AsRef<str>>(self, ldflag: S) -> Self;

    fn export<S: AsRef<str>>(&mut self, export: S);
    fn with_export<S: AsRef<str>>(self, export: S) -> Self;
}

impl<T: AsLink> LinkOpts for T {
    fn ldflag<S: AsRef<str>>(&mut self, ldflag: S) {
        self.as_link().ldflags.push(ldflag.as_ref().to_owned());
    }

    fn with_ldflag<S: AsRef<str>>(mut self, ldflag: S) -> Self {
        self.ldflag(ldflag);
        self
    }

    fn export<S: AsRef<str>>(&mut self, export: S) {
        self.as_link()
            .ldflags
            .push(format!("--export={}", export.as_ref()));
    }

    fn with_export<S: AsRef<str>>(mut self, export: S) -> Self {
        self.export(export);
        self
    }
}

impl<T: AsLink> CompileOpts for T {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S) {
        self.as_link().cflags.push(cflag.as_ref().to_owned());
    }

    fn with_cflag<S: AsRef<str>>(mut self, cflag: S) -> Self {
        self.cflag(cflag);
        self
    }

    fn include<S: AsRef<str>>(&mut self, include: S) {
        self.as_link()
            .cflags
            .push(format!("-I{}", include.as_ref()));
    }

    fn with_include<S: AsRef<str>>(mut self, include: S) -> Self {
        self.include(include);
        self
    }
}

pub struct Lucetc {
    link: Link,
    lucetc: lucetc::Lucetc,
    tmpdir: TempDir,
    wasm_file: PathBuf,
}

impl Lucetc {
    pub fn new<P: AsRef<Path>>(input: &[P]) -> Self {
        let link = Link::new(input);
        let tmpdir = TempDir::new().expect("temporary directory creation failed");
        let wasm_file = tmpdir.path().join("out.wasm");
        let lucetc = lucetc::Lucetc::new(&wasm_file);
        Lucetc {
            link,
            lucetc,
            tmpdir,
            wasm_file,
        }
    }

    pub fn print_output(mut self, print: bool) -> Self {
        self.link.print_output = print;
        self
    }

    pub fn build<P: AsRef<Path>>(self, output: P) -> Result<(), CompileError> {
        self.link.link(&self.wasm_file)?;
        self.lucetc
            .shared_object_file(output.as_ref())
            .map_err(|e| CompileError::Lucetc { e })?;
        Ok(self.tmpdir.close()?)
    }
}

impl AsLink for Lucetc {
    fn as_link(&mut self) -> &mut Link {
        &mut self.link
    }
}

impl lucetc::AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut lucetc::Lucetc {
        &mut self.lucetc
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::TempDir;
    #[test]
    fn wasi_sdk_installed() {
        let clang = wasi_sdk_clang();
        assert!(clang.exists(), "clang executable exists");
    }

    fn test_file(name: &str) -> PathBuf {
        let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        p.push("test");
        p.push(name);
        assert!(p.exists(), "test file does not exist");
        p
    }

    #[test]
    fn compile_a() {
        let tmp = TempDir::new().expect("create temporary directory");

        let compiler = Compile::new(test_file("a.c"));

        let objfile = tmp.path().join("a.o");

        compiler.compile(objfile.clone()).expect("compile a.c");

        assert!(objfile.exists(), "object file created");

        let mut linker = Link::new(&[objfile]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");

        let wasmfile = tmp.path().join("a.wasm");

        linker.link(wasmfile.clone()).expect("link a.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_b() {
        let tmp = TempDir::new().expect("create temporary directory");

        let compiler = Compile::new(test_file("b.c"));

        let objfile = tmp.path().join("b.o");

        compiler.compile(objfile.clone()).expect("compile b.c");

        assert!(objfile.exists(), "object file created");

        let mut linker = Link::new(&[objfile]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");
        linker.ldflag("--allow-undefined");

        let wasmfile = tmp.path().join("b.wasm");

        linker.link(wasmfile.clone()).expect("link b.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_a_and_b() {
        let tmp = TempDir::new().expect("create temporary directory");

        let mut linker = Link::new(&[test_file("a.c"), test_file("b.c")]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");

        let wasmfile = tmp.path().join("ab.wasm");

        linker.link(wasmfile.clone()).expect("link ab.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_to_lucet() {
        let tmp = TempDir::new().expect("create temporary directory");

        let mut lucetc = Lucetc::new(&[test_file("a.c"), test_file("b.c")]);
        lucetc.cflag("-nostartfiles");
        lucetc.ldflag("--no-entry");

        let so_file = tmp.path().join("ab.so");

        lucetc.build(&so_file).expect("compile ab.so");

        assert!(so_file.exists(), "so file created");
    }
}
<commit_msg>[lucet-wasi-sdk] refine API and be more verbose with commands<commit_after>use failure::{Error, Fail};
use std::env;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use tempfile::TempDir;

#[derive(Debug, Fail)]
pub enum CompileError {
    #[fail(display = "File not found: {}", _0)]
    FileNotFound(String),
    #[fail(display = "Clang reported error: {}", _0)]
    Execution { stdout: String, stderr: String },
    #[fail(display = "Lucetc error: {}", _0)]
    Lucetc {
        #[cause]
        e: Error,
    },
    #[fail(display = "IO error: {}", _0)]
    IO {
        #[cause]
        e: std::io::Error,
    },
}

impl From<std::io::Error> for CompileError {
    fn from(e: std::io::Error) -> CompileError {
        CompileError::IO { e }
    }
}

impl CompileError {
    pub fn check(output: Output, print: bool) -> Result<(), Self> {
        if print {
            std::io::stdout().write_all(&output.stdout).unwrap();
            std::io::stderr().write_all(&output.stderr).unwrap();
        }
        if output.status.success() {
            Ok(())
        } else {
            Err(CompileError::Execution {
                stdout: String::from_utf8_lossy(&output.stdout).to_string(),
                stderr: String::from_utf8_lossy(&output.stderr).to_string(),
            })
        }
    }
}

fn wasi_sdk_clang() -> PathBuf {
    let mut base = PathBuf::from(env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned()));
    base.push("bin");
    base.push("clang");
    base
}

pub struct Compile {
    input: PathBuf,
    cflags: Vec<String>,
    print_output: bool,
}

pub trait CompileOpts {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S);
    fn with_cflag<S: AsRef<str>>(self, cflag: S) -> Self;

    fn include<S: AsRef<Path>>(&mut self, include: S);
    fn with_include<S: AsRef<Path>>(self, include: S) -> Self;
}

impl CompileOpts for Compile {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S) {
        self.cflags.push(cflag.as_ref().to_owned());
    }

    fn with_cflag<S: AsRef<str>>(mut self, cflag: S) -> Self {
        self.cflag(cflag);
        self
    }

    fn include<S: AsRef<Path>>(&mut self, include: S) {
        self.cflags
            .push(format!("-I{}", include.as_ref().display()));
    }

    fn with_include<S: AsRef<Path>>(mut self, include: S) -> Self {
        self.include(include);
        self
    }
}

impl Compile {
    pub fn new<P: AsRef<Path>>(input: P) -> Self {
        Compile {
            input: PathBuf::from(input.as_ref()),
            cflags: Vec::new(),
            print_output: false,
        }
    }

    pub fn print_output(&mut self, print: bool) {
        self.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn compile<P: AsRef<Path>>(&self, output: P) -> Result<(), CompileError> {
        let clang = wasi_sdk_clang();
        if !clang.exists() {
            Err(CompileError::FileNotFound(
                clang.to_string_lossy().into_owned(),
            ))?;
        }
        if !self.input.exists() {
            Err(CompileError::FileNotFound(
                self.input.to_string_lossy().into_owned(),
            ))?;
        }
        let mut cmd = Command::new(clang);
        cmd.arg("-c");
        cmd.arg(self.input.clone());
        cmd.arg("-o");
        cmd.arg(output.as_ref());
        for cflag in self.cflags.iter() {
            cmd.arg(cflag);
        }
        if self.print_output {
            println!("running: {:?}", cmd);
        }
        let run = cmd.output().expect("clang executable exists");
        CompileError::check(run, self.print_output)
    }
}

pub struct Link {
    input: Vec<PathBuf>,
    cflags: Vec<String>,
    ldflags: Vec<String>,
    print_output: bool,
}

impl Link {
    pub fn new<P: AsRef<Path>>(input: &[P]) -> Self {
        Link {
            input: input.iter().map(|p| PathBuf::from(p.as_ref())).collect(),
            cflags: vec![],
            ldflags: vec![],
            print_output: false,
        }
        .with_ldflag("--no-threads")
    }

    pub fn print_output(&mut self, print: bool) {
        self.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn link<P: AsRef<Path>>(&self, output: P) -> Result<(), CompileError> {
        let clang = wasi_sdk_clang();
        if !clang.exists() {
            Err(CompileError::FileNotFound(
                clang.to_string_lossy().into_owned(),
            ))?;
        }
        let mut cmd = Command::new(clang);
        for input in self.input.iter() {
            if !input.exists() {
                Err(CompileError::FileNotFound(
                    input.to_string_lossy().into_owned(),
                ))?;
            }
            cmd.arg(input.clone());
        }
        cmd.arg("-o");
        cmd.arg(output.as_ref());
        for cflag in self.cflags.iter() {
            cmd.arg(cflag);
        }
        for ldflag in self.ldflags.iter() {
            cmd.arg(format!("-Wl,{}", ldflag));
        }
        if self.print_output {
            println!("running: {:?}", cmd);
        }
        let run = cmd.output().expect("clang executable exists");
        CompileError::check(run, self.print_output)
    }
}

pub trait AsLink {
    fn as_link(&mut self) -> &mut Link;
}

impl AsLink for Link {
    fn as_link(&mut self) -> &mut Link {
        self
    }
}

pub trait LinkOpts {
    fn ldflag<S: AsRef<str>>(&mut self, ldflag: S);
    fn with_ldflag<S: AsRef<str>>(self, ldflag: S) -> Self;

    fn export<S: AsRef<str>>(&mut self, export: S);
    fn with_export<S: AsRef<str>>(self, export: S) -> Self;
}

impl<T: AsLink> LinkOpts for T {
    fn ldflag<S: AsRef<str>>(&mut self, ldflag: S) {
        self.as_link().ldflags.push(ldflag.as_ref().to_owned());
    }

    fn with_ldflag<S: AsRef<str>>(mut self, ldflag: S) -> Self {
        self.ldflag(ldflag);
        self
    }

    fn export<S: AsRef<str>>(&mut self, export: S) {
        self.as_link()
            .ldflags
            .push(format!("--export={}", export.as_ref()));
    }

    fn with_export<S: AsRef<str>>(mut self, export: S) -> Self {
        self.export(export);
        self
    }
}

impl<T: AsLink> CompileOpts for T {
    fn cflag<S: AsRef<str>>(&mut self, cflag: S) {
        self.as_link().cflags.push(cflag.as_ref().to_owned());
    }

    fn with_cflag<S: AsRef<str>>(mut self, cflag: S) -> Self {
        self.cflag(cflag);
        self
    }

    fn include<S: AsRef<Path>>(&mut self, include: S) {
        self.as_link()
            .cflags
            .push(format!("-I{}", include.as_ref().display()));
    }

    fn with_include<S: AsRef<Path>>(mut self, include: S) -> Self {
        self.include(include);
        self
    }
}

pub struct Lucetc {
    link: Link,
    lucetc: lucetc::Lucetc,
    tmpdir: TempDir,
    wasm_file: PathBuf,
}

impl Lucetc {
    pub fn new<P: AsRef<Path>>(input: &[P]) -> Self {
        let link = Link::new(input);
        let tmpdir = TempDir::new().expect("temporary directory creation failed");
        let wasm_file = tmpdir.path().join("out.wasm");
        let lucetc = lucetc::Lucetc::new(&wasm_file);
        Lucetc {
            link,
            lucetc,
            tmpdir,
            wasm_file,
        }
    }

    pub fn print_output(&mut self, print: bool) {
        self.link.print_output = print;
    }

    pub fn with_print_output(mut self, print: bool) -> Self {
        self.print_output(print);
        self
    }

    pub fn build<P: AsRef<Path>>(self, output: P) -> Result<(), CompileError> {
        self.link.link(&self.wasm_file)?;
        self.lucetc
            .shared_object_file(output.as_ref())
            .map_err(|e| CompileError::Lucetc { e })?;
        Ok(self.tmpdir.close()?)
    }
}

impl AsLink for Lucetc {
    fn as_link(&mut self) -> &mut Link {
        &mut self.link
    }
}

impl lucetc::AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut lucetc::Lucetc {
        &mut self.lucetc
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::TempDir;
    #[test]
    fn wasi_sdk_installed() {
        let clang = wasi_sdk_clang();
        assert!(clang.exists(), "clang executable exists");
    }

    fn test_file(name: &str) -> PathBuf {
        let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
        p.push("test");
        p.push(name);
        assert!(p.exists(), "test file does not exist");
        p
    }

    #[test]
    fn compile_a() {
        let tmp = TempDir::new().expect("create temporary directory");

        let compiler = Compile::new(test_file("a.c"));

        let objfile = tmp.path().join("a.o");

        compiler.compile(objfile.clone()).expect("compile a.c");

        assert!(objfile.exists(), "object file created");

        let mut linker = Link::new(&[objfile]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");

        let wasmfile = tmp.path().join("a.wasm");

        linker.link(wasmfile.clone()).expect("link a.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_b() {
        let tmp = TempDir::new().expect("create temporary directory");

        let compiler = Compile::new(test_file("b.c"));

        let objfile = tmp.path().join("b.o");

        compiler.compile(objfile.clone()).expect("compile b.c");

        assert!(objfile.exists(), "object file created");

        let mut linker = Link::new(&[objfile]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");
        linker.ldflag("--allow-undefined");

        let wasmfile = tmp.path().join("b.wasm");

        linker.link(wasmfile.clone()).expect("link b.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_a_and_b() {
        let tmp = TempDir::new().expect("create temporary directory");

        let mut linker = Link::new(&[test_file("a.c"), test_file("b.c")]);
        linker.cflag("-nostartfiles");
        linker.ldflag("--no-entry");

        let wasmfile = tmp.path().join("ab.wasm");

        linker.link(wasmfile.clone()).expect("link ab.wasm");

        assert!(wasmfile.exists(), "wasm file created");
    }

    #[test]
    fn compile_to_lucet() {
        let tmp = TempDir::new().expect("create temporary directory");

        let mut lucetc = Lucetc::new(&[test_file("a.c"), test_file("b.c")]);
        lucetc.cflag("-nostartfiles");
        lucetc.ldflag("--no-entry");

        let so_file = tmp.path().join("ab.so");

        lucetc.build(&so_file).expect("compile ab.so");

        assert!(so_file.exists(), "so file created");
    }
}
<|endoftext|>


<commit_before>#![deny(warnings, rust_2018_idioms)]
#![feature(async_await)]

use futures_util::future;
use futures_util::stream::StreamExt;

/// how many signals to handle before exiting
const STOP_AFTER: u64 = 10;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // tokio_signal provides a convenience builder for Ctrl+C
    // this even works cross-platform: linux and windows!
    //
    // `fn ctrl_c()` produces a `Future` of the actual stream-initialisation
    // so first we await until the signal is ready.
    let endless_stream = tokio_signal::ctrl_c().await?;
    // don't keep going forever: convert the endless stream to a bounded one.
    let limited_stream = endless_stream.take(STOP_AFTER);

    // how many Ctrl+C have we received so far?
    let mut counter = 0;

    println!(
        "This program is now waiting for you to press Ctrl+C {0} times.
  * If running via `cargo run --example ctrl-c`, Ctrl+C also kills it, \
    due to https://github.com/rust-lang-nursery/rustup.rs/issues/806
  * If running the binary directly, the Ctrl+C is properly trapped.
    Terminate by repeating Ctrl+C {0} times, or ahead of time by \
    opening a second terminal and issuing `pkill -sigkil ctrl-c`",
        STOP_AFTER
    );

    // Stream::for_each is a powerful primitive provided by the Futures crate.
    // It turns a Stream into a Future that completes after all stream-items
    // have been completed, or the first time the closure returns an error
    let future = limited_stream
        .map(|result| result.expect("failed to get event"))
        .for_each(|()| {
            // Note how we manipulate the counter without any fancy synchronisation.
            // The borrowchecker realises there can't be any conflicts, so the closure
            // can just capture it.
            counter += 1;
            println!(
                "Ctrl+C received {} times! {} more before exit",
                counter,
                STOP_AFTER - counter
            );

            // return a result to continue handling the stream
            future::ready(())
        });

    // Up until now, we haven't really DONE anything, just prepared
    // now it's time to actually the results!
    future.await;

    println!("Stream ended, quiting the program.");
    Ok(())
}
<commit_msg>signal: update instructions in Ctrl-C example (#1270)<commit_after>#![deny(warnings, rust_2018_idioms)]
#![feature(async_await)]

use futures_util::future;
use futures_util::stream::StreamExt;

/// how many signals to handle before exiting
const STOP_AFTER: u64 = 10;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // tokio_signal provides a convenience builder for Ctrl+C
    // this even works cross-platform: linux and windows!
    //
    // `fn ctrl_c()` produces a `Future` of the actual stream-initialisation
    // so first we await until the signal is ready.
    let endless_stream = tokio_signal::ctrl_c().await?;
    // don't keep going forever: convert the endless stream to a bounded one.
    let limited_stream = endless_stream.take(STOP_AFTER);

    // how many Ctrl+C have we received so far?
    let mut counter = 0;

    println!(
        "This program is now waiting for you to press Ctrl+C {0} times. \
         Terminate by repeating Ctrl+C {0} times, or ahead of time by opening \
         a second terminal and issuing `pkill -sigkil ctrl-c`.",
        STOP_AFTER
    );

    // Stream::for_each is a powerful primitive provided by the Futures crate.
    // It turns a Stream into a Future that completes after all stream-items
    // have been completed, or the first time the closure returns an error
    let future = limited_stream
        .map(|result| result.expect("failed to get event"))
        .for_each(|()| {
            // Note how we manipulate the counter without any fancy synchronisation.
            // The borrowchecker realises there can't be any conflicts, so the closure
            // can just capture it.
            counter += 1;
            println!(
                "Ctrl+C received {} times! {} more before exit",
                counter,
                STOP_AFTER - counter
            );

            // return a result to continue handling the stream
            future::ready(())
        });

    // Up until now, we haven't really DONE anything, just prepared
    // now it's time to actually the results!
    future.await;

    println!("Stream ended, quiting the program.");
    Ok(())
}
<|endoftext|>


<commit_before>extern mod syntax;
extern mod rustc;

extern mod extra;

use rustc::{front, metadata, driver, middle};

use syntax::parse;
use syntax::ast;
use syntax::ast_map;

use std::os;
use std::local_data;
use extra::json::ToJson;

macro_rules! logi{
	()=>(println(file!()+":"+line!().to_str()+": "));
	($a:expr)=>(println(file!()+":"+line!().to_str()+": "+$a.to_str()));
	($a:expr,$b:expr)=>(println(file!()+":"+line!().to_str()+": "+$a.to_str()+$b.to_str()));
	($a:expr,$b:expr,$c:expr)=>(println(file!()+":"+line!().to_str()+": "+$a.to_str+$b.to_str(),$c.to_str()))

}

pub static ctxtkey: local_data::Key<@DocContext> = &local_data::Key;

struct DocContext {
    crate: @ast::crate,
    tycx: middle::ty::ctxt,
    sess: driver::session::Session
}

/// Parses, resolves the given crate
fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {

    let parsesess = parse::new_parse_sess(None);
    let sessopts = @driver::session::options {
        binary: @"rustdoc",
        maybe_sysroot: Some(@std::os::self_exe_path().get().pop()),
        addl_lib_search_paths: @mut libs,
        .. copy (*rustc::driver::session::basic_options())
    };

    let diagnostic_handler = syntax::diagnostic::mk_handler(None);
    let span_diagnostic_handler =
        syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);

    let mut sess = driver::driver::build_session_(sessopts, parsesess.cm,
                                                  syntax::diagnostic::emit,
                                                  span_diagnostic_handler);

    let (crate, tycx) = driver::driver::compile_upto(sess, sessopts.cfg.clone(),
                                                     &driver::driver::file_input(cpath.clone()),
                                                     driver::driver::cu_typeck, None);

	let c=crate.unwrap();
	let t=tycx.unwrap();
    DocContext { crate: c, tycx: t, sess: sess }
}

trait MyToStr {
	fn myToStr(&self)->~str;
}
impl<A:MyToStr,B:MyToStr> MyToStr for (A,B) {
	fn myToStr(&self)->~str{ let &(ref a, ref b)=self; ~"("+a.myToStr()+~","+b.myToStr()+~")"}
}
impl MyToStr for ast::mutability {
	fn myToStr(&self)->~str{
		match(self) {
			&m_mutbl=>~"m_mutbl",
//			m_imm=>~"m_imm",
//			m_const=>~"m_const",
		}
	}
}
/*
impl<'self> MyToStr for &ast::mutability<'self> {
	fn myToStr(&'self self)->~str{
		match(self) {
			&m_mutbl=>~"m_mutbl",
//			m_imm=>~"m_imm",
//			m_const=>~"m_const",
		}
	}
}
*/

impl MyToStr for int {
	fn myToStr(&self)->~str{self.to_str()}
}
impl MyToStr for ast::expr {
	fn myToStr(&self)->~str {
		"{"+"id:"+self.id.myToStr()+",node:"+self.node.myToStr()+",span:"+self.span.myToStr()+"}"
	}
}
impl<T:MyToStr> MyToStr for Option<T> {
	fn myToStr(&self)->~str{
		match(self) {
			&Some(ref x)=>~"Some("+x.myToStr()+")",
			&None=>~"None"
		}
	}
}
impl MyToStr for syntax::codemap::BytePos {
	fn myToStr(&self)->~str {
		let &syntax::codemap::BytePos(x)=self; x.to_str()
	}
}
impl MyToStr for @syntax::codemap::ExpnInfo {
	fn myToStr(&self)->~str{~"ExpnInfo{TODO}"}
}
impl MyToStr for syntax::codemap::ExpnInfo {
	fn myToStr(&self)->~str{~"ExpnInfo{TODO}"}
}

fn fMyToStr(x:&syntax::codemap::ExpnInfo)->~str {
	x.myToStr()
}

impl MyToStr for @ast::expr {
	fn myToStr(&self)->~str {
		~"{"+~"id:"+self.id.to_str()+~",node:"+self.node.myToStr()+~",span"+self.span.myToStr()+~"}"
	}
}

impl MyToStr for syntax::codemap::span {
	fn myToStr(&self)->~str {
		~"{"+~"lo:"+self.lo.myToStr()+~",hi:"+self.hi.myToStr()+~",expn_info:"+self.expn_info.myToStr()+~"}"
	}
}

impl MyToStr for ast::item_ {
	fn myToStr(&self)->~str{
		use syntax::ast::*;
		match (self) {
			&item_static(ref t,ref m,ref e)=> ~"item_static"+(*m,*e).myToStr()+~")",
			&item_fn(ref decl, ref purity,ref AbiSet, ref Generics, ref refblk)=>
				~"item_fn()",
			&item_mod(ref m) => ~"item_mod()",
			&item_foreign_mod(ref m) => ~"item_foreign_mod()",
			&item_ty(ref _ty,ref g) => ~"item_ty()",
			&item_enum(ref e,ref g) => ~"item_enum()",
			&item_struct(ref sd,ref g) => ~"item_struct()",
			&item_trait(ref g, ref trs,ref tms)=>~"item_trait",
			&item_impl(ref g, ref opt_tr, ref ty, ref ms)=>~"item_impl",
			&item_mac(ref m)=>~"item_mac()",

		}
	}
}
impl MyToStr for ast::expr_ {
	fn myToStr(&self)->~str {
		match(self) {
			_ =>~"expr_(TODO)" // all the complexity of statements is handled here
		}
	}
}

fn my_visit(c:&ast::crate){

	for c.node.module.items.iter().advance|x|{
		println(x.node.myToStr());
	}
}

fn main() {
    use extra::getopts::*;
    use std::hashmap::HashMap;

    let args = os::args();

    let opts = ~[
        optmulti("L")
    ];

    let matches = getopts(args.tail(), opts).get();
    let libs = opt_strs(&matches, "L").map(|s| Path(*s));

    let ctxt = @get_ast_and_resolve(&Path(matches.free[0]), libs);
    debug!("defmap:");
    for ctxt.tycx.def_map.iter().advance |(k, v)| {
        debug!("%?: %?", k, v);
    }
    local_data::set(ctxtkey, ctxt);
//	println(ctxt.to_str());
	my_visit(ctxt.crate);
/*
    let mut v = @mut RustdocVisitor::new();
    v.visit(ctxt.crate);

    let mut crate = v.clean();
    println(crate.to_json().to_str());
*/
}
<commit_msg>discovered fmt(%?,..), made dump! macro, very handy,obseletes much debug..<commit_after>extern mod syntax;
extern mod rustc;

extern mod extra;

use rustc::{front, metadata, driver, middle};

use syntax::parse;
use syntax::ast;
use syntax::ast_map;

use std::os;
use std::local_data;
use extra::json::ToJson;

macro_rules! logi{
	()=>(println(file!()+":"+line!().to_str()+": "));
	($a:expr)=>(println(file!()+":"+line!().to_str()+": "+$a.to_str()));
	($a:expr,$b:expr)=>(println(file!()+":"+line!().to_str()+": "+$a.to_str()+$b.to_str()));
	($a:expr,$b:expr,$c:expr)=>(println(file!()+":"+line!().to_str()+": "+$a.to_str+$b.to_str(),$c.to_str()))

}
macro_rules! dump{ ($a:expr)=>(logi!(fmt!("%?",$a));)}

pub static ctxtkey: local_data::Key<@DocContext> = &local_data::Key;

struct DocContext {
    crate: @ast::crate,
    tycx: middle::ty::ctxt,
    sess: driver::session::Session
}

/// Parses, resolves the given crate
fn get_ast_and_resolve(cpath: &Path, libs: ~[Path]) -> DocContext {

    let parsesess = parse::new_parse_sess(None);
    let sessopts = @driver::session::options {
        binary: @"rustdoc",
        maybe_sysroot: Some(@std::os::self_exe_path().get().pop()),
        addl_lib_search_paths: @mut libs,
        .. copy (*rustc::driver::session::basic_options())
    };

    let diagnostic_handler = syntax::diagnostic::mk_handler(None);
    let span_diagnostic_handler =
        syntax::diagnostic::mk_span_handler(diagnostic_handler, parsesess.cm);

    let mut sess = driver::driver::build_session_(sessopts, parsesess.cm,
                                                  syntax::diagnostic::emit,
                                                  span_diagnostic_handler);

    let (crate, tycx) = driver::driver::compile_upto(sess, sessopts.cfg.clone(),
                                                     &driver::driver::file_input(cpath.clone()),
                                                     driver::driver::cu_typeck, None);

	let c=crate.unwrap();
	let t=tycx.unwrap();
    DocContext { crate: c, tycx: t, sess: sess }
}

trait MyToStr {
	fn myToStr(&self)->~str;
}
impl<A:MyToStr,B:MyToStr> MyToStr for (A,B) {
	fn myToStr(&self)->~str{ let &(ref a, ref b)=self; ~"("+a.myToStr()+~","+b.myToStr()+~")"}
}
impl MyToStr for ast::mutability {
	fn myToStr(&self)->~str{
		match(self) {
			&m_mutbl=>~"m_mutbl",
//			m_imm=>~"m_imm",
//			m_const=>~"m_const",
		}
	}
}
/*
impl<'self> MyToStr for &ast::mutability<'self> {
	fn myToStr(&'self self)->~str{
		match(self) {
			&m_mutbl=>~"m_mutbl",
//			m_imm=>~"m_imm",
//			m_const=>~"m_const",
		}
	}
}
*/

impl MyToStr for int {
	fn myToStr(&self)->~str{self.to_str()}
}
impl MyToStr for ast::expr {
	fn myToStr(&self)->~str {
		"{"+"id:"+self.id.myToStr()+",node:"+self.node.myToStr()+",span:"+self.span.myToStr()+"}"
	}
}
impl<T:MyToStr> MyToStr for Option<T> {
	fn myToStr(&self)->~str{
		match(self) {
			&Some(ref x)=>~"Some("+x.myToStr()+")",
			&None=>~"None"
		}
	}
}
impl MyToStr for syntax::codemap::BytePos {
	fn myToStr(&self)->~str {
		let &syntax::codemap::BytePos(x)=self; x.to_str()
	}
}
impl MyToStr for @syntax::codemap::ExpnInfo {
	fn myToStr(&self)->~str{~"ExpnInfo{TODO}"}
}
impl MyToStr for syntax::codemap::ExpnInfo {
	fn myToStr(&self)->~str{~"ExpnInfo{TODO}"}
}

impl MyToStr for syntax::ast::ident {
	fn myToStr(&self)->~str{~"ident{"+~"name:"+self.name.myToStr()+~"}"}
}
impl MyToStr for syntax::ast::Name {
	fn myToStr(&self)->~str{
		self.to_str()
	}
}

fn fMyToStr(x:&syntax::codemap::ExpnInfo)->~str {
	x.myToStr()
}

impl MyToStr for @ast::expr {
	fn myToStr(&self)->~str {
		~"{"+~"id:"+self.id.to_str()+~",node:"+self.node.myToStr()+~",span"+self.span.myToStr()+~"}"
	}
}

impl MyToStr for syntax::codemap::span {
	fn myToStr(&self)->~str {
		~"{"+~"lo:"+self.lo.myToStr()+~",hi:"+self.hi.myToStr()+~",expn_info:"+self.expn_info.myToStr()+~"}"
	}
}

impl MyToStr for ast::item_ {
	fn myToStr(&self)->~str{
		use syntax::ast::*;
		match (self) {
			&item_static(ref t,ref m,ref e)=> ~"item_static"+(*m,*e).myToStr(),
			&item_fn(ref decl, ref purity,ref AbiSet, ref Generics, ref refblk)=>
				~"item_fn()",
			&item_mod(ref m) => ~"item_mod()",
			&item_foreign_mod(ref m) => ~"item_foreign_mod()",
			&item_ty(ref _ty,ref g) => ~"item_ty()",
			&item_enum(ref e,ref g) => ~"item_enum()",
			&item_struct(ref sd,ref g) => ~"item_struct()",
			&item_trait(ref g, ref trs,ref tms)=>~"item_trait",
			&item_impl(ref g, ref opt_tr, ref ty, ref ms)=>~"item_impl",
			&item_mac(ref m)=>~"item_mac()",

		}
	}
}
impl MyToStr for ast::expr_ {
	fn myToStr(&self)->~str {
		match(self) {
			_ =>~"expr_(TODO)" // all the complexity of statements is handled here
		}
	}
}
impl MyToStr for ast::item {
	fn myToStr(&self)->~str {
		~"item{"+
			~"ident:"+self.ident.myToStr()+
			~",node:"+self.node.myToStr()+
			~",span:"+self.span.myToStr()+
		~"}"
	}
}

impl MyToStr for ast::_mod{
	fn myToStr(&self)->~str{
		~"_mod{"+~"view_items:"+array_myToStr(self.view_items)+~",items"+arrayOfSharedPtr_myToStr(self.items)+~"}"
	}
}
impl<T: MyToStr> MyToStr for syntax::codemap::spanned<T> {
	fn myToStr(&self)->~str{
		~"spanned<>{"+~"node:"+self.node.myToStr()+~",span:"+self.span.myToStr()+~"}"
	}
}
impl MyToStr for ast::crate_ {
	fn myToStr(&self)->~str{
		~"crate_{"+~"module:"+self.module.myToStr()
		+~",attrs:?,config:?"
		+~"}"
	}
}
impl MyToStr for ast::view_item {
	fn myToStr(&self)->~str {
		~"view_item{"+
		~"node:"+self.node.myToStr()+
		~",attrs:?"+
		~",vis:?"+
		~",span:"+self.span.myToStr()+
		"}"
	}
}
impl MyToStr for ast::view_item_ {
	fn myToStr(&self)->~str {
		use syntax::ast::*;
		match (self) {
		&view_item_extern_mod(ref ident, ref mis, ref nid)=>~"view_item_extern_mod()",
		&view_item_use(ref vps)=>~"view_item_use()"
		}
	}
}
/*
impl<T:MyToStr> MyToStr for ~[T]{
	fn myToStr(&self)->~str {
		self.iter().transform( |x|{ x.myToStr()}).collect()
	}
}
*/
fn arrayOfSharedPtr_myToStr<T:MyToStr>(a:&[@T])->~str {
	let mut acc:~str=~"[";
	for a.iter().advance |x| {acc=acc.append( (*x).myToStr() )+","};
	acc=acc.append(~"]");
	acc
//	a.iter().map( |x|{ x.myToStr()}).to_str()
}
fn array_myToStr<T:MyToStr>(a:&[T])->~str {
	let mut acc:~str=~"[";
	for a.iter().advance |x| {acc=acc.append( x.myToStr() )+","};
	acc=acc.append(~"]");
	acc
//	a.iter().map( |x|{ x.myToStr()}).to_str()
}

fn my_visit(c:&ast::crate){
	for c.node.module.items.iter().advance|x|{
		println(x.myToStr());
	}
}

fn main() {
    use extra::getopts::*;
    use std::hashmap::HashMap;

    let args = os::args();

    let opts = ~[
        optmulti("L")
    ];

    let matches = getopts(args.tail(), opts).get();
    let libs = opt_strs(&matches, "L").map(|s| Path(*s));

    let ctxt = @get_ast_and_resolve(&Path(matches.free[0]), libs);
    debug!("defmap:");
//    for ctxt.tycx.def_map.iter().advance |(k, v)| {
//        debug!("%?: %?", k, v);
//    }
    local_data::set(ctxtkey, ctxt);
//	println(ctxt.to_str());
	//my_visit(ctxt.crate);
//	println(ctxt.crate.myToStr());
	dump!(ctxt.crate);
/*
    let mut v = @mut RustdocVisitor::new();
    v.visit(ctxt.crate);

    let mut crate = v.clean();
    println(crate.to_json().to_str());
*/
}
<|endoftext|>


<commit_before>#![crate_id = "kernewbie#0.0"]
#![allow(ctypes)]
#![no_std]

mod zero;

static VGA_ADDRESS: uint = 0xb8000;
static VGA_WIDTH: u16 = 80;
//static VGA_HEIGHT: u16 = 80;

static mut fg_color: Color = Green;
static mut bg_color: Color = Black;

enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

fn range(lo: uint, hi: uint, it: |uint| -> ()) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

fn make_vgaentry(c: u8, fg: Color, bg: Color) -> u16 {
  let color = fg as u16 | (bg as u16 << 4);
  return c as u16 | (color << 8);
}

pub fn putchar(x: u16, y: u16, c: u8) {
  let idx: uint = (y * VGA_WIDTH * 2 + x * 2) as uint;
  unsafe {
    *((VGA_ADDRESS + idx) as *mut u16) = make_vgaentry(c, fg_color, bg_color);
  }
}

unsafe fn clear_screen(background: Color) {
    range(0, 80*25, |i| {
        *((0xb8000 + i * 2) as *mut u16) = (background as u16) << 12;
    });
}

#[no_mangle]
pub unsafe fn main() {
    clear_screen(Black);
    putchar(0, 0, 79);
    putchar(1, 0, 108);
    putchar(2, 0, 97);
    putchar(3, 0, 114);
    putchar(4, 0, 32);
    putchar(5, 0, 109);
    putchar(6, 0, 117);
    putchar(7, 0, 110);
    putchar(8, 0, 100);
    putchar(9, 0, 111);
}
<commit_msg>update crate_id<commit_after>#![crate_id = "rustic#0.0"]
#![allow(ctypes)]
#![no_std]

mod zero;

static VGA_ADDRESS: uint = 0xb8000;
static VGA_WIDTH: u16 = 80;
//static VGA_HEIGHT: u16 = 80;

static mut fg_color: Color = Green;
static mut bg_color: Color = Black;

enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yellow      = 14,
    White       = 15,
}

fn range(lo: uint, hi: uint, it: |uint| -> ()) {
    let mut iter = lo;
    while iter < hi {
        it(iter);
        iter += 1;
    }
}

fn make_vgaentry(c: u8, fg: Color, bg: Color) -> u16 {
  let color = fg as u16 | (bg as u16 << 4);
  return c as u16 | (color << 8);
}

pub fn putchar(x: u16, y: u16, c: u8) {
  let idx: uint = (y * VGA_WIDTH * 2 + x * 2) as uint;
  unsafe {
    *((VGA_ADDRESS + idx) as *mut u16) = make_vgaentry(c, fg_color, bg_color);
  }
}

unsafe fn clear_screen(background: Color) {
    range(0, 80*25, |i| {
        *((0xb8000 + i * 2) as *mut u16) = (background as u16) << 12;
    });
}

#[no_mangle]
pub unsafe fn main() {
    clear_screen(Black);
    putchar(0, 0, 79);
    putchar(1, 0, 108);
    putchar(2, 0, 97);
    putchar(3, 0, 114);
    putchar(4, 0, 32);
    putchar(5, 0, 109);
    putchar(6, 0, 117);
    putchar(7, 0, 110);
    putchar(8, 0, 100);
    putchar(9, 0, 111);
}
<|endoftext|>


<commit_before>extern crate time;

use std::io::File; /* input/output */
use std::string::String;
use std::os;
use core::CPU;
use std::io::timer;

mod core;

static MAX_RAM : uint = 0xFFF;
static START_RAM :uint = 0x200;

static INSTRUCTIONS_PER_SEC : u64 = 500;
static CYCLES_CHECK : u64 = 20;

/* Reads a ROM file and returns a vector containing
 * its bytes if successful. Otherwise an error string
 * if the file is too large or IoError is raised */
fn read_rom(file_path: String) -> Result<Vec<u8>,String> {

    match File::open(&Path::new(file_path)).read_to_end() {

        Ok(rom_contents) =>  {
            /* Programs start at address 0x200, in original implementation
             * 0x000 - 0x1FF reserved for VM, just pad start of mem with
             * 0s in this case */
            let mem = Vec::from_elem(START_RAM, 0u8) + rom_contents;
            let size = mem.len();

            if size <= MAX_RAM {
                    Ok(mem)
            } else { /* Memory read in from game ROM is too large */
                Err(format!("game image is too large
                    ({} bytes), must be a maximum of {} bytes"
                    ,size , MAX_RAM - START_RAM).to_string())
            }
        },
        /* Error reading file */
        Err(e) => Err(e.detail.unwrap_or("".to_string()))
    }
}

fn get_time_ms() -> u64 { time::precise_time_ns()/1000000 }

fn wait_for_next_cycle(old_time:u64, instructions:u64, ins_per_sec:u64 )  {
    let current_time = get_time_ms();
    if old_time < current_time {
        timer::sleep(((current_time - old_time) * instructions) / ins_per_sec);
    }
}

fn run_program(mut chip8 :core::CPU, cycle_max: u64, ins_per_sec: u64)  {

    loop {
        let start_timer = get_time_ms();
        for _ in range(0, cycle_max) {
            chip8.perform_cycle();
        }
        wait_for_next_cycle(start_timer, cycle_max, ins_per_sec);
    }
}

fn main() {
    let mut args = os::args();

   let file_name = match args.remove(1)  {
       Some(name) => name,
       None => fail!("No file name specified")
   };

    //debug!("reading file {}",file_name);

    let memory = match read_rom(file_name) {
        Ok(mem) => mem,
        Err(e) => fail!("{}",e)
    };

    assert!(memory.len() <=  MAX_RAM);

    run_program(core::CPU::new(memory), CYCLES_CHECK, INSTRUCTIONS_PER_SEC);
}

<commit_msg>updated timing algorithm<commit_after>extern crate time;

use std::io::File; /* input/output */
use std::string::String;
use std::os;
use core::CPU;
use std::io::timer;

mod core;

static MAX_RAM : uint = 0xFFF;
static START_RAM :uint = 0x200;

static INSTRUCTIONS_PER_SEC : u64 = 500;
static CYCLES_CHECK : u64 = 5;

/* Reads a ROM file and returns a vector containing
 * its bytes if successful. Otherwise an error string
 * if the file is too large or IoError is raised */
fn read_rom(file_path: String) -> Result<Vec<u8>,String> {

    match File::open(&Path::new(file_path)).read_to_end() {

        Ok(rom_contents) =>  {
            /* Programs start at address 0x200, in original implementation
             * 0x000 - 0x1FF reserved for VM, just pad start of mem with
             * 0s in this case */
            let mem = Vec::from_elem(START_RAM, 0u8) + rom_contents;
            let size = mem.len();

            if size <= MAX_RAM {
                    Ok(mem)
            } else { /* Memory read in from game ROM is too large */
                Err(format!("game image is too large
                    ({} bytes), must be a maximum of {} bytes"
                    ,size , MAX_RAM - START_RAM).to_string())
            }
        },
        /* Error reading file */
        Err(e) => Err(e.detail.unwrap_or("".to_string()))
    }
}

fn wait_for_next_cycle(old_time:u64, instructions:u64, ins_per_sec:u64 )  {
    println!("waiting {:u}",old_time);
    let current_time = time::precise_time_ns();
    if old_time < current_time {
        let expired_ns = current_time - old_time;
        let overall_duration_ns = (1000000000 * instructions)/ins_per_sec; /*Calculate duration instruction should take */
        if overall_duration_ns > expired_ns { /* ensure that duration has expired until next cycles begin */
            timer::sleep((overall_duration_ns - expired_ns)/1000000);
       }
    }
}

fn run_program(mut chip8 :core::CPU, cycle_max: u64, ins_per_sec: u64)  {

    loop {
        let start_timer = time::precise_time_ns();
        for _ in range(0, cycle_max) {
            chip8.perform_cycle();
        }
        wait_for_next_cycle(start_timer, cycle_max, ins_per_sec);
    }
}

fn main() {
    let mut args = os::args();

   let file_name = match args.remove(1)  {
       Some(name) => name,
       None => fail!("No file name specified")
   };

    //debug!("reading file {}",file_name);

    let memory = match read_rom(file_name) {
        Ok(mem) => mem,
        Err(e) => fail!("{}",e)
    };

    assert!(memory.len() <=  MAX_RAM);

    run_program(core::CPU::new(memory), CYCLES_CHECK, INSTRUCTIONS_PER_SEC);
}

<|endoftext|>


<commit_before>//! Asynchronous streams.
//!
//! This module contains:
//!
//! - The [`Stream`] trait, for objects that can asynchronously produce a
//!   sequence of values.
//! - The [`StreamExt`] and [`TryStreamExt`] trait, which provides adapters for
//!   chaining and composing streams.
//! - Top-level stream constructors like [`iter`](iter()) which creates a
//!   stream from an iterator.

#[cfg(feature = "alloc")]
pub use futures_core::stream::{BoxStream, LocalBoxStream};
pub use futures_core::stream::{FusedStream, Stream, TryStream};

// Extension traits and combinators

#[allow(clippy::module_inception)]
mod stream;
pub use self::stream::{
    Chain, Collect, Concat, Cycle, Enumerate, Filter, FilterMap, FlatMap, Flatten, Fold, ForEach,
    Fuse, Inspect, Map, Next, NextIf, NextIfEq, Peek, Peekable, Scan, SelectNextSome, Skip,
    SkipWhile, StreamExt, StreamFuture, Take, TakeUntil, TakeWhile, Then, TryFold, TryForEach,
    Unzip, Zip,
};

#[cfg(feature = "std")]
pub use self::stream::CatchUnwind;

#[cfg(feature = "alloc")]
pub use self::stream::Chunks;

#[cfg(feature = "alloc")]
pub use self::stream::ReadyChunks;

#[cfg(feature = "sink")]
#[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
pub use self::stream::Forward;

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::stream::{BufferUnordered, Buffered, ForEachConcurrent, TryForEachConcurrent};

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "sink")]
#[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
#[cfg(feature = "alloc")]
pub use self::stream::{ReuniteError, SplitSink, SplitStream};

mod try_stream;
pub use self::try_stream::{
    try_unfold, AndThen, ErrInto, InspectErr, InspectOk, IntoStream, MapErr, MapOk, OrElse,
    TryCollect, TryConcat, TryFilter, TryFilterMap, TryFlatten, TryNext, TrySkipWhile,
    TryStreamExt, TryTakeWhile, TryUnfold,
};

#[cfg(feature = "io")]
#[cfg_attr(docsrs, doc(cfg(feature = "io")))]
#[cfg(feature = "std")]
pub use self::try_stream::IntoAsyncRead;

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::try_stream::{TryBufferUnordered, TryBuffered};

// Primitive streams

mod iter;
pub use self::iter::{iter, Iter};

mod repeat;
pub use self::repeat::{repeat, Repeat};

mod repeat_with;
pub use self::repeat_with::{repeat_with, RepeatWith};

mod empty;
pub use self::empty::{empty, Empty};

mod once;
pub use self::once::{once, Once};

mod pending;
pub use self::pending::{pending, Pending};

mod poll_fn;
pub use self::poll_fn::{poll_fn, PollFn};

mod select;
pub use self::select::{select, Select};

mod unfold;
pub use self::unfold::{unfold, Unfold};

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
mod futures_ordered;
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::futures_ordered::FuturesOrdered;

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub mod futures_unordered;
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
#[doc(inline)]
pub use self::futures_unordered::FuturesUnordered;

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub mod select_all;
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::select_all::{select_all, SelectAll};

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
mod abortable;
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use crate::abortable::{AbortHandle, AbortRegistration, Abortable, Aborted};
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use abortable::abortable;

// Just a helper function to ensure the streams we're returning all have the
// right implementations.
pub(crate) fn assert_stream<T, S>(stream: S) -> S
where
    S: Stream<Item = T>,
{
    stream
}
<commit_msg>Add #[doc(inline)] to export of SelectAll (#2442)<commit_after>//! Asynchronous streams.
//!
//! This module contains:
//!
//! - The [`Stream`] trait, for objects that can asynchronously produce a
//!   sequence of values.
//! - The [`StreamExt`] and [`TryStreamExt`] trait, which provides adapters for
//!   chaining and composing streams.
//! - Top-level stream constructors like [`iter`](iter()) which creates a
//!   stream from an iterator.

#[cfg(feature = "alloc")]
pub use futures_core::stream::{BoxStream, LocalBoxStream};
pub use futures_core::stream::{FusedStream, Stream, TryStream};

// Extension traits and combinators

#[allow(clippy::module_inception)]
mod stream;
pub use self::stream::{
    Chain, Collect, Concat, Cycle, Enumerate, Filter, FilterMap, FlatMap, Flatten, Fold, ForEach,
    Fuse, Inspect, Map, Next, NextIf, NextIfEq, Peek, Peekable, Scan, SelectNextSome, Skip,
    SkipWhile, StreamExt, StreamFuture, Take, TakeUntil, TakeWhile, Then, TryFold, TryForEach,
    Unzip, Zip,
};

#[cfg(feature = "std")]
pub use self::stream::CatchUnwind;

#[cfg(feature = "alloc")]
pub use self::stream::Chunks;

#[cfg(feature = "alloc")]
pub use self::stream::ReadyChunks;

#[cfg(feature = "sink")]
#[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
pub use self::stream::Forward;

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::stream::{BufferUnordered, Buffered, ForEachConcurrent, TryForEachConcurrent};

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "sink")]
#[cfg_attr(docsrs, doc(cfg(feature = "sink")))]
#[cfg(feature = "alloc")]
pub use self::stream::{ReuniteError, SplitSink, SplitStream};

mod try_stream;
pub use self::try_stream::{
    try_unfold, AndThen, ErrInto, InspectErr, InspectOk, IntoStream, MapErr, MapOk, OrElse,
    TryCollect, TryConcat, TryFilter, TryFilterMap, TryFlatten, TryNext, TrySkipWhile,
    TryStreamExt, TryTakeWhile, TryUnfold,
};

#[cfg(feature = "io")]
#[cfg_attr(docsrs, doc(cfg(feature = "io")))]
#[cfg(feature = "std")]
pub use self::try_stream::IntoAsyncRead;

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::try_stream::{TryBufferUnordered, TryBuffered};

// Primitive streams

mod iter;
pub use self::iter::{iter, Iter};

mod repeat;
pub use self::repeat::{repeat, Repeat};

mod repeat_with;
pub use self::repeat_with::{repeat_with, RepeatWith};

mod empty;
pub use self::empty::{empty, Empty};

mod once;
pub use self::once::{once, Once};

mod pending;
pub use self::pending::{pending, Pending};

mod poll_fn;
pub use self::poll_fn::{poll_fn, PollFn};

mod select;
pub use self::select::{select, Select};

mod unfold;
pub use self::unfold::{unfold, Unfold};

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
mod futures_ordered;
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use self::futures_ordered::FuturesOrdered;

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub mod futures_unordered;
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
#[doc(inline)]
pub use self::futures_unordered::FuturesUnordered;

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub mod select_all;
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
#[doc(inline)]
pub use self::select_all::{select_all, SelectAll};

#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
mod abortable;
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use crate::abortable::{AbortHandle, AbortRegistration, Abortable, Aborted};
#[cfg(not(futures_no_atomic_cas))]
#[cfg(feature = "alloc")]
pub use abortable::abortable;

// Just a helper function to ensure the streams we're returning all have the
// right implementations.
pub(crate) fn assert_stream<T, S>(stream: S) -> S
where
    S: Stream<Item = T>,
{
    stream
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! FreeBSD-specific raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]
#![rustc_deprecated(since = "1.8.0",
                    reason = "these type aliases are no longer supported by \
                              the standard library, the `libc` crate on \
                              crates.io should be used instead for the correct \
                              definitions")]
#![allow(deprecated)]

#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;

#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;

#[doc(inline)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub use self::arch::{stat, time_t};

#[cfg(target_arch = "x86")]
mod arch {
    use super::{off_t, dev_t, ino_t, mode_t, nlink_t, blksize_t, blkcnt_t, fflags_t};
    use os::raw::c_long;
    use os::unix::raw::{uid_t, gid_t};

    #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

    #[repr(C)]
    #[derive(Clone)]
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub struct stat {
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_dev: dev_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_ino: ino_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_mode: mode_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_nlink: nlink_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_uid: uid_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_gid: gid_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_rdev: dev_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_atime: time_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_atime_nsec: c_long,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_mtime: time_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_mtime_nsec: c_long,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_ctime: time_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_ctime_nsec: c_long,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_size: off_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_blocks: blkcnt_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_blksize: blksize_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_flags: fflags_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_gen: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_lspare: i32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_birthtime: time_t,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_birthtime_nsec: c_long,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub __unused: [u8; 8],
    }
}

#[cfg(target_arch = "x86_64")]
mod arch {
    use super::{off_t, dev_t, ino_t, mode_t, nlink_t, blksize_t, blkcnt_t, fflags_t};
    use os::raw::c_long;
    use os::unix::raw::{uid_t, gid_t};

    #[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

    #[repr(C)]
    #[derive(Clone)]
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub struct stat {
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_dev: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_ino: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_mode: u16,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_nlink: u16,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_uid: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_gid: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_rdev: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_atime: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_atime_nsec: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_mtime: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_mtime_nsec: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_ctime: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_ctime_nsec: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_size: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_blocks: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_blksize: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_flags: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_gen: u32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_lspare: i32,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_birthtime: i64,
        #[stable(feature = "raw_ext", since = "1.1.0")]
        pub st_birthtime_nsec: i64,
    }
}

<commit_msg>unfork freebsd stat definitions, fixes x86<commit_after>// Copyright 2015 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.

//! FreeBSD-specific raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]
#![rustc_deprecated(since = "1.8.0",
                    reason = "these type aliases are no longer supported by \
                              the standard library, the `libc` crate on \
                              crates.io should be used instead for the correct \
                              definitions")]
#![allow(deprecated)]

#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

#[unstable(feature = "pthread_t", issue = "29791")] pub type pthread_t = usize;

#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_dev: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ino: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mode: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_nlink: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_uid: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gid: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_rdev: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime_nsec: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_size: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blocks: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blksize: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_flags: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gen: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_lspare: i32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_birthtime: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_birthtime_nsec: i64,
}
<|endoftext|>


<commit_before>use arch::cpu::{self,DescriptorExtra,Dtr,InterruptDescriptor,Regs,Tss};
use arch::debug;
use arch::mmu;
use core::mem;
use once::{self,Once};
use prelude::*;
use process;
use ptr::{self,Align};
use singleton::{DropSingleton,Singleton};

extern {
    static GDT: u8;
    static mut GDT_TSS: DescriptorExtra;
    static mut TSS: Tss;
    static TSSEnd: u8;
    static mut IDT: [InterruptDescriptor; 49];
    static IDTEnd: u8;
    static interrupt_handlers: [u64; 49];
    static interrupt_handlers_end: u8;
}

lazy_static! {
    static ref IRQ_HANDLERS: Vec<Singleton<Box<Fn() + 'static>>> = {
        let mut v: Vec<Singleton<Box<Fn() + 'static>>> = Vec::new();
        for _ in 0..16 {
            v.push(Singleton::new());
        }

        v
    };
}

const PIC1: u16 = 0x20; // IO base address for master PIC
const PIC2: u16 = 0xA0; // IO base address for slave PIC
const PIC1_COMMAND: u16 = PIC1;
const PIC1_DATA: u16 = PIC1 + 1;
const PIC2_COMMAND: u16 = PIC2;
const PIC2_DATA: u16 = PIC2 + 1;

pub type DropIrqHandler = DropSingleton<Box<Fn()>>;

pub fn register_irq_handler<T: Fn() + 'static>(irq: usize, handler: T) -> DropIrqHandler  {
    if let Some(singleton) = IRQ_HANDLERS.get(irq) {
        singleton.register(Box::new(handler))
    } else {
        panic!("irq must be between 0 and {}", IRQ_HANDLERS.len())
    }
}

macro_rules! assert_size {
	($value:expr, $expected_end:expr) => ({
        let value = $value;
        let expected_end = $expected_end;
        let expected_len = ptr::bytes_between(value as *const _ as *const u8, expected_end as *const _ as *const u8);
        assert_eq!(mem::size_of_val(value), expected_len);
    })
}

macro_rules! assert_len {
	($slice:expr, $expected_end:expr) => ({
        let slice = $slice;
        let expected_end = $expected_end;
        let expected_len = ptr::bytes_between(slice.as_ptr() as *const u8, expected_end as *const u8) / mem::size_of_val(&*slice.as_ptr());
        assert_eq!(expected_len, slice.len());
    })
}

pub fn init_once() {
    static ONCE: Once = once::ONCE_INIT;
    ONCE.call_once(|| unsafe {
        assert_size!(&TSS, &TSSEnd);
        assert_len!(&interrupt_handlers, &interrupt_handlers_end);
        assert_len!(&IDT, &IDTEnd);
        assert_eq!(104, mem::size_of::<Tss>());
        assert_eq!(10, mem::size_of::<Dtr>());
        assert!(Align::is_aligned(mem::size_of::<Regs>(), 16));

        let tss_selector = ptr::bytes_between(&GDT, &GDT_TSS as *const _ as *const u8) as u16;
        assert_eq!(0x38, tss_selector);

        let tss_ptr = &TSS as *const _ as usize;
        GDT_TSS = Default::default();
        GDT_TSS.limit_low = mem::size_of::<Tss>() as u16;
        GDT_TSS.base_low = tss_ptr as u16;
        GDT_TSS.base_mid = (tss_ptr >> 16) as u8;
        GDT_TSS.base_high = (tss_ptr >> 24) as u8;
        GDT_TSS.base_extra = (tss_ptr >> 32) as u32;
        GDT_TSS.access = 0x89;
        GDT_TSS.limit_high_and_flags = 0x10;

        TSS = Default::default();
        TSS.iopm_len = mem::size_of::<Tss>() as u16;

        cpu::ltr(tss_selector);

        for (handler_ptr, desc) in interrupt_handlers.iter().zip(IDT.iter_mut()) {
            let handler_ptr: u64 = *handler_ptr;
            *desc = Default::default();
            desc.offset_low = handler_ptr as u16;
            desc.offset_high = (handler_ptr >> 16) as u16;
            desc.offset_extra = (handler_ptr >> 32) as u32;
            desc.type_attr = 0x8e; // 32-bit interrupt gate: 0x8E ( P=1, DPL=00b, S=0, type=1110b => type_attr=1000_1110b=0x8E)
            desc.selector = 0x08;
        }

        let idtr = Dtr {
            limit: mem::size_of_val(&IDT) as u16,
            base: IDT.as_ptr() as u64
        };

        cpu::lidt(&idtr);

        const ICW1_ICW4: u8 = 0x01;         /* ICW4 (not) needed */
        const ICW1_INIT: u8 = 0x10;         /* Initialization - required! */
        const ICW4_8086: u8 = 0x01;         /* 8086/88 (MCS-80/85) mode */

        const OFFSET1: u8 = 32;
        const OFFSET2: u8 = 40;

        let a1 = cpu::inb(PIC1_DATA);                        // save masks
        let a2 = cpu::inb(PIC2_DATA);

        cpu::outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4);  // starts the initialization sequence (in cascade mode)
        cpu::outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
        cpu::outb(PIC1_DATA, OFFSET1);                 // ICW2: Master PIC vector offset
        cpu::outb(PIC2_DATA, OFFSET2);                 // ICW2: Slave PIC vector offset
        cpu::outb(PIC1_DATA, 4);                       // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
        cpu::outb(PIC2_DATA, 2);                       // ICW3: tell Slave PIC its cascade identity (0000 0010)

        cpu::outb(PIC1_DATA, ICW4_8086);
        cpu::outb(PIC2_DATA, ICW4_8086);

        cpu::outb(PIC1_DATA, a1);   // restore saved masks.
        cpu::outb(PIC2_DATA, a2);

        cpu::sti();
    });
}

pub unsafe fn set_kernel_stack(ptr: *mut u8) {
    assert!(Align::is_aligned(ptr, 16));
    TSS.rsp0 = ptr as u64;
}

#[no_mangle]
pub extern fn irq(num: usize, _: &Regs) {
    unsafe {
        const PIC_EOI: u8 = 0x20; // End-of-interrupt command code

        if num != 0 {
            if let Some(singleton) = IRQ_HANDLERS.get(num) {
                if let Some(handler) = singleton.get() {
                    handler();
                }
            }
        }

        if num >= 8 {
            cpu::outb(PIC2_COMMAND, PIC_EOI);
        }

        cpu::outb(PIC1_COMMAND, PIC_EOI);
    }
}

#[no_mangle]
pub extern fn exception(num: u8, regs: &Regs) {
    let cr2: *mut u8 = cpu::read_cr2();
    if num == 14 && process::resolve_page_fault(cr2) {
        return;
    }

    log!("exception {}: error=0x{:x}  cr2={:p}", num, regs.error, cr2);
    log!("ss:rsp={:x}:{:-16x}  cs:rip={:x}:{:-16x} rflags={:x}", regs.ss, regs.rsp, regs.cs, regs.rip, regs.rflags);
    log!("rax={:-16x} rbx={:-16x} rcx={:-16x} rdx={:-16x}", regs.rax, regs.rbx, regs.rcx, regs.rdx);
    log!("rbp={:-16x} rdi={:-16x} rsi={:-16x}", regs.rbp, regs.rdi, regs.rsi);
    log!(" r8={:-16x}  r9={:-16x} r10={:-16x} r11={:-16x}", regs.r8, regs.r9, regs.r10, regs.r11);
    log!("r12={:-16x} r12={:-16x} r14={:-16x} r15={:-16x}", regs.r12, regs.r13, regs.r14, regs.r15);
    log!("");

    if num == 14 {
        log!("page fault: {} {} in {} mode",
             if (regs.error & 1) != 0 { "protection violation" } else { "page not present" },
             if (regs.error & 2) != 0 { "writing" } else { "reading" },
             if (regs.error & 4) != 0 { "user" } else { "kernel" });

        log!("cr3 = {:x}", cpu::read_cr3());
        mmu::print_mapping(cr2);
        log!("");
    }

    unsafe { debug::print_stack_trace(regs.rsp as *const usize) };
    loop { }
}

#[no_mangle]
pub extern fn interrupt(num: u8, regs: &Regs) {
    if num < 32 {
        exception(num, regs)
    } else {
        log!("interrupt {}", num)
    }
}

#[cfg(feature = "test")]
pub mod test {
    use arch::cpu;

    test! {
        fn can_interrupt() {
            unsafe { cpu::int48() }
        }
    }
}
<commit_msg>Print the name of the process that crashed<commit_after>use arch::cpu::{self,DescriptorExtra,Dtr,InterruptDescriptor,Regs,Tss};
use arch::debug;
use arch::mmu;
use core::mem;
use once::{self,Once};
use prelude::*;
use process;
use ptr::{self,Align};
use singleton::{DropSingleton,Singleton};
use thread;

extern {
    static GDT: u8;
    static mut GDT_TSS: DescriptorExtra;
    static mut TSS: Tss;
    static TSSEnd: u8;
    static mut IDT: [InterruptDescriptor; 49];
    static IDTEnd: u8;
    static interrupt_handlers: [u64; 49];
    static interrupt_handlers_end: u8;
}

lazy_static! {
    static ref IRQ_HANDLERS: Vec<Singleton<Box<Fn() + 'static>>> = {
        let mut v: Vec<Singleton<Box<Fn() + 'static>>> = Vec::new();
        for _ in 0..16 {
            v.push(Singleton::new());
        }

        v
    };
}

const PIC1: u16 = 0x20; // IO base address for master PIC
const PIC2: u16 = 0xA0; // IO base address for slave PIC
const PIC1_COMMAND: u16 = PIC1;
const PIC1_DATA: u16 = PIC1 + 1;
const PIC2_COMMAND: u16 = PIC2;
const PIC2_DATA: u16 = PIC2 + 1;

pub type DropIrqHandler = DropSingleton<Box<Fn()>>;

pub fn register_irq_handler<T: Fn() + 'static>(irq: usize, handler: T) -> DropIrqHandler  {
    if let Some(singleton) = IRQ_HANDLERS.get(irq) {
        singleton.register(Box::new(handler))
    } else {
        panic!("irq must be between 0 and {}", IRQ_HANDLERS.len())
    }
}

macro_rules! assert_size {
	($value:expr, $expected_end:expr) => ({
        let value = $value;
        let expected_end = $expected_end;
        let expected_len = ptr::bytes_between(value as *const _ as *const u8, expected_end as *const _ as *const u8);
        assert_eq!(mem::size_of_val(value), expected_len);
    })
}

macro_rules! assert_len {
	($slice:expr, $expected_end:expr) => ({
        let slice = $slice;
        let expected_end = $expected_end;
        let expected_len = ptr::bytes_between(slice.as_ptr() as *const u8, expected_end as *const u8) / mem::size_of_val(&*slice.as_ptr());
        assert_eq!(expected_len, slice.len());
    })
}

pub fn init_once() {
    static ONCE: Once = once::ONCE_INIT;
    ONCE.call_once(|| unsafe {
        assert_size!(&TSS, &TSSEnd);
        assert_len!(&interrupt_handlers, &interrupt_handlers_end);
        assert_len!(&IDT, &IDTEnd);
        assert_eq!(104, mem::size_of::<Tss>());
        assert_eq!(10, mem::size_of::<Dtr>());
        assert!(Align::is_aligned(mem::size_of::<Regs>(), 16));

        let tss_selector = ptr::bytes_between(&GDT, &GDT_TSS as *const _ as *const u8) as u16;
        assert_eq!(0x38, tss_selector);

        let tss_ptr = &TSS as *const _ as usize;
        GDT_TSS = Default::default();
        GDT_TSS.limit_low = mem::size_of::<Tss>() as u16;
        GDT_TSS.base_low = tss_ptr as u16;
        GDT_TSS.base_mid = (tss_ptr >> 16) as u8;
        GDT_TSS.base_high = (tss_ptr >> 24) as u8;
        GDT_TSS.base_extra = (tss_ptr >> 32) as u32;
        GDT_TSS.access = 0x89;
        GDT_TSS.limit_high_and_flags = 0x10;

        TSS = Default::default();
        TSS.iopm_len = mem::size_of::<Tss>() as u16;

        cpu::ltr(tss_selector);

        for (handler_ptr, desc) in interrupt_handlers.iter().zip(IDT.iter_mut()) {
            let handler_ptr: u64 = *handler_ptr;
            *desc = Default::default();
            desc.offset_low = handler_ptr as u16;
            desc.offset_high = (handler_ptr >> 16) as u16;
            desc.offset_extra = (handler_ptr >> 32) as u32;
            desc.type_attr = 0x8e; // 32-bit interrupt gate: 0x8E ( P=1, DPL=00b, S=0, type=1110b => type_attr=1000_1110b=0x8E)
            desc.selector = 0x08;
        }

        let idtr = Dtr {
            limit: mem::size_of_val(&IDT) as u16,
            base: IDT.as_ptr() as u64
        };

        cpu::lidt(&idtr);

        const ICW1_ICW4: u8 = 0x01;         /* ICW4 (not) needed */
        const ICW1_INIT: u8 = 0x10;         /* Initialization - required! */
        const ICW4_8086: u8 = 0x01;         /* 8086/88 (MCS-80/85) mode */

        const OFFSET1: u8 = 32;
        const OFFSET2: u8 = 40;

        let a1 = cpu::inb(PIC1_DATA);                        // save masks
        let a2 = cpu::inb(PIC2_DATA);

        cpu::outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4);  // starts the initialization sequence (in cascade mode)
        cpu::outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
        cpu::outb(PIC1_DATA, OFFSET1);                 // ICW2: Master PIC vector offset
        cpu::outb(PIC2_DATA, OFFSET2);                 // ICW2: Slave PIC vector offset
        cpu::outb(PIC1_DATA, 4);                       // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
        cpu::outb(PIC2_DATA, 2);                       // ICW3: tell Slave PIC its cascade identity (0000 0010)

        cpu::outb(PIC1_DATA, ICW4_8086);
        cpu::outb(PIC2_DATA, ICW4_8086);

        cpu::outb(PIC1_DATA, a1);   // restore saved masks.
        cpu::outb(PIC2_DATA, a2);

        cpu::sti();
    });
}

pub unsafe fn set_kernel_stack(ptr: *mut u8) {
    assert!(Align::is_aligned(ptr, 16));
    TSS.rsp0 = ptr as u64;
}

#[no_mangle]
pub extern fn irq(num: usize, _: &Regs) {
    unsafe {
        const PIC_EOI: u8 = 0x20; // End-of-interrupt command code

        if num != 0 {
            if let Some(singleton) = IRQ_HANDLERS.get(num) {
                if let Some(handler) = singleton.get() {
                    handler();
                }
            }
        }

        if num >= 8 {
            cpu::outb(PIC2_COMMAND, PIC_EOI);
        }

        cpu::outb(PIC1_COMMAND, PIC_EOI);
    }
}

#[no_mangle]
pub extern fn exception(num: u8, regs: &Regs) {
    let cr2: *mut u8 = cpu::read_cr2();
    if num == 14 && process::resolve_page_fault(cr2) {
        return;
    }

    {
        let process_opt = thread::try_current_process();
        let process_name = &process_opt.as_ref().map_or("<no process>", |p| p.name());
        log!("exception {} in {}: error=0x{:x}  cr2={:p}", num, process_name, regs.error, cr2);
    }

    log!("ss:rsp={:x}:{:-16x}  cs:rip={:x}:{:-16x} rflags={:x}", regs.ss, regs.rsp, regs.cs, regs.rip, regs.rflags);
    log!("rax={:-16x} rbx={:-16x} rcx={:-16x} rdx={:-16x}", regs.rax, regs.rbx, regs.rcx, regs.rdx);
    log!("rbp={:-16x} rdi={:-16x} rsi={:-16x}", regs.rbp, regs.rdi, regs.rsi);
    log!(" r8={:-16x}  r9={:-16x} r10={:-16x} r11={:-16x}", regs.r8, regs.r9, regs.r10, regs.r11);
    log!("r12={:-16x} r12={:-16x} r14={:-16x} r15={:-16x}", regs.r12, regs.r13, regs.r14, regs.r15);
    log!("");

    if num == 14 {
        log!("page fault: {} {} in {} mode",
             if (regs.error & 1) != 0 { "protection violation" } else { "page not present" },
             if (regs.error & 2) != 0 { "writing" } else { "reading" },
             if (regs.error & 4) != 0 { "user" } else { "kernel" });

        log!("cr3 = {:x}", cpu::read_cr3());
        mmu::print_mapping(cr2);
        log!("");
    }

    unsafe { debug::print_stack_trace(regs.rsp as *const usize) };
    loop { }
}

#[no_mangle]
pub extern fn interrupt(num: u8, regs: &Regs) {
    if num < 32 {
        exception(num, regs)
    } else {
        log!("interrupt {}", num)
    }
}

#[cfg(feature = "test")]
pub mod test {
    use arch::cpu;

    test! {
        fn can_interrupt() {
            unsafe { cpu::int48() }
        }
    }
}
<|endoftext|>