<commit_before>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::create_dir_all;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::build(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
        let list = glob(&self.prefix_of_files_for_module(m)[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.prefix_of_files_for_module(owner) + "-" + &id[..] + ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
             data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<commit_msg>Implement StorageBackend::remove_file()<commit_after>use std::error::Error;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FMTResult;
use std::path::Path;
use std::path::PathBuf;
use std::vec::Vec;
use std::fs::File as FSFile;
use std::fs::remove_file;
use std::io::Read;
use std::io::Write;
use std::vec::IntoIter;

use glob::glob;
use glob::Paths;

use storage::file::File;
use storage::file_id::*;
use storage::parser::{FileHeaderParser, Parser, ParserError};

use module::Module;
use runtime::Runtime;

pub type BackendOperationResult<T = ()> = Result<T, StorageBackendError>;

pub struct StorageBackend {
    basepath: String,
    storepath: String,
}

impl StorageBackend {

    pub fn new(rt: &Runtime) -> BackendOperationResult<StorageBackend> {
        let storepath = rt.get_rtp() + "/store/";
        debug!("Trying to create {}", storepath);
        create_dir_all(&storepath).and_then(|_| {
            debug!("Creating succeeded, constructing backend instance");
            Ok(StorageBackend {
                basepath: rt.get_rtp(),
                storepath: storepath.clone(),
            })
        }).or_else(|e| {
            debug!("Creating failed, constructing error instance");
            let mut serr = StorageBackendError::build(
                "create_dir_all()",
                "Could not create store directories",
                Some(storepath)
            );
            serr.caused_by = Some(Box::new(e));
            Err(serr)
        })
    }

    fn build<M: Module>(rt: &Runtime, m: &M) -> StorageBackend {
        let path = rt.get_rtp() + m.name() + "/store";
        // TODO: Don't use "/store" but value from configuration
        debug!("Building StorageBackend for {}", path);
        StorageBackend::new(path)
    }

    fn get_file_ids(&self, m: &Module) -> Option<Vec<FileID>> {
        let list = glob(&self.prefix_of_files_for_module(m)[..]);

        if let Ok(globlist) = list {
            let mut v = vec![];
            for entry in globlist {
                if let Ok(path) = entry {
                    debug!(" - File: {:?}", path);
                    v.push(from_pathbuf(&path));
                } else {
                    // Entry is not a path
                }
            }

            Some(v)
        } else {
            None
        }
    }

    pub fn iter_ids(&self, m: &Module) -> Option<IntoIter<FileID>>
    {
        glob(&self.prefix_of_files_for_module(m)[..]).and_then(|globlist| {
            let v = globlist.filter_map(Result::ok)
                            .map(|pbuf| from_pathbuf(&pbuf))
                            .collect::<Vec<FileID>>()
                            .into_iter();
            Ok(v)
        }).ok()
    }

    pub fn iter_files<'a, HP>(&self, m: &'a Module, p: &Parser<HP>)
        -> Option<IntoIter<File<'a>>>
        where HP: FileHeaderParser
    {
        self.iter_ids(m).and_then(|ids| {
            Some(ids.filter_map(|id| self.get_file_by_id(m, &id, p))
                    .collect::<Vec<File>>()
                    .into_iter())
        })
    }

    /*
     * Write a file to disk.
     *
     * The file is moved to this function as the file won't be edited afterwards
     */
    pub fn put_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let written = write_with_parser(&f, p);
        if written.is_err() { return Err(written.err().unwrap()); }
        let string = written.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::create(&path).map(|mut file| {
            debug!("Created file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write_all()",
                            "Could not write out File contents",
                            None
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not create file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::create()",
                "Creating file on disk failed",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Update a file. We have the UUID and can find the file on FS with it and
     * then replace its contents with the contents of the passed file object
     */
    pub fn update_file<HP>(&self, f: File, p: &Parser<HP>) -> BackendOperationResult
        where HP: FileHeaderParser
    {
        let contents = write_with_parser(&f, p);
        if contents.is_err() { return Err(contents.err().unwrap()); }
        let string = contents.unwrap();

        let path = self.build_filepath(&f);
        debug!("Writing file: {}", path);
        debug!("      string: {}", string);

        FSFile::open(&path).map(|mut file| {
            debug!("Open file at '{}'", path);
            file.write_all(&string.clone().into_bytes())
                .map_err(|ioerr| {
                    debug!("Could not write file");
                    let mut err = StorageBackendError::build(
                            "File::write()",
                            "Tried to write contents of this file, though operation did not succeed",
                            Some(string)
                        );
                    err.caused_by = Some(Box::new(ioerr));
                    err
                })
        }).map_err(|writeerr| {
            debug!("Could not write file at '{}'", path);
            let mut err = StorageBackendError::build(
                "File::open()",
                "Tried to update contents of this file, though file doesn't exist",
                None
            );
            err.caused_by = Some(Box::new(writeerr));
            err
        }).and(Ok(()))
    }

    /*
     * Find a file by its ID and return it if found. Return nothing if not
     * found, of course.
     *
     * TODO: Needs refactoring, as there might be an error when reading from
     * disk OR the id just does not exist.
     */
    pub fn get_file_by_id<'a, HP>(&self, m: &'a Module, id: &FileID, p: &Parser<HP>) -> Option<File<'a>>
        where HP: FileHeaderParser
    {
        debug!("Searching for file with id '{}'", id);
        if let Ok(mut fs) = FSFile::open(self.build_filepath_with_id(m, id.clone())) {
            let mut s = String::new();
            fs.read_to_string(&mut s);
            debug!("Success reading file with id '{}'", id);
            debug!("Parsing to internal structure now");
            p.read(s).and_then(|(h, d)| Ok(File::from_parser_result(m, id.clone(), h, d))).ok()
        } else {
            debug!("No file with id '{}'", id);
            None
        }
    }

    pub fn remove_file(&self, m: &Module, file: File, checked: bool) -> BackendOperationResult {
        if checked {
            error!("Checked remove not implemented yet. I will crash now");
            unimplemented!()
        }

        debug!("Doing unchecked remove");
        info!("Going to remove file: {}", file);

        let fp = self.build_filepath(&file);
        remove_file(fp).map_err(|e| {
            let mut serr = StorageBackendError::build(
                "remove_file()",
                "File removal failed",
                Some(format!("{}", file))
            );
            serr.caused_by = Some(Box::new(e));
            serr
        })
    }

    fn build_filepath(&self, f: &File) -> String {
        self.build_filepath_with_id(f.owner(), f.id())
    }

    fn build_filepath_with_id(&self, owner: &Module, id: FileID) -> String {
        debug!("Building filepath with id");
        debug!("  basepath: '{}'", self.basepath);
        debug!(" storepath: '{}'", self.storepath);
        debug!("  id      : '{}'", id);
        self.prefix_of_files_for_module(owner) + "-" + &id[..] + ".imag"
    }

    fn prefix_of_files_for_module(&self, m: &Module) -> String {
        self.storepath.clone() + m.name()
    }

}

#[derive(Debug)]
pub struct StorageBackendError {
    pub action: String,             // The file system action in words
    pub desc: String,               // A short description
    pub data_dump: Option<String>,  // Data dump, if any
    pub caused_by: Option<Box<Error>>,  // caused from this error
}

impl StorageBackendError {
    fn new(action: String,
           desc  : String,
           data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         action,
            desc:           desc,
            data_dump:      data,
            caused_by:      None,
        }
    }

    fn build(action: &'static str,
             desc:   &'static str,
             data  : Option<String>) -> StorageBackendError
    {
        StorageBackendError {
            action:         String::from(action),
            desc:           String::from(desc),
            dataDump:       data,
            caused_by:      None,
        }
    }

}

impl Error for StorageBackendError {

    fn description(&self) -> &str {
        &self.desc[..]
    }

    fn cause(&self) -> Option<&Error> {
        self.caused_by.as_ref().map(|e| &**e)
    }

}

impl<'a> Display for StorageBackendError {
    fn fmt(&self, f: &mut Formatter) -> FMTResult {
        write!(f, "StorageBackendError[{}]: {}",
               self.action, self.desc)
    }
}

fn write_with_parser<'a, HP>(f: &File, p: &Parser<HP>) -> Result<String, StorageBackendError>
    where HP: FileHeaderParser
{
    p.write(f.contents())
        .or_else(|err| {
            let mut serr = StorageBackendError::build(
                "Parser::write()",
                "Cannot translate internal representation of file contents into on-disk representation",
                None
            );
            serr.caused_by = Some(Box::new(err));
            Err(serr)
        })
}
<|endoftext|>


<commit_before>//src: http://stackoverflow.com/a/29168659/539686
#![feature(core_intrinsics)]
//https://doc.rust-lang.org/stable/std/intrinsics/index.html

fn print_type_of<T>(_: &T) -> () {
    let type_name =
        unsafe {
            std::intrinsics::type_name::<T>()
        };
    println!("{}", type_name);
}

fn main() -> () {
    print_type_of(&32.90);           // prints "f64"
    print_type_of(&(vec!(1, 2, 4))); // prints "collections::vec::Vec<i32>"
    let x = 5; // x: i32 //src: https://doc.rust-lang.org/nightly/book/variable-bindings.html
    print_type_of(&x);
}

<commit_msg>get rustc version<commit_after>//src: http://stackoverflow.com/a/29168659/539686
#![feature(core_intrinsics)]
//https://doc.rust-lang.org/stable/std/intrinsics/index.html

use std::process::Command;
use std::str;

fn print_type_of<T>(_: &T) -> () {
    let type_name =
        unsafe {
            std::intrinsics::type_name::<T>()
        };
    println!("{}", type_name);
}

fn main() -> () {
    print_type_of(&32.90);           // prints "f64"
    print_type_of(&(vec!(1, 2, 4))); // prints "collections::vec::Vec<i32>"
    let x = 5; // x: i32 //src: https://doc.rust-lang.org/nightly/book/variable-bindings.html
    print_type_of(&x);

    //src: https://github.com/rust-lang/rust-playpen/issues/247#issuecomment-243658273

    println!("{}", str::from_utf8(&Command::new("rustc").arg("-vV").output().unwrap().stdout).unwrap());
}

<|endoftext|>


<commit_before>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use anyhow::{bail, Result};
use std::env;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

const MINIGBM_SRC: &str = "../third_party/minigbm";
const VIRGLRENDERER_SRC: &str = "../third_party/virglrenderer";

fn is_native_build() -> bool {
    env::var("HOST").unwrap() == env::var("TARGET").unwrap()
}

/// Returns the target triplet prefix for gcc commands. No prefix is required
/// for native builds.
fn get_cross_compile_prefix() -> String {
    if is_native_build() {
        return String::from("");
    }

    let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
    return format!("{}-{}-{}-", arch, os, env);
}

/// For cross-compilation with meson, we need to pick a cross-file, which
/// live in /usr/local/share/meson/cross.
fn get_meson_cross_args() -> Vec<String> {
    if is_native_build() {
        Vec::new()
    } else {
        vec![
            "--cross-file".to_string(),
            env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
        ]
    }
}

fn build_minigbm(out_dir: &Path) -> Result<()> {
    let lib_path = out_dir.join("libgbm.a");
    if lib_path.exists() {
        return Ok(());
    }

    if !Path::new(MINIGBM_SRC).join(".git").exists() {
        bail!(
            "{} source does not exist, did you forget to \
            `git submodule update --init`?",
            MINIGBM_SRC
        );
    }

    let make_flags = env::var("CARGO_MAKEFLAGS").unwrap();
    let status = Command::new("make")
        .env("MAKEFLAGS", make_flags)
        .env("CROSS_COMPILE", get_cross_compile_prefix())
        .arg(format!("OUT={}", out_dir.display()))
        .arg("CC_STATIC_LIBRARY(libminigbm.pie.a)")
        .current_dir(MINIGBM_SRC)
        .status()?;
    if !status.success() {
        bail!("make failed with status: {}", status);
    }

    // minigbm will be linked using the name gbm, make sure it can be found.
    fs::copy(out_dir.join("libminigbm.pie.a"), out_dir.join("libgbm.a"))?;
    Ok(())
}

fn build_virglrenderer(out_dir: &Path) -> Result<()> {
    let lib_path = out_dir.join("src/libvirglrenderer.a");
    if lib_path.exists() {
        return Ok(());
    }

    if !Path::new(VIRGLRENDERER_SRC).join(".git").exists() {
        bail!(
            "{} source does not exist, did you forget to \
            `git submodule update --init`?",
            VIRGLRENDERER_SRC
        );
    }

    let minigbm_src_abs = PathBuf::from(MINIGBM_SRC).canonicalize()?;
    let status = Command::new("meson")
        .env("PKG_CONFIG_PATH", &minigbm_src_abs)
        .arg("setup")
        .arg("-Ddefault_library=static")
        .args(get_meson_cross_args())
        .arg(out_dir.as_os_str())
        .current_dir(VIRGLRENDERER_SRC)
        .status()?;
    if !status.success() {
        bail!("meson setup failed with status: {}", status);
    }

    // Add local minigbm paths to make sure virglrenderer can build against it.
    let mut cmd = Command::new("meson");
    cmd.env("CPATH", &minigbm_src_abs)
        .arg("compile")
        .arg("src/virglrenderer")
        .current_dir(out_dir);

    let status = cmd.status()?;
    if !status.success() {
        bail!("meson compile failed with status: {}", status);
    }
    Ok(())
}

fn virglrenderer() -> Result<()> {
    // System provided runtime dependencies.
    pkg_config::Config::new().probe("epoxy")?;
    pkg_config::Config::new().probe("libdrm")?;

    // Use virglrenderer package from the standard system location if available.
    if pkg_config::Config::new().probe("virglrenderer").is_ok() {
        return Ok(());
    }

    // Otherwise build from source.
    let out_dir = PathBuf::from(env::var("OUT_DIR")?);
    let minigbm_out = out_dir.join("minigbm");
    let virglrenderer_out = out_dir.join("virglrenderer");
    build_minigbm(&minigbm_out)?;
    build_virglrenderer(&virglrenderer_out)?;

    println!(
        "cargo:rustc-link-search={}/src",
        virglrenderer_out.display()
    );
    println!("cargo:rustc-link-search={}", minigbm_out.display());
    println!("cargo:rustc-link-lib=static=virglrenderer");
    println!("cargo:rustc-link-lib=static=gbm");
    Ok(())
}

fn main() -> Result<()> {
    #[cfg(feature = "virgl_renderer")]
    virglrenderer()?;

    Ok(())
}
<commit_msg>rutabaga_gfx: silence warnings when not building virgl_renderer<commit_after>// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use anyhow::Result;

#[cfg(feature = "virgl_renderer")]
use anyhow::bail;
#[cfg(feature = "virgl_renderer")]
use std::env;
#[cfg(feature = "virgl_renderer")]
use std::fs;
#[cfg(feature = "virgl_renderer")]
use std::path::Path;
#[cfg(feature = "virgl_renderer")]
use std::path::PathBuf;
#[cfg(feature = "virgl_renderer")]
use std::process::Command;

#[cfg(feature = "virgl_renderer")]
const MINIGBM_SRC: &str = "../third_party/minigbm";
#[cfg(feature = "virgl_renderer")]
const VIRGLRENDERER_SRC: &str = "../third_party/virglrenderer";

#[cfg(feature = "virgl_renderer")]
fn is_native_build() -> bool {
    env::var("HOST").unwrap() == env::var("TARGET").unwrap()
}

/// Returns the target triplet prefix for gcc commands. No prefix is required
/// for native builds.
#[cfg(feature = "virgl_renderer")]
fn get_cross_compile_prefix() -> String {
    if is_native_build() {
        return String::from("");
    }

    let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
    let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
    let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
    return format!("{}-{}-{}-", arch, os, env);
}

/// For cross-compilation with meson, we need to pick a cross-file, which
/// live in /usr/local/share/meson/cross.
#[cfg(feature = "virgl_renderer")]
fn get_meson_cross_args() -> Vec<String> {
    if is_native_build() {
        Vec::new()
    } else {
        vec![
            "--cross-file".to_string(),
            env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
        ]
    }
}

#[cfg(feature = "virgl_renderer")]
fn build_minigbm(out_dir: &Path) -> Result<()> {
    let lib_path = out_dir.join("libgbm.a");
    if lib_path.exists() {
        return Ok(());
    }

    if !Path::new(MINIGBM_SRC).join(".git").exists() {
        bail!(
            "{} source does not exist, did you forget to \
            `git submodule update --init`?",
            MINIGBM_SRC
        );
    }

    let make_flags = env::var("CARGO_MAKEFLAGS").unwrap();
    let status = Command::new("make")
        .env("MAKEFLAGS", make_flags)
        .env("CROSS_COMPILE", get_cross_compile_prefix())
        .arg(format!("OUT={}", out_dir.display()))
        .arg("CC_STATIC_LIBRARY(libminigbm.pie.a)")
        .current_dir(MINIGBM_SRC)
        .status()?;
    if !status.success() {
        bail!("make failed with status: {}", status);
    }

    // minigbm will be linked using the name gbm, make sure it can be found.
    fs::copy(out_dir.join("libminigbm.pie.a"), out_dir.join("libgbm.a"))?;
    Ok(())
}

#[cfg(feature = "virgl_renderer")]
fn build_virglrenderer(out_dir: &Path) -> Result<()> {
    let lib_path = out_dir.join("src/libvirglrenderer.a");
    if lib_path.exists() {
        return Ok(());
    }

    if !Path::new(VIRGLRENDERER_SRC).join(".git").exists() {
        bail!(
            "{} source does not exist, did you forget to \
            `git submodule update --init`?",
            VIRGLRENDERER_SRC
        );
    }

    let minigbm_src_abs = PathBuf::from(MINIGBM_SRC).canonicalize()?;
    let status = Command::new("meson")
        .env("PKG_CONFIG_PATH", &minigbm_src_abs)
        .arg("setup")
        .arg("-Ddefault_library=static")
        .args(get_meson_cross_args())
        .arg(out_dir.as_os_str())
        .current_dir(VIRGLRENDERER_SRC)
        .status()?;
    if !status.success() {
        bail!("meson setup failed with status: {}", status);
    }

    // Add local minigbm paths to make sure virglrenderer can build against it.
    let mut cmd = Command::new("meson");
    cmd.env("CPATH", &minigbm_src_abs)
        .arg("compile")
        .arg("src/virglrenderer")
        .current_dir(out_dir);

    let status = cmd.status()?;
    if !status.success() {
        bail!("meson compile failed with status: {}", status);
    }
    Ok(())
}

#[cfg(feature = "virgl_renderer")]
fn virglrenderer() -> Result<()> {
    // System provided runtime dependencies.
    pkg_config::Config::new().probe("epoxy")?;
    pkg_config::Config::new().probe("libdrm")?;

    // Use virglrenderer package from the standard system location if available.
    if pkg_config::Config::new().probe("virglrenderer").is_ok() {
        return Ok(());
    }

    // Otherwise build from source.
    let out_dir = PathBuf::from(env::var("OUT_DIR")?);
    let minigbm_out = out_dir.join("minigbm");
    let virglrenderer_out = out_dir.join("virglrenderer");
    build_minigbm(&minigbm_out)?;
    build_virglrenderer(&virglrenderer_out)?;

    println!(
        "cargo:rustc-link-search={}/src",
        virglrenderer_out.display()
    );
    println!("cargo:rustc-link-search={}", minigbm_out.display());
    println!("cargo:rustc-link-lib=static=virglrenderer");
    println!("cargo:rustc-link-lib=static=gbm");
    Ok(())
}

fn main() -> Result<()> {
    #[cfg(feature = "virgl_renderer")]
    virglrenderer()?;

    Ok(())
}
<|endoftext|>


<commit_before>use Configuration;
use deque;
use deque::{Worker, Stealer, Stolen};
use job::{JobRef, JobMode};
use latch::{Latch, LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use rand;
use std::cell::Cell;
use std::sync::{Arc, Condvar, Mutex, Once, ONCE_INIT};
use std::thread;
use std::collections::VecDeque;
use std::mem;
use unwind;
use util::leak;
use num_cpus;

///////////////////////////////////////////////////////////////////////////

pub struct Registry {
    thread_infos: Vec<ThreadInfo>,
    state: Mutex<RegistryState>,
    work_available: Condvar,
}

struct RegistryState {
    terminate: bool,
    threads_at_work: usize,
    injected_jobs: VecDeque<JobRef>,
}

///////////////////////////////////////////////////////////////////////////
// Initialization

static mut THE_REGISTRY: Option<&'static Registry> = None;
static THE_REGISTRY_SET: Once = ONCE_INIT;

/// Starts the worker threads (if that has not already happened). If
/// initialization has not already occurred, use the default
/// configuration.
pub fn get_registry() -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| unsafe { init_registry(Configuration::new()) });
    unsafe { THE_REGISTRY.unwrap() }
}

/// Starts the worker threads (if that has not already happened) with
/// the given configuration.
pub fn get_registry_with_config(config: Configuration) -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| unsafe { init_registry(config) });
    unsafe { THE_REGISTRY.unwrap() }
}

/// Initializes the global registry with the given configuration.
/// Meant to be called from within the `THE_REGISTRY_SET` once
/// function. Declared `unsafe` because it writes to `THE_REGISTRY` in
/// an unsynchronized fashion.
unsafe fn init_registry(config: Configuration) {
    let registry = leak(Registry::new(config.num_threads()));
    THE_REGISTRY = Some(registry);
}

enum Work {
    None,
    Job(JobRef),
    Terminate,
}

impl Registry {
    pub fn new(num_threads: Option<usize>) -> Arc<Registry> {
        let limit_value = match num_threads {
            Some(value) => value,
            None => num_cpus::get()
        };

        let (workers, stealers) : (Vec<_>, Vec<_>) =
            (0..limit_value).map(|_| deque::new()).unzip();

        let registry = Arc::new(Registry {
            thread_infos: stealers.into_iter().map(|s| ThreadInfo::new(s))
                                          .collect(),
            state: Mutex::new(RegistryState::new()),
            work_available: Condvar::new(),
        });

        for (index, worker) in workers.into_iter().enumerate() {
            let registry = registry.clone();
            thread::spawn(move || unsafe { main_loop(worker, registry, index) });
        }

        registry
    }

    pub fn num_threads(&self) -> usize {
        self.thread_infos.len()
    }

    /// Waits for the worker threads to get up and running.  This is
    /// meant to be used for benchmarking purposes, primarily, so that
    /// you can get more consistent numbers by having everything
    /// "ready to go".
    pub fn wait_until_primed(&self) {
        for info in &self.thread_infos {
            info.primed.wait();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // MAIN LOOP
    //
    // So long as all of the worker threads are hanging out in their
    // top-level loop, there is no work to be done.

    fn start_working(&self, index: usize) {
        log!(StartWorking { index: index });
        let mut state = self.state.lock().unwrap();
        state.threads_at_work += 1;
        self.work_available.notify_all();
    }

    pub unsafe fn inject(&self, injected_jobs: &[JobRef]) {
        log!(InjectJobs { count: injected_jobs.len() });
        let mut state = self.state.lock().unwrap();

        // It should not be possible for `state.terminate` to be true
        // here. It is only set to true when the user creates (and
        // drops) a `ThreadPool`; and, in that case, they cannot be
        // calling `inject()` later, since they dropped their
        // `ThreadPool`.
        assert!(!state.terminate, "inject() sees state.terminate as true");

        state.injected_jobs.extend(injected_jobs);
        self.work_available.notify_all();
    }

    fn wait_for_work(&self, _worker: usize, was_active: bool) -> Work {
        log!(WaitForWork { worker: _worker, was_active: was_active });

        let mut state = self.state.lock().unwrap();

        if was_active {
            state.threads_at_work -= 1;
        }

        loop {
            // Check if we need to terminate.
            if state.terminate {
                return Work::Terminate;
            }

            // Otherwise, if anything was injected from outside,
            // return that.  Note that this gives preference to
            // injected items over stealing from others, which is a
            // bit dubious, but then so is the opposite.
            if let Some(job) = state.injected_jobs.pop_front() {
                state.threads_at_work += 1;
                self.work_available.notify_all();
                return Work::Job(job);
            }

            // If any of the threads are running a job, we should spin
            // up, since they may generate subworkitems.
            if state.threads_at_work > 0 {
                return Work::None;
            }

            state = self.work_available.wait(state).unwrap();
        }
    }

    pub fn terminate(&self) {
        let mut state = self.state.lock().unwrap();
        state.terminate = true;
        for job in state.injected_jobs.drain(..) {
            unsafe {
                job.execute(JobMode::Abort);
            }
        }
        self.work_available.notify_all();
    }
}

impl RegistryState {
    pub fn new() -> RegistryState {
        RegistryState {
            threads_at_work: 0,
            injected_jobs: VecDeque::new(),
            terminate: false,
        }
    }
}

struct ThreadInfo {
    // latch is set once thread has started and we are entering into
    // the main loop
    primed: LockLatch,
    stealer: Stealer<JobRef>,
}

impl ThreadInfo {
    fn new(stealer: Stealer<JobRef>) -> ThreadInfo {
        ThreadInfo {
            primed: LockLatch::new(),
            stealer: stealer,
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread identifiers

pub struct WorkerThread {
    worker: Worker<JobRef>,
    stealers: Vec<Stealer<JobRef>>,
    index: usize,

    /// a counter tracking how many calls to `Scope::spawn` occurred
    /// on the current thread; this is used by the scope code to
    /// ensure that the depth of the local deque is maintained
    spawn_count: Cell<usize>,
}

// This is a bit sketchy, but basically: the WorkerThread is
// allocated on the stack of the worker on entry and stored into this
// thread local variable. So it will remain valid at least until the
// worker is fully unwound. Using an unsafe pointer avoids the need
// for a RefCell<T> etc.
thread_local! {
    static WORKER_THREAD_STATE: Cell<*const WorkerThread> =
        Cell::new(0 as *const WorkerThread)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread; returns
    /// NULL if this is not a worker thread. This pointer is valid
    /// anywhere on the current thread.
    #[inline]
    pub unsafe fn current() -> *const WorkerThread {
        WORKER_THREAD_STATE.with(|t| t.get())
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(&self) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(self);
        });
    }

    #[inline]
    pub fn index(&self) -> usize {
        self.index
    }

    #[inline]
    pub fn spawn_count(&self) -> &Cell<usize> {
        &self.spawn_count
    }

    #[inline]
    pub unsafe fn push(&self, job: JobRef) {
        self.worker.push(job);
    }

    /// Pop `job` from top of stack, returning `false` if it has been
    /// stolen.
    #[inline]
    pub unsafe fn pop(&self) -> Option<JobRef> {
        self.worker.pop()
    }

    #[cold]
    pub unsafe fn steal_until(&self, latch: &SpinLatch) {
        // If another thread stole our job when we panic, we must halt unwinding
        // until that thread is finished using it.
        let guard = unwind::finally(&latch, |latch| latch.spin());
        while !latch.probe() {
            if let Some(job) = self.steal_work() {
                job.execute(JobMode::Execute);
            } else {
                thread::yield_now();
            }
        }
        mem::forget(guard);
    }

    unsafe fn steal_work(&self) -> Option<JobRef> {
        if self.stealers.is_empty() { return None }
        let start = rand::random::<usize>() % self.stealers.len();
        let (lo, hi) = self.stealers.split_at(start);
        hi.iter().chain(lo)
            .filter_map(|stealer| match stealer.steal() {
                Stolen::Empty => None,
                Stolen::Abort => None, // loop?
                Stolen::Data(v) => Some(v),
            })
            .next()
    }
}

///////////////////////////////////////////////////////////////////////////

unsafe fn main_loop(worker: Worker<JobRef>, registry: Arc<Registry>, index: usize) {
    let stealers = registry.thread_infos.iter()
        .enumerate().filter(|&(i, _)| i != index)
        .map(|(_, ti)| ti.stealer.clone())
        .collect();

    let worker_thread = WorkerThread {
        worker: worker,
        stealers: stealers,
        index: index,
        spawn_count: Cell::new(0),
    };
    worker_thread.set_current();

    // let registry know we are ready to do work
    registry.thread_infos[index].primed.set();

    // Worker threads should not panic. If they do, just abort, as the
    // internal state of the threadpool is corrupted. Note that if
    // **user code** panics, we should catch that and redirect.
    let abort_guard = unwind::AbortIfPanic;

    let mut was_active = false;
    loop {
        match registry.wait_for_work(index, was_active) {
            Work::Job(injected_job) => {
                injected_job.execute(JobMode::Execute);
                was_active = true;
                continue;
            }
            Work::Terminate => break,
            Work::None => {},
        }

        if let Some(stolen_job) = worker_thread.steal_work() {
            log!(StoleWork { worker: index });
            registry.start_working(index);
            stolen_job.execute(JobMode::Execute);
            was_active = true;
        } else {
            was_active = false;
        }
    }

    // Normal termination, do not abort.
    mem::forget(abort_guard);
}
<commit_msg>worker: Use a weaker rng.<commit_after>use Configuration;
use deque;
use deque::{Worker, Stealer, Stolen};
use job::{JobRef, JobMode};
use latch::{Latch, LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use rand::{self, Rng};
use std::cell::Cell;
use std::sync::{Arc, Condvar, Mutex, Once, ONCE_INIT};
use std::thread;
use std::collections::VecDeque;
use std::mem;
use unwind;
use util::leak;
use num_cpus;

///////////////////////////////////////////////////////////////////////////

pub struct Registry {
    thread_infos: Vec<ThreadInfo>,
    state: Mutex<RegistryState>,
    work_available: Condvar,
}

struct RegistryState {
    terminate: bool,
    threads_at_work: usize,
    injected_jobs: VecDeque<JobRef>,
}

///////////////////////////////////////////////////////////////////////////
// Initialization

static mut THE_REGISTRY: Option<&'static Registry> = None;
static THE_REGISTRY_SET: Once = ONCE_INIT;

/// Starts the worker threads (if that has not already happened). If
/// initialization has not already occurred, use the default
/// configuration.
pub fn get_registry() -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| unsafe { init_registry(Configuration::new()) });
    unsafe { THE_REGISTRY.unwrap() }
}

/// Starts the worker threads (if that has not already happened) with
/// the given configuration.
pub fn get_registry_with_config(config: Configuration) -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| unsafe { init_registry(config) });
    unsafe { THE_REGISTRY.unwrap() }
}

/// Initializes the global registry with the given configuration.
/// Meant to be called from within the `THE_REGISTRY_SET` once
/// function. Declared `unsafe` because it writes to `THE_REGISTRY` in
/// an unsynchronized fashion.
unsafe fn init_registry(config: Configuration) {
    let registry = leak(Registry::new(config.num_threads()));
    THE_REGISTRY = Some(registry);
}

enum Work {
    None,
    Job(JobRef),
    Terminate,
}

impl Registry {
    pub fn new(num_threads: Option<usize>) -> Arc<Registry> {
        let limit_value = match num_threads {
            Some(value) => value,
            None => num_cpus::get()
        };

        let (workers, stealers) : (Vec<_>, Vec<_>) =
            (0..limit_value).map(|_| deque::new()).unzip();

        let registry = Arc::new(Registry {
            thread_infos: stealers.into_iter().map(|s| ThreadInfo::new(s))
                                          .collect(),
            state: Mutex::new(RegistryState::new()),
            work_available: Condvar::new(),
        });

        for (index, worker) in workers.into_iter().enumerate() {
            let registry = registry.clone();
            thread::spawn(move || unsafe { main_loop(worker, registry, index) });
        }

        registry
    }

    pub fn num_threads(&self) -> usize {
        self.thread_infos.len()
    }

    /// Waits for the worker threads to get up and running.  This is
    /// meant to be used for benchmarking purposes, primarily, so that
    /// you can get more consistent numbers by having everything
    /// "ready to go".
    pub fn wait_until_primed(&self) {
        for info in &self.thread_infos {
            info.primed.wait();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // MAIN LOOP
    //
    // So long as all of the worker threads are hanging out in their
    // top-level loop, there is no work to be done.

    fn start_working(&self, index: usize) {
        log!(StartWorking { index: index });
        let mut state = self.state.lock().unwrap();
        state.threads_at_work += 1;
        self.work_available.notify_all();
    }

    pub unsafe fn inject(&self, injected_jobs: &[JobRef]) {
        log!(InjectJobs { count: injected_jobs.len() });
        let mut state = self.state.lock().unwrap();

        // It should not be possible for `state.terminate` to be true
        // here. It is only set to true when the user creates (and
        // drops) a `ThreadPool`; and, in that case, they cannot be
        // calling `inject()` later, since they dropped their
        // `ThreadPool`.
        assert!(!state.terminate, "inject() sees state.terminate as true");

        state.injected_jobs.extend(injected_jobs);
        self.work_available.notify_all();
    }

    fn wait_for_work(&self, _worker: usize, was_active: bool) -> Work {
        log!(WaitForWork { worker: _worker, was_active: was_active });

        let mut state = self.state.lock().unwrap();

        if was_active {
            state.threads_at_work -= 1;
        }

        loop {
            // Check if we need to terminate.
            if state.terminate {
                return Work::Terminate;
            }

            // Otherwise, if anything was injected from outside,
            // return that.  Note that this gives preference to
            // injected items over stealing from others, which is a
            // bit dubious, but then so is the opposite.
            if let Some(job) = state.injected_jobs.pop_front() {
                state.threads_at_work += 1;
                self.work_available.notify_all();
                return Work::Job(job);
            }

            // If any of the threads are running a job, we should spin
            // up, since they may generate subworkitems.
            if state.threads_at_work > 0 {
                return Work::None;
            }

            state = self.work_available.wait(state).unwrap();
        }
    }

    pub fn terminate(&self) {
        let mut state = self.state.lock().unwrap();
        state.terminate = true;
        for job in state.injected_jobs.drain(..) {
            unsafe {
                job.execute(JobMode::Abort);
            }
        }
        self.work_available.notify_all();
    }
}

impl RegistryState {
    pub fn new() -> RegistryState {
        RegistryState {
            threads_at_work: 0,
            injected_jobs: VecDeque::new(),
            terminate: false,
        }
    }
}

struct ThreadInfo {
    // latch is set once thread has started and we are entering into
    // the main loop
    primed: LockLatch,
    stealer: Stealer<JobRef>,
}

impl ThreadInfo {
    fn new(stealer: Stealer<JobRef>) -> ThreadInfo {
        ThreadInfo {
            primed: LockLatch::new(),
            stealer: stealer,
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread identifiers

pub struct WorkerThread {
    worker: Worker<JobRef>,
    stealers: Vec<Stealer<JobRef>>,
    index: usize,

    /// a counter tracking how many calls to `Scope::spawn` occurred
    /// on the current thread; this is used by the scope code to
    /// ensure that the depth of the local deque is maintained
    spawn_count: Cell<usize>,

    /// A weak random number generator.
    rng: rand::XorShiftRng,
}

// This is a bit sketchy, but basically: the WorkerThread is
// allocated on the stack of the worker on entry and stored into this
// thread local variable. So it will remain valid at least until the
// worker is fully unwound. Using an unsafe pointer avoids the need
// for a RefCell<T> etc.
thread_local! {
    static WORKER_THREAD_STATE: Cell<*mut WorkerThread> =
        Cell::new(0 as *mut WorkerThread)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread; returns
    /// NULL if this is not a worker thread. This pointer is valid
    /// anywhere on the current thread.
    #[inline]
    pub unsafe fn current() -> *mut WorkerThread {
        WORKER_THREAD_STATE.with(|t| t.get())
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(&mut self) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(self);
        });
    }

    #[inline]
    pub fn index(&self) -> usize {
        self.index
    }

    #[inline]
    pub fn spawn_count(&self) -> &Cell<usize> {
        &self.spawn_count
    }

    #[inline]
    pub unsafe fn push(&self, job: JobRef) {
        self.worker.push(job);
    }

    /// Pop `job` from top of stack, returning `false` if it has been
    /// stolen.
    #[inline]
    pub unsafe fn pop(&self) -> Option<JobRef> {
        self.worker.pop()
    }

    #[cold]
    pub unsafe fn steal_until(&mut self, latch: &SpinLatch) {
        // If another thread stole our job when we panic, we must halt unwinding
        // until that thread is finished using it.
        let guard = unwind::finally(&latch, |latch| latch.spin());
        while !latch.probe() {
            if let Some(job) = self.steal_work() {
                job.execute(JobMode::Execute);
            } else {
                thread::yield_now();
            }
        }
        mem::forget(guard);
    }

    unsafe fn steal_work(&mut self) -> Option<JobRef> {
        if self.stealers.is_empty() { return None }
        let start = self.rng.next_u32() % self.stealers.len() as u32;
        let (lo, hi) = self.stealers.split_at(start as usize);
        hi.iter().chain(lo)
            .filter_map(|stealer| match stealer.steal() {
                Stolen::Empty => None,
                Stolen::Abort => None, // loop?
                Stolen::Data(v) => Some(v),
            })
            .next()
    }
}

///////////////////////////////////////////////////////////////////////////

unsafe fn main_loop(worker: Worker<JobRef>, registry: Arc<Registry>, index: usize) {
    let stealers = registry.thread_infos.iter()
        .enumerate().filter(|&(i, _)| i != index)
        .map(|(_, ti)| ti.stealer.clone())
        .collect::<Vec<_>>();

    assert!(stealers.len() < ::std::u32::MAX as usize,
            "We assume this is not going to happen!");

    let mut worker_thread = WorkerThread {
        worker: worker,
        stealers: stealers,
        index: index,
        spawn_count: Cell::new(0),
        rng: rand::weak_rng(),
    };
    worker_thread.set_current();

    // let registry know we are ready to do work
    registry.thread_infos[index].primed.set();

    // Worker threads should not panic. If they do, just abort, as the
    // internal state of the threadpool is corrupted. Note that if
    // **user code** panics, we should catch that and redirect.
    let abort_guard = unwind::AbortIfPanic;

    let mut was_active = false;
    loop {
        match registry.wait_for_work(index, was_active) {
            Work::Job(injected_job) => {
                injected_job.execute(JobMode::Execute);
                was_active = true;
                continue;
            }
            Work::Terminate => break,
            Work::None => {},
        }

        if let Some(stolen_job) = worker_thread.steal_work() {
            log!(StoleWork { worker: index });
            registry.start_working(index);
            stolen_job.execute(JobMode::Execute);
            was_active = true;
        } else {
            was_active = false;
        }
    }

    // Normal termination, do not abort.
    mem::forget(abort_guard);
}
<|endoftext|>


<commit_before>use job::{Job, NULL_JOB};
use latch::Latch;
#[allow(unused_imports)]
use log::Event::*;
use rand;
use std::cell::Cell;
use std::sync::{Condvar, Mutex, Once, ONCE_INIT};
use std::thread;
use std::u32;
use util::leak;

///////////////////////////////////////////////////////////////////////////

const NUM_CPUS: usize = 2;

pub struct Registry {
    thread_infos: Vec<ThreadInfo>,
    state: Mutex<RegistryState>,
    work_available: Condvar,
}

struct RegistryState {
    threads_at_work: usize,
    injected_jobs: Vec<*mut Job>,
}

///////////////////////////////////////////////////////////////////////////
// Initialization

static mut THE_REGISTRY: Option<&'static Registry> = None;
static THE_REGISTRY_SET: Once = ONCE_INIT;
static THE_REGISTRY_INIT: Once = ONCE_INIT;

fn get_registry_or_init() -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| {
        let registry = leak(Box::new(Registry::new()));
        unsafe { THE_REGISTRY = Some(registry); }
    });
    unsafe { THE_REGISTRY.unwrap() }
}

#[inline]
pub fn initialize() -> &'static Registry {
    THE_REGISTRY_INIT.call_once(|| {
        get_registry_or_init().finish_initializing();
    });
    unsafe { THE_REGISTRY.unwrap() }
}

impl Registry {
    fn new() -> Registry {
        for index in 0 .. NUM_CPUS {
            thread::spawn(move || unsafe { main_loop(index) });
        }

        Registry {
            thread_infos: (0..NUM_CPUS).map(|_| ThreadInfo::new()).collect(),
            state: Mutex::new(RegistryState::new()),
            work_available: Condvar::new(),
        }
    }

    fn finish_initializing(&self) {
        for info in &self.thread_infos {
            info.primed.wait();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // MAIN LOOP
    //
    // So long as all of the worker threads are hanging out in their
    // top-level loop, there is no work to be done.

    fn start_working(&self, _index: usize) {
        log!(StartWorking { index: _index });
        let mut state = self.state.lock().unwrap();
        state.threads_at_work += 1;
        self.work_available.notify_all();
    }

    fn inject(&self, injected_jobs: &[*mut Job]) {
        log!(InjectJobs { count: injected_jobs.len() });
        let mut state = self.state.lock().unwrap();
        state.injected_jobs.extend(injected_jobs);
        self.work_available.notify_all();
    }

    fn wait_for_work(&self, _worker: usize, was_active: bool) -> Option<*mut Job> {
        log!(WaitForWork { worker: _worker, was_active: was_active });

        let mut state = self.state.lock().unwrap();

        if was_active {
            state.threads_at_work -= 1;
        }

        loop {
            // Otherwise, if anything was injected from outside,
            // return that.  Note that this gives preference to
            // injected items over stealing from others, which is a
            // bit dubious, but then so is the opposite.
            if let Some(job) = state.injected_jobs.pop() {
                state.threads_at_work += 1;
                self.work_available.notify_all();
                return Some(job);
            }

            // If any of the threads are running a job, we should spin
            // up, since they may generate subworkitems.
            if state.threads_at_work > 0 {
                return None;
            }

            state = self.work_available.wait(state).unwrap();
        }
    }
}

impl RegistryState {
    pub fn new() -> RegistryState {
        RegistryState {
            threads_at_work: 0,
            injected_jobs: Vec::new(),
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread identifiers

#[derive(Copy, Clone, Debug)]
pub struct WorkerThread(u32);

thread_local! {
    static WORKER_THREAD_INDEX: Cell<u32> = Cell::new(u32::MAX)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread, if any.
    #[inline]
    pub fn current() -> Option<WorkerThread> {
        let n = WORKER_THREAD_INDEX.with(|t| t.get());
        if n == u32::MAX { None } else { Some(WorkerThread(n)) }
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    fn set_current(&self) {
        assert!(self.0 != u32::MAX);
        assert!(WORKER_THREAD_INDEX.with(|t| t.get()) == u32::MAX);
        assert!(unsafe { THE_REGISTRY.is_some() });
        WORKER_THREAD_INDEX.with(|t| t.set(self.0));
    }

    #[inline]
    fn registry(&self) -> &'static Registry {
        // if you have gotten possession of a worker thread,
        // the registry must have been initialized by now
        unsafe { THE_REGISTRY.unwrap() }
    }

    #[inline]
    fn thread_info(&self) -> &'static ThreadInfo {
        &self.registry().thread_infos[self.0 as usize]
    }

    #[inline]
    pub unsafe fn push(&self, job: *mut Job) {
        let thread_info = self.thread_info();
        let mut deque = thread_info.deque.lock().unwrap();

        let top = deque.top;
        (*job).previous = top;
        if !top.is_null() {
            (*top).next = job;
        }

        deque.top = job;
        if deque.bottom.is_null() {
            deque.bottom = job;
        }
    }

    /// Pop `job` if it is still at the top of the stack.  Otherwise,
    /// some other thread has stolen this job.
    #[inline]
    pub unsafe fn pop(&self, job: *mut Job) -> bool {
        let thread_info = self.thread_info();
        let mut deque = thread_info.deque.lock().unwrap();
        if deque.top == job {
            let previous_job = (*job).previous;
            deque.top = previous_job;

            if previous_job != NULL_JOB {
                (*previous_job).next = NULL_JOB;
            } else {
                deque.bottom = NULL_JOB;
            }
            true
        } else {
            false
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread info

struct ThreadInfo {
    // latch is set once thread has started and we are entering into
    // the main loop
    primed: Latch,
    deque: Mutex<ThreadDeque>,
}

struct ThreadDeque {
    bottom: *mut Job,
    top: *mut Job,
}

impl ThreadInfo {
    fn new() -> ThreadInfo {
        ThreadInfo {
            deque: Mutex::new(ThreadDeque::new()),
            primed: Latch::new(),
        }
    }
}

impl ThreadDeque {
    fn new() -> ThreadDeque {
        ThreadDeque { bottom: NULL_JOB, top: NULL_JOB }
    }
}

///////////////////////////////////////////////////////////////////////////

unsafe fn main_loop(index: usize) {
    assert!(index < (u32::MAX as usize));
    let worker_index = WorkerThread(index as u32);

    // implicitly blocks until Registry is initialized, which means
    // that later, if we see that `WORKER_THREAD_INDEX` is valid, we know
    // that `THE_REGISTRY` is `Some(_)`
    let registry = get_registry_or_init();

    // store the thread index so we know that we are on a worker thread
    worker_index.set_current();

    // let registry know we are ready to do work
    registry.thread_infos[index].primed.set();

    let mut was_active = false;
    loop {
        if let Some(injected_job) = registry.wait_for_work(index, was_active) {
            (*injected_job).execute();
            was_active = true;
        } else if let Some(stolen_job) = steal_work(registry, index) {
            log!(StoleWork { worker: index, job: stolen_job });
            registry.start_working(index);
            (*stolen_job).execute();
            was_active = true;
        } else {
            was_active = false;
        }
    }
}

unsafe fn steal_work(registry: &Registry, index: usize) -> Option<*mut Job> {
    let start = rand::random::<usize>() % NUM_CPUS;
    (start .. NUM_CPUS)
        .chain(0 .. start)
        .filter(|&i| i != index)
        .filter_map(|i| steal_work_from(registry, i))
        .next()
}

unsafe fn steal_work_from(registry: &Registry, index: usize) -> Option<*mut Job> {
    let thread_info = &registry.thread_infos[index];
    let mut deque = thread_info.deque.lock().unwrap();
    if deque.bottom.is_null() {
        return None;
    }

    let job = deque.bottom;
    let next = (*job).next;
    deque.bottom = next;
    if next != NULL_JOB {
        (*next).previous = NULL_JOB;
    } else {
        deque.top = NULL_JOB;
    }
    Some(job)
}

pub fn inject(jobs: &[*mut Job]) {
    debug_assert!(WorkerThread::current().is_none());
    let registry = initialize();
    registry.inject(jobs);
}
<commit_msg>get more parallelism<commit_after>use job::{Job, NULL_JOB};
use latch::Latch;
#[allow(unused_imports)]
use log::Event::*;
use rand;
use std::cell::Cell;
use std::sync::{Condvar, Mutex, Once, ONCE_INIT};
use std::thread;
use std::u32;
use util::leak;

///////////////////////////////////////////////////////////////////////////

const NUM_CPUS: usize = 4;

pub struct Registry {
    thread_infos: Vec<ThreadInfo>,
    state: Mutex<RegistryState>,
    work_available: Condvar,
}

struct RegistryState {
    threads_at_work: usize,
    injected_jobs: Vec<*mut Job>,
}

///////////////////////////////////////////////////////////////////////////
// Initialization

static mut THE_REGISTRY: Option<&'static Registry> = None;
static THE_REGISTRY_SET: Once = ONCE_INIT;
static THE_REGISTRY_INIT: Once = ONCE_INIT;

fn get_registry_or_init() -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| {
        let registry = leak(Box::new(Registry::new()));
        unsafe { THE_REGISTRY = Some(registry); }
    });
    unsafe { THE_REGISTRY.unwrap() }
}

#[inline]
pub fn initialize() -> &'static Registry {
    THE_REGISTRY_INIT.call_once(|| {
        get_registry_or_init().finish_initializing();
    });
    unsafe { THE_REGISTRY.unwrap() }
}

impl Registry {
    fn new() -> Registry {
        for index in 0 .. NUM_CPUS {
            thread::spawn(move || unsafe { main_loop(index) });
        }

        Registry {
            thread_infos: (0..NUM_CPUS).map(|_| ThreadInfo::new()).collect(),
            state: Mutex::new(RegistryState::new()),
            work_available: Condvar::new(),
        }
    }

    fn finish_initializing(&self) {
        for info in &self.thread_infos {
            info.primed.wait();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // MAIN LOOP
    //
    // So long as all of the worker threads are hanging out in their
    // top-level loop, there is no work to be done.

    fn start_working(&self, _index: usize) {
        log!(StartWorking { index: _index });
        let mut state = self.state.lock().unwrap();
        state.threads_at_work += 1;
        self.work_available.notify_all();
    }

    fn inject(&self, injected_jobs: &[*mut Job]) {
        log!(InjectJobs { count: injected_jobs.len() });
        let mut state = self.state.lock().unwrap();
        state.injected_jobs.extend(injected_jobs);
        self.work_available.notify_all();
    }

    fn wait_for_work(&self, _worker: usize, was_active: bool) -> Option<*mut Job> {
        log!(WaitForWork { worker: _worker, was_active: was_active });

        let mut state = self.state.lock().unwrap();

        if was_active {
            state.threads_at_work -= 1;
        }

        loop {
            // Otherwise, if anything was injected from outside,
            // return that.  Note that this gives preference to
            // injected items over stealing from others, which is a
            // bit dubious, but then so is the opposite.
            if let Some(job) = state.injected_jobs.pop() {
                state.threads_at_work += 1;
                self.work_available.notify_all();
                return Some(job);
            }

            // If any of the threads are running a job, we should spin
            // up, since they may generate subworkitems.
            if state.threads_at_work > 0 {
                return None;
            }

            state = self.work_available.wait(state).unwrap();
        }
    }
}

impl RegistryState {
    pub fn new() -> RegistryState {
        RegistryState {
            threads_at_work: 0,
            injected_jobs: Vec::new(),
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread identifiers

#[derive(Copy, Clone, Debug)]
pub struct WorkerThread(u32);

thread_local! {
    static WORKER_THREAD_INDEX: Cell<u32> = Cell::new(u32::MAX)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread, if any.
    #[inline]
    pub fn current() -> Option<WorkerThread> {
        let n = WORKER_THREAD_INDEX.with(|t| t.get());
        if n == u32::MAX { None } else { Some(WorkerThread(n)) }
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    fn set_current(&self) {
        assert!(self.0 != u32::MAX);
        assert!(WORKER_THREAD_INDEX.with(|t| t.get()) == u32::MAX);
        assert!(unsafe { THE_REGISTRY.is_some() });
        WORKER_THREAD_INDEX.with(|t| t.set(self.0));
    }

    #[inline]
    fn registry(&self) -> &'static Registry {
        // if you have gotten possession of a worker thread,
        // the registry must have been initialized by now
        unsafe { THE_REGISTRY.unwrap() }
    }

    #[inline]
    fn thread_info(&self) -> &'static ThreadInfo {
        &self.registry().thread_infos[self.0 as usize]
    }

    #[inline]
    pub unsafe fn push(&self, job: *mut Job) {
        let thread_info = self.thread_info();
        let mut deque = thread_info.deque.lock().unwrap();

        let top = deque.top;
        (*job).previous = top;
        if !top.is_null() {
            (*top).next = job;
        }

        deque.top = job;
        if deque.bottom.is_null() {
            deque.bottom = job;
        }
    }

    /// Pop `job` if it is still at the top of the stack.  Otherwise,
    /// some other thread has stolen this job.
    #[inline]
    pub unsafe fn pop(&self, job: *mut Job) -> bool {
        let thread_info = self.thread_info();
        let mut deque = thread_info.deque.lock().unwrap();
        if deque.top == job {
            let previous_job = (*job).previous;
            deque.top = previous_job;

            if previous_job != NULL_JOB {
                (*previous_job).next = NULL_JOB;
            } else {
                deque.bottom = NULL_JOB;
            }
            true
        } else {
            false
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread info

struct ThreadInfo {
    // latch is set once thread has started and we are entering into
    // the main loop
    primed: Latch,
    deque: Mutex<ThreadDeque>,
}

struct ThreadDeque {
    bottom: *mut Job,
    top: *mut Job,
}

impl ThreadInfo {
    fn new() -> ThreadInfo {
        ThreadInfo {
            deque: Mutex::new(ThreadDeque::new()),
            primed: Latch::new(),
        }
    }
}

impl ThreadDeque {
    fn new() -> ThreadDeque {
        ThreadDeque { bottom: NULL_JOB, top: NULL_JOB }
    }
}

///////////////////////////////////////////////////////////////////////////

unsafe fn main_loop(index: usize) {
    assert!(index < (u32::MAX as usize));
    let worker_index = WorkerThread(index as u32);

    // implicitly blocks until Registry is initialized, which means
    // that later, if we see that `WORKER_THREAD_INDEX` is valid, we know
    // that `THE_REGISTRY` is `Some(_)`
    let registry = get_registry_or_init();

    // store the thread index so we know that we are on a worker thread
    worker_index.set_current();

    // let registry know we are ready to do work
    registry.thread_infos[index].primed.set();

    let mut was_active = false;
    loop {
        if let Some(injected_job) = registry.wait_for_work(index, was_active) {
            (*injected_job).execute();
            was_active = true;
        } else if let Some(stolen_job) = steal_work(registry, index) {
            log!(StoleWork { worker: index, job: stolen_job });
            registry.start_working(index);
            (*stolen_job).execute();
            was_active = true;
        } else {
            was_active = false;
        }
    }
}

unsafe fn steal_work(registry: &Registry, index: usize) -> Option<*mut Job> {
    let start = rand::random::<usize>() % NUM_CPUS;
    (start .. NUM_CPUS)
        .chain(0 .. start)
        .filter(|&i| i != index)
        .filter_map(|i| steal_work_from(registry, i))
        .next()
}

unsafe fn steal_work_from(registry: &Registry, index: usize) -> Option<*mut Job> {
    let thread_info = &registry.thread_infos[index];
    let mut deque = thread_info.deque.lock().unwrap();
    if deque.bottom.is_null() {
        return None;
    }

    let job = deque.bottom;
    let next = (*job).next;
    deque.bottom = next;
    if next != NULL_JOB {
        (*next).previous = NULL_JOB;
    } else {
        deque.top = NULL_JOB;
    }
    Some(job)
}

pub fn inject(jobs: &[*mut Job]) {
    debug_assert!(WorkerThread::current().is_none());
    let registry = initialize();
    registry.inject(jobs);
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::net::IpAddr;
use std::sync::{Arc, Mutex};
use std::os::unix::io::{AsRawFd, RawFd};

use {amy, c_ares};

use tracker::{ErrorKind, Result, ResultExt};
use util::FHashMap;

#[derive(Debug)]
pub struct QueryResponse {
    pub id: usize,
    pub res: Result<IpAddr>,
}

pub struct Resolver {
    reg: amy::Registrar,
    socks: FHashMap<usize, c_ares::Socket>,
    csocks: FHashMap<c_ares::Socket, usize>,
    chan: c_ares::Channel,
    sender: Arc<Mutex<amy::Sender<QueryResponse>>>,
    marked: HashSet<usize>,
}

struct CSockWrapper(c_ares::Socket);

impl AsRawFd for CSockWrapper {
    fn as_raw_fd(&self) -> RawFd {
        self.0
    }
}

impl Resolver {
    pub fn new(reg: amy::Registrar, send: amy::Sender<QueryResponse>) -> Resolver {
        let mut opts = c_ares::Options::new();
        opts.set_timeout(3000).set_tries(4);
        Resolver {
            reg,
            socks: FHashMap::default(),
            csocks: FHashMap::default(),
            chan: c_ares::Channel::with_options(opts).unwrap(),
            sender: Arc::new(Mutex::new(send)),
            marked: HashSet::new(),
        }
    }

    pub fn contains(&self, id: usize) -> bool {
        self.socks.contains_key(&id)
    }

    pub fn readable(&mut self, id: usize) {
        self.chan.process_fd(self.socks[&id], c_ares::SOCKET_BAD);
    }

    pub fn writable(&mut self, id: usize) {
        self.chan.process_fd(c_ares::SOCKET_BAD, self.socks[&id]);
    }

    pub fn tick(&mut self) {
        self.marked.clear();
        // Add any unrecognized fd's to amy for polling, remove
        // any fd's in amy which are no longer handled by c_ares
        for (fd, _, _) in &self.chan.get_sock() {
            // Not efficient, but the max number of queries active at at time is likely limited
            if let Some(id) = self.csocks.get(&fd).cloned() {
                self.marked.insert(id);
            } else {
                let id = self.reg
                    .register(&CSockWrapper(fd), amy::Event::Both)
                    .unwrap();
                self.marked.insert(id);
                self.socks.insert(id, fd);
                self.csocks.insert(fd, id);
            }
        }

        // Any socks remaining in csocks should be deregistered and destroyed
        let socks = &mut self.socks;
        let csocks = &mut self.csocks;
        let marked = &self.marked;
        let reg = &self.reg;
        socks.retain(|id, fd| {
            if marked.contains(id) {
                true
            } else {
                csocks.remove(fd);
                reg.deregister(&CSockWrapper(*fd)).ok();
                false
            }
        });
    }

    pub fn new_query(&mut self, id: usize, host: &str) {
        // TODO: handle ipv6 too
        let s = self.sender.clone();
        self.chan
            .get_host_by_name(host, c_ares::AddressFamily::INET, move |res| {
                let res = res.chain_err(|| ErrorKind::DNS)
                    .and_then(|ips| ips.addresses().next().ok_or_else(|| ErrorKind::DNS.into()));
                let resp = QueryResponse { id, res };
                if s.lock().unwrap().send(resp).is_err() {
                    // Other end was shutdown, ignore
                }
            });
    }
}
<commit_msg>Simplify DNS handling<commit_after>use std::net::IpAddr;
use std::sync::{Arc, Mutex};
use std::os::unix::io::{AsRawFd, RawFd};

use {amy, c_ares};

use tracker::{ErrorKind, Result, ResultExt};
use util::FHashMap;

#[derive(Debug)]
pub struct QueryResponse {
    pub id: usize,
    pub res: Result<IpAddr>,
}

pub struct Resolver {
    reg: amy::Registrar,
    socks: FHashMap<usize, c_ares::Socket>,
    chan: c_ares::Channel,
    sender: Arc<Mutex<amy::Sender<QueryResponse>>>,
}

struct CSockWrapper(c_ares::Socket);

impl AsRawFd for CSockWrapper {
    fn as_raw_fd(&self) -> RawFd {
        self.0
    }
}

impl Resolver {
    pub fn new(reg: amy::Registrar, send: amy::Sender<QueryResponse>) -> Resolver {
        let mut opts = c_ares::Options::new();
        opts.set_timeout(3000).set_tries(4);
        Resolver {
            reg,
            socks: FHashMap::default(),
            chan: c_ares::Channel::with_options(opts).unwrap(),
            sender: Arc::new(Mutex::new(send)),
        }
    }

    pub fn contains(&self, id: usize) -> bool {
        self.socks.contains_key(&id)
    }

    pub fn readable(&mut self, id: usize) {
        self.chan.process_fd(self.socks[&id], c_ares::SOCKET_BAD);
    }

    pub fn writable(&mut self, id: usize) {
        self.chan.process_fd(c_ares::SOCKET_BAD, self.socks[&id]);
    }

    pub fn tick(&mut self) {
        // Add any unrecognized fd's to amy for polling, remove
        // any fd's in amy which are no longer handled by c_ares
        self.socks = self.chan
            .get_sock()
            .iter()
            .map(|(fd, _, _)| {
                (
                    self.reg
                        .register(&CSockWrapper(fd), amy::Event::Both)
                        .unwrap(),
                    fd,
                )
            })
            .collect();
    }

    pub fn new_query(&mut self, id: usize, host: &str) {
        // TODO: handle ipv6 too
        let s = self.sender.clone();
        self.chan
            .get_host_by_name(host, c_ares::AddressFamily::INET, move |res| {
                let res = res.chain_err(|| ErrorKind::DNS)
                    .and_then(|ips| ips.addresses().next().ok_or_else(|| ErrorKind::DNS.into()));
                let resp = QueryResponse { id, res };
                if s.lock().unwrap().send(resp).is_err() {
                    // Other end was shutdown, ignore
                }
            });
    }
}
<|endoftext|>


<commit_before>#![macro_use]

#[macro_export]
macro_rules! cond{
  (orelse => $default:block) => ($default);
  ($pred:expr => $body:block , $($tail:tt)*) => (if $pred $body else { cond!($($tail)*) })
}

#[macro_export]
macro_rules! withDefault{
  ($default, $expr)  => (match $expr { Ok(val) => val; Err(e) => $default})
}

#[macro_export]
macro_rules! bindMaybe{
    ($left:expr, $right:stmt) => ( match $left
                           { Ok(val) => $right(val)
                           ; Err(e)  => Err(e)
                           }
                       )
}

#[macro_export]
macro_rules! mdo{
  ($x:ident <- $y:expr ; $($tail:tt)*) => ( bindMaybe!($y, |$x|   mdo!($($tail)*)));
  ($y:block ; $($tail:tt)*)          => ( { $y; mdo!($($tail)*) });
  ($y:expr )                        => ( Ok($y));
}

<commit_msg>Fixed spacing<commit_after>#![macro_use]

#[macro_export]
macro_rules! cond{
  (orelse => $default:block) => ($default);
  ($pred:expr => $body:block , $($tail:tt)*) => (if $pred $body else { cond!($($tail)*) })
}

#[macro_export]
macro_rules! withDefault{
  ($default, $expr)  => (match $expr { Ok(val) => val; Err(e) => $default})
}

#[macro_export]
macro_rules! bindMaybe{
    ($left:expr, $right:stmt) => (match $left { Ok(val) => $right(val) ; Err(e)  => Err(e) })
}

#[macro_export]
macro_rules! mdo{
  ($x:ident <- $y:expr ; $($tail:tt)*) => ( bindMaybe!($y, |$x|   mdo!($($tail)*)));
  ($y:block ; $($tail:tt)*)            => ( { $y; mdo!($($tail)*) });
  ($y:expr )                           => ( Ok($y));
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io;
use std::path;
use serialize::json;
use serialize::json::Json;
use serialize::Decodable;
use collections::hashmap::HashMap;

use syntax::codemap::Span;
use syntax::ast::{Path, ExprLit, LitStr, TokenTree, TTTok};
use syntax::parse::token::{get_ident, LIT_STR};
use syntax::ext::base::{ExtCtxt, MacResult, MRExpr};
use syntax::ext::source_util::expand_file;

macro_rules! expect ( ($e:expr, $err:expr) => (
    match $e {
        Some(x) => x,
        None => cx.span_fatal(sp, $err),
    }
))

// A struct matching the entries in entities.json.
// Simplifies JSON parsing because we can use Decodable.
#[deriving(Decodable)]
struct CharRef {
    codepoints: Vec<u32>,
    //characters: ~str,  // Present in the file but we don't need it
}

// Build the map from entity names (and their prefixes) to characters.
fn build_map(js: Json) -> Option<HashMap<~str, [u32, ..2]>> {
    let mut map = HashMap::new();
    let json_map = match js {
        json::Object(m) => m,
        _ => return None,
    };

    // Add every named entity to the map.
    for (k,v) in json_map.move_iter() {
        let mut decoder = json::Decoder::new(v);
        let CharRef { codepoints }: CharRef = Decodable::decode(&mut decoder);

        assert!((codepoints.len() >= 1) && (codepoints.len() <= 2));
        let mut codepoint_pair = [0, 0];
        for (i,n) in codepoints.move_iter().enumerate() {
            codepoint_pair[i] = n;
        }

        // Slice off the initial '&'
        assert!(k.char_at(0) == '&');
        map.insert(k.slice_from(1).to_owned(), codepoint_pair);
    }

    // Add every missing prefix of those keys, mapping to NULL characters.
    map.insert(~"", [0, 0]);
    let keys: Vec<~str> = map.keys().map(|k| k.to_owned()).collect();
    for k in keys.move_iter() {
        for n in range(1, k.len()) {
            let pfx = k.slice_to(n).to_owned();
            if !map.contains_key(&pfx) {
                map.insert(pfx, [0, 0]);
            }
        }
    }

    Some(map)
}

// Expand named_entities!("path/to/entities.json") into an invocation of phf_map!().
pub fn expand(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> MacResult {
    // Argument to the macro should be a single literal string: a path to
    // entities.json, relative to the file containing the macro invocation.
    let json_filename = match tt {
        [TTTok(_, LIT_STR(s))] => get_ident(s).get().to_owned(),
        _ => cx.span_fatal(sp, "named_entities takes one argument, a relative path to entities.json"),
    };

    // Get the result of calling file!() in the same place as our macro.
    // This would be a lot nicer if @-patterns were still supported.
    let mod_filename = expect!(match expand_file(cx, sp, &[]) {
        MRExpr(e) => match e.node {
            ExprLit(s) => match s.node {
                LitStr(ref s, _) => Some(s.get().to_owned()),
                _ => None,
            },
            _ => None,
        },
        _ => None,
    }, "unexpected result from file!()");

    // Combine those to get an absolute path to entities.json.
    let mod_path: path::Path = expect!(from_str(mod_filename), "can't parse module filename");
    let json_path = mod_path.dir_path().join(json_filename);

    // Open the JSON file, parse it, and build the map from names to characters.
    let mut json_file = expect!(io::File::open(&json_path).ok(), "can't open JSON file");
    let js = expect!(json::from_reader(&mut json_file as &mut Reader).ok(), "can't parse JSON file");
    let map = expect!(build_map(js), "JSON file does not match entities.json format");

    // Emit a macro invocation of the form
    //
    //     phf_map!(k => v, k => v, ...)
    let mut tts: Vec<TokenTree> = Vec::new();
    for (k, [c1, c2]) in map.move_iter() {
        tts.push_all_move(quote_tokens!(&mut *cx, $k => [$c1, $c2],));
    }
    MRExpr(quote_expr!(&mut *cx, phf_map!($tts)))
}
<commit_msg>Update for Result-yielding Decodable::decode().<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::io;
use std::path;
use serialize::json;
use serialize::json::Json;
use serialize::Decodable;
use collections::hashmap::HashMap;

use syntax::codemap::Span;
use syntax::ast::{Path, ExprLit, LitStr, TokenTree, TTTok};
use syntax::parse::token::{get_ident, LIT_STR};
use syntax::ext::base::{ExtCtxt, MacResult, MRExpr};
use syntax::ext::source_util::expand_file;

macro_rules! expect ( ($e:expr, $err:expr) => (
    match $e {
        Some(x) => x,
        None => cx.span_fatal(sp, $err),
    }
))

// A struct matching the entries in entities.json.
// Simplifies JSON parsing because we can use Decodable.
#[deriving(Decodable)]
struct CharRef {
    codepoints: Vec<u32>,
    //characters: ~str,  // Present in the file but we don't need it
}

// Build the map from entity names (and their prefixes) to characters.
fn build_map(js: Json) -> Option<HashMap<~str, [u32, ..2]>> {
    let mut map = HashMap::new();
    let json_map = match js {
        json::Object(m) => m,
        _ => return None,
    };

    // Add every named entity to the map.
    for (k,v) in json_map.move_iter() {
        let mut decoder = json::Decoder::new(v);
        let CharRef { codepoints }: CharRef = match Decodable::decode(&mut decoder) {
            Ok(o) => o,
            Err(_) => return None,
        };

        assert!((codepoints.len() >= 1) && (codepoints.len() <= 2));
        let mut codepoint_pair = [0, 0];
        for (i,n) in codepoints.move_iter().enumerate() {
            codepoint_pair[i] = n;
        }

        // Slice off the initial '&'
        assert!(k.char_at(0) == '&');
        map.insert(k.slice_from(1).to_owned(), codepoint_pair);
    }

    // Add every missing prefix of those keys, mapping to NULL characters.
    map.insert(~"", [0, 0]);
    let keys: Vec<~str> = map.keys().map(|k| k.to_owned()).collect();
    for k in keys.move_iter() {
        for n in range(1, k.len()) {
            let pfx = k.slice_to(n).to_owned();
            if !map.contains_key(&pfx) {
                map.insert(pfx, [0, 0]);
            }
        }
    }

    Some(map)
}

// Expand named_entities!("path/to/entities.json") into an invocation of phf_map!().
pub fn expand(cx: &mut ExtCtxt, sp: Span, tt: &[TokenTree]) -> MacResult {
    // Argument to the macro should be a single literal string: a path to
    // entities.json, relative to the file containing the macro invocation.
    let json_filename = match tt {
        [TTTok(_, LIT_STR(s))] => get_ident(s).get().to_owned(),
        _ => cx.span_fatal(sp, "named_entities takes one argument, a relative path to entities.json"),
    };

    // Get the result of calling file!() in the same place as our macro.
    // This would be a lot nicer if @-patterns were still supported.
    let mod_filename = expect!(match expand_file(cx, sp, &[]) {
        MRExpr(e) => match e.node {
            ExprLit(s) => match s.node {
                LitStr(ref s, _) => Some(s.get().to_owned()),
                _ => None,
            },
            _ => None,
        },
        _ => None,
    }, "unexpected result from file!()");

    // Combine those to get an absolute path to entities.json.
    let mod_path: path::Path = expect!(from_str(mod_filename), "can't parse module filename");
    let json_path = mod_path.dir_path().join(json_filename);

    // Open the JSON file, parse it, and build the map from names to characters.
    let mut json_file = expect!(io::File::open(&json_path).ok(), "can't open JSON file");
    let js = expect!(json::from_reader(&mut json_file as &mut Reader).ok(), "can't parse JSON file");
    let map = expect!(build_map(js), "JSON file does not match entities.json format");

    // Emit a macro invocation of the form
    //
    //     phf_map!(k => v, k => v, ...)
    let mut tts: Vec<TokenTree> = Vec::new();
    for (k, [c1, c2]) in map.move_iter() {
        tts.push_all_move(quote_tokens!(&mut *cx, $k => [$c1, $c2],));
    }
    MRExpr(quote_expr!(&mut *cx, phf_map!($tts)))
}
<|endoftext|>


<commit_before>use futures::Future;
use xrl;
use tokio_core::reactor::Handle;

pub struct Client {
    inner: xrl::Client,
    handle: Handle,
    view_id: xrl::ViewId,
}

impl Client {
    pub fn new(client: xrl::Client, handle: Handle, view_id: xrl::ViewId) -> Self {
        Client {
            inner: client,
            handle: handle,
            view_id: view_id,
        }
    }

    pub fn insert(&mut self, character: char) {
        let f = self.inner.char(self.view_id, character).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn scroll(&mut self, start: u64, end: u64) {
        let f = self.inner.scroll(self.view_id, start, end).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn down(&mut self) {
        let f = self.inner.down(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn up(&mut self) {
        let f = self.inner.up(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn right(&mut self) {
        let f = self.inner.right(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn left(&mut self) {
        let f = self.inner.left(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn page_down(&mut self) {
        let f = self.inner.page_up(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn page_up(&mut self) {
        let f = self.inner.page_up(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn delete(&mut self) {
        let f = self.inner.del(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn save(&mut self, file: &str) {
        let f = self.inner.save(self.view_id, file).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn click(&mut self, line: u64, column: u64) {
        let f = self.inner.click(self.view_id, line, column).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn drag(&mut self, line: u64, column: u64) {
        let f = self.inner.drag(self.view_id, line, column).map_err(|_| ());
        self.handle.spawn(f);
    }
}
<commit_msg>Fix page down shortcut<commit_after>use futures::Future;
use xrl;
use tokio_core::reactor::Handle;

pub struct Client {
    inner: xrl::Client,
    handle: Handle,
    view_id: xrl::ViewId,
}

impl Client {
    pub fn new(client: xrl::Client, handle: Handle, view_id: xrl::ViewId) -> Self {
        Client {
            inner: client,
            handle: handle,
            view_id: view_id,
        }
    }

    pub fn insert(&mut self, character: char) {
        let f = self.inner.char(self.view_id, character).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn scroll(&mut self, start: u64, end: u64) {
        let f = self.inner.scroll(self.view_id, start, end).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn down(&mut self) {
        let f = self.inner.down(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn up(&mut self) {
        let f = self.inner.up(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn right(&mut self) {
        let f = self.inner.right(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn left(&mut self) {
        let f = self.inner.left(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn page_down(&mut self) {
        let f = self.inner.page_down(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn page_up(&mut self) {
        let f = self.inner.page_up(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn delete(&mut self) {
        let f = self.inner.del(self.view_id).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn save(&mut self, file: &str) {
        let f = self.inner.save(self.view_id, file).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn click(&mut self, line: u64, column: u64) {
        let f = self.inner.click(self.view_id, line, column).map_err(|_| ());
        self.handle.spawn(f);
    }

    pub fn drag(&mut self, line: u64, column: u64) {
        let f = self.inner.drag(self.view_id, line, column).map_err(|_| ());
        self.handle.spawn(f);
    }
}
<|endoftext|>