<commit_before>//! cargo_check provides the functionality needed to run `cargo check` or
//! another compatible command (f.x. clippy) in a background thread and provide
//! LSP diagnostics based on the output of the command.

use std::{
    fmt,
    io::{self, BufReader},
    path::PathBuf,
    process::{Command, Stdio},
    time::Instant,
};

use crossbeam_channel::{never, select, unbounded, Receiver, RecvError, Sender};

pub use cargo_metadata::diagnostic::{
    Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FlycheckConfig {
    CargoCommand {
        command: String,
        all_targets: bool,
        all_features: bool,
        features: Vec<String>,
        extra_args: Vec<String>,
    },
    CustomCommand {
        command: String,
        args: Vec<String>,
    },
}

impl fmt::Display for FlycheckConfig {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command),
            FlycheckConfig::CustomCommand { command, args } => {
                write!(f, "{} {}", command, args.join(" "))
            }
        }
    }
}

/// Flycheck wraps the shared state and communication machinery used for
/// running `cargo check` (or other compatible command) and providing
/// diagnostics based on the output.
/// The spawned thread is shut down when this struct is dropped.
#[derive(Debug)]
pub struct FlycheckHandle {
    // XXX: drop order is significant
    cmd_send: Sender<CheckCommand>,
    handle: jod_thread::JoinHandle,
}

impl FlycheckHandle {
    pub fn spawn(
        sender: Box<dyn Fn(Message) + Send>,
        config: FlycheckConfig,
        workspace_root: PathBuf,
    ) -> FlycheckHandle {
        let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
        let handle = jod_thread::spawn(move || {
            FlycheckActor::new(sender, config, workspace_root).run(&cmd_recv);
        });
        FlycheckHandle { cmd_send, handle }
    }

    /// Schedule a re-start of the cargo check worker.
    pub fn update(&self) {
        self.cmd_send.send(CheckCommand::Update).unwrap();
    }
}

#[derive(Debug)]
pub enum Message {
    /// Request a clearing of all cached diagnostics from the check watcher
    ClearDiagnostics,

    /// Request adding a diagnostic with fixes included to a file
    AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic },

    /// Request check progress notification to client
    Progress(Progress),
}

#[derive(Debug)]
pub enum Progress {
    Being,
    DidCheckCrate(String),
    End,
}

enum CheckCommand {
    /// Request re-start of check thread
    Update,
}

struct FlycheckActor {
    sender: Box<dyn Fn(Message) + Send>,
    config: FlycheckConfig,
    workspace_root: PathBuf,
    last_update_req: Option<Instant>,
    // XXX: drop order is significant
    message_recv: Receiver<CheckEvent>,
    /// WatchThread exists to wrap around the communication needed to be able to
    /// run `cargo check` without blocking. Currently the Rust standard library
    /// doesn't provide a way to read sub-process output without blocking, so we
    /// have to wrap sub-processes output handling in a thread and pass messages
    /// back over a channel.
    check_process: Option<jod_thread::JoinHandle>,
}

impl FlycheckActor {
    fn new(
        sender: Box<dyn Fn(Message) + Send>,
        config: FlycheckConfig,
        workspace_root: PathBuf,
    ) -> FlycheckActor {
        FlycheckActor {
            sender,
            config,
            workspace_root,
            last_update_req: None,
            message_recv: never(),
            check_process: None,
        }
    }

    fn run(&mut self, cmd_recv: &Receiver<CheckCommand>) {
        // If we rerun the thread, we need to discard the previous check results first
        self.clean_previous_results();

        loop {
            select! {
                recv(&cmd_recv) -> cmd => match cmd {
                    Ok(cmd) => self.handle_command(cmd),
                    Err(RecvError) => {
                        // Command channel has closed, so shut down
                        break;
                    },
                },
                recv(self.message_recv) -> msg => match msg {
                    Ok(msg) => self.handle_message(msg),
                    Err(RecvError) => {
                        // Watcher finished, replace it with a never channel to
                        // avoid busy-waiting.
                        self.message_recv = never();
                        self.check_process = None;
                    },
                }
            };

            if self.should_recheck() {
                self.last_update_req = None;
                self.send(Message::ClearDiagnostics);
                self.restart_check_process();
            }
        }
    }

    fn clean_previous_results(&self) {
        self.send(Message::ClearDiagnostics);
        self.send(Message::Progress(Progress::End));
    }

    fn should_recheck(&mut self) -> bool {
        if let Some(_last_update_req) = &self.last_update_req {
            // We currently only request an update on save, as we need up to
            // date source on disk for cargo check to do it's magic, so we
            // don't really need to debounce the requests at this point.
            return true;
        }
        false
    }

    fn handle_command(&mut self, cmd: CheckCommand) {
        match cmd {
            CheckCommand::Update => self.last_update_req = Some(Instant::now()),
        }
    }

    fn handle_message(&self, msg: CheckEvent) {
        match msg {
            CheckEvent::Begin => {
                self.send(Message::Progress(Progress::Being));
            }

            CheckEvent::End => {
                self.send(Message::Progress(Progress::End));
            }

            CheckEvent::Msg(cargo_metadata::Message::CompilerArtifact(msg)) => {
                self.send(Message::Progress(Progress::DidCheckCrate(msg.target.name)));
            }

            CheckEvent::Msg(cargo_metadata::Message::CompilerMessage(msg)) => {
                self.send(Message::AddDiagnostic {
                    workspace_root: self.workspace_root.clone(),
                    diagnostic: msg.message,
                });
            }

            CheckEvent::Msg(cargo_metadata::Message::BuildScriptExecuted(_))
            | CheckEvent::Msg(cargo_metadata::Message::BuildFinished(_))
            | CheckEvent::Msg(cargo_metadata::Message::TextLine(_))
            | CheckEvent::Msg(cargo_metadata::Message::Unknown) => {}
        }
    }

    fn restart_check_process(&mut self) {
        // First, clear and cancel the old thread
        self.message_recv = never();
        self.check_process = None;

        let mut cmd = match &self.config {
            FlycheckConfig::CargoCommand {
                command,
                all_targets,
                all_features,
                extra_args,
                features,
            } => {
                let mut cmd = Command::new(ra_toolchain::cargo());
                cmd.arg(command);
                cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
                    .arg(self.workspace_root.join("Cargo.toml"));
                if *all_targets {
                    cmd.arg("--all-targets");
                }
                if *all_features {
                    cmd.arg("--all-features");
                } else if !features.is_empty() {
                    cmd.arg("--features");
                    cmd.arg(features.join(" "));
                }
                cmd.args(extra_args);
                cmd
            }
            FlycheckConfig::CustomCommand { command, args } => {
                let mut cmd = Command::new(command);
                cmd.args(args);
                cmd
            }
        };
        cmd.current_dir(&self.workspace_root);

        let (message_send, message_recv) = unbounded();
        self.message_recv = message_recv;
        self.check_process = Some(jod_thread::spawn(move || {
            // If we trigger an error here, we will do so in the loop instead,
            // which will break out of the loop, and continue the shutdown
            let _ = message_send.send(CheckEvent::Begin);

            let res = run_cargo(cmd, &mut |message| {
                // Skip certain kinds of messages to only spend time on what's useful
                match &message {
                    cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => {
                        return true
                    }
                    cargo_metadata::Message::BuildScriptExecuted(_)
                    | cargo_metadata::Message::Unknown => return true,
                    _ => {}
                }

                // if the send channel was closed, we want to shutdown
                message_send.send(CheckEvent::Msg(message)).is_ok()
            });

            if let Err(err) = res {
                // FIXME: make the `message_send` to be `Sender<Result<CheckEvent, CargoError>>`
                // to display user-caused misconfiguration errors instead of just logging them here
                log::error!("Cargo watcher failed {:?}", err);
            }

            // We can ignore any error here, as we are already in the progress
            // of shutting down.
            let _ = message_send.send(CheckEvent::End);
        }))
    }

    fn send(&self, check_task: Message) {
        (self.sender)(check_task)
    }
}

enum CheckEvent {
    Begin,
    Msg(cargo_metadata::Message),
    End,
}

fn run_cargo(
    mut command: Command,
    on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool,
) -> io::Result<()> {
    let mut child =
        command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()).spawn()?;

    // We manually read a line at a time, instead of using serde's
    // stream deserializers, because the deserializer cannot recover
    // from an error, resulting in it getting stuck, because we try to
    // be resillient against failures.
    //
    // Because cargo only outputs one JSON object per line, we can
    // simply skip a line if it doesn't parse, which just ignores any
    // erroneus output.
    let stdout = BufReader::new(child.stdout.take().unwrap());
    let mut read_at_least_one_message = false;
    for message in cargo_metadata::Message::parse_stream(stdout) {
        let message = match message {
            Ok(message) => message,
            Err(err) => {
                log::error!("Invalid json from cargo check, ignoring ({})", err);
                continue;
            }
        };

        read_at_least_one_message = true;

        if !on_message(message) {
            break;
        }
    }

    // It is okay to ignore the result, as it only errors if the process is already dead
    let _ = child.kill();

    let exit_status = child.wait()?;
    if !exit_status.success() && !read_at_least_one_message {
        // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
        // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
        return Err(io::Error::new(
            io::ErrorKind::Other,
            format!(
                "the command produced no valid metadata (exit code: {:?}): {:?}",
                exit_status, command
            ),
        ));
    }

    Ok(())
}
<commit_msg>Simplify<commit_after>//! cargo_check provides the functionality needed to run `cargo check` or
//! another compatible command (f.x. clippy) in a background thread and provide
//! LSP diagnostics based on the output of the command.

use std::{
    fmt,
    io::{self, BufReader},
    path::PathBuf,
    process::{Command, Stdio},
    time::Instant,
};

use crossbeam_channel::{never, select, unbounded, Receiver, RecvError, Sender};

pub use cargo_metadata::diagnostic::{
    Applicability, Diagnostic, DiagnosticLevel, DiagnosticSpan, DiagnosticSpanMacroExpansion,
};

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FlycheckConfig {
    CargoCommand {
        command: String,
        all_targets: bool,
        all_features: bool,
        features: Vec<String>,
        extra_args: Vec<String>,
    },
    CustomCommand {
        command: String,
        args: Vec<String>,
    },
}

impl fmt::Display for FlycheckConfig {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            FlycheckConfig::CargoCommand { command, .. } => write!(f, "cargo {}", command),
            FlycheckConfig::CustomCommand { command, args } => {
                write!(f, "{} {}", command, args.join(" "))
            }
        }
    }
}

/// Flycheck wraps the shared state and communication machinery used for
/// running `cargo check` (or other compatible command) and providing
/// diagnostics based on the output.
/// The spawned thread is shut down when this struct is dropped.
#[derive(Debug)]
pub struct FlycheckHandle {
    // XXX: drop order is significant
    cmd_send: Sender<Restart>,
    handle: jod_thread::JoinHandle,
}

impl FlycheckHandle {
    pub fn spawn(
        sender: Box<dyn Fn(Message) + Send>,
        config: FlycheckConfig,
        workspace_root: PathBuf,
    ) -> FlycheckHandle {
        let (cmd_send, cmd_recv) = unbounded::<Restart>();
        let handle = jod_thread::spawn(move || {
            FlycheckActor::new(sender, config, workspace_root).run(&cmd_recv);
        });
        FlycheckHandle { cmd_send, handle }
    }

    /// Schedule a re-start of the cargo check worker.
    pub fn update(&self) {
        self.cmd_send.send(Restart).unwrap();
    }
}

#[derive(Debug)]
pub enum Message {
    /// Request a clearing of all cached diagnostics from the check watcher
    ClearDiagnostics,

    /// Request adding a diagnostic with fixes included to a file
    AddDiagnostic { workspace_root: PathBuf, diagnostic: Diagnostic },

    /// Request check progress notification to client
    Progress(Progress),
}

#[derive(Debug)]
pub enum Progress {
    Being,
    DidCheckCrate(String),
    End,
}

struct Restart;

struct FlycheckActor {
    sender: Box<dyn Fn(Message) + Send>,
    config: FlycheckConfig,
    workspace_root: PathBuf,
    last_update_req: Option<Instant>,
    // XXX: drop order is significant
    message_recv: Receiver<CheckEvent>,
    /// WatchThread exists to wrap around the communication needed to be able to
    /// run `cargo check` without blocking. Currently the Rust standard library
    /// doesn't provide a way to read sub-process output without blocking, so we
    /// have to wrap sub-processes output handling in a thread and pass messages
    /// back over a channel.
    check_process: Option<jod_thread::JoinHandle>,
}

impl FlycheckActor {
    fn new(
        sender: Box<dyn Fn(Message) + Send>,
        config: FlycheckConfig,
        workspace_root: PathBuf,
    ) -> FlycheckActor {
        FlycheckActor {
            sender,
            config,
            workspace_root,
            last_update_req: None,
            message_recv: never(),
            check_process: None,
        }
    }

    fn run(&mut self, cmd_recv: &Receiver<Restart>) {
        // If we rerun the thread, we need to discard the previous check results first
        self.clean_previous_results();

        loop {
            select! {
                recv(&cmd_recv) -> cmd => match cmd {
                    Ok(Restart) => self.last_update_req = Some(Instant::now()),
                    Err(RecvError) => {
                        // Command channel has closed, so shut down
                        break;
                    },
                },
                recv(self.message_recv) -> msg => match msg {
                    Ok(msg) => self.handle_message(msg),
                    Err(RecvError) => {
                        // Watcher finished, replace it with a never channel to
                        // avoid busy-waiting.
                        self.message_recv = never();
                        self.check_process = None;
                    },
                }
            };

            if self.should_recheck() {
                self.last_update_req = None;
                self.send(Message::ClearDiagnostics);
                self.restart_check_process();
            }
        }
    }

    fn clean_previous_results(&self) {
        self.send(Message::ClearDiagnostics);
        self.send(Message::Progress(Progress::End));
    }

    fn should_recheck(&mut self) -> bool {
        if let Some(_last_update_req) = &self.last_update_req {
            // We currently only request an update on save, as we need up to
            // date source on disk for cargo check to do it's magic, so we
            // don't really need to debounce the requests at this point.
            return true;
        }
        false
    }

    fn handle_message(&self, msg: CheckEvent) {
        match msg {
            CheckEvent::Begin => {
                self.send(Message::Progress(Progress::Being));
            }

            CheckEvent::End => {
                self.send(Message::Progress(Progress::End));
            }

            CheckEvent::Msg(cargo_metadata::Message::CompilerArtifact(msg)) => {
                self.send(Message::Progress(Progress::DidCheckCrate(msg.target.name)));
            }

            CheckEvent::Msg(cargo_metadata::Message::CompilerMessage(msg)) => {
                self.send(Message::AddDiagnostic {
                    workspace_root: self.workspace_root.clone(),
                    diagnostic: msg.message,
                });
            }

            CheckEvent::Msg(cargo_metadata::Message::BuildScriptExecuted(_))
            | CheckEvent::Msg(cargo_metadata::Message::BuildFinished(_))
            | CheckEvent::Msg(cargo_metadata::Message::TextLine(_))
            | CheckEvent::Msg(cargo_metadata::Message::Unknown) => {}
        }
    }

    fn restart_check_process(&mut self) {
        // First, clear and cancel the old thread
        self.message_recv = never();
        self.check_process = None;

        let mut cmd = match &self.config {
            FlycheckConfig::CargoCommand {
                command,
                all_targets,
                all_features,
                extra_args,
                features,
            } => {
                let mut cmd = Command::new(ra_toolchain::cargo());
                cmd.arg(command);
                cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
                    .arg(self.workspace_root.join("Cargo.toml"));
                if *all_targets {
                    cmd.arg("--all-targets");
                }
                if *all_features {
                    cmd.arg("--all-features");
                } else if !features.is_empty() {
                    cmd.arg("--features");
                    cmd.arg(features.join(" "));
                }
                cmd.args(extra_args);
                cmd
            }
            FlycheckConfig::CustomCommand { command, args } => {
                let mut cmd = Command::new(command);
                cmd.args(args);
                cmd
            }
        };
        cmd.current_dir(&self.workspace_root);

        let (message_send, message_recv) = unbounded();
        self.message_recv = message_recv;
        self.check_process = Some(jod_thread::spawn(move || {
            // If we trigger an error here, we will do so in the loop instead,
            // which will break out of the loop, and continue the shutdown
            let _ = message_send.send(CheckEvent::Begin);

            let res = run_cargo(cmd, &mut |message| {
                // Skip certain kinds of messages to only spend time on what's useful
                match &message {
                    cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => {
                        return true
                    }
                    cargo_metadata::Message::BuildScriptExecuted(_)
                    | cargo_metadata::Message::Unknown => return true,
                    _ => {}
                }

                // if the send channel was closed, we want to shutdown
                message_send.send(CheckEvent::Msg(message)).is_ok()
            });

            if let Err(err) = res {
                // FIXME: make the `message_send` to be `Sender<Result<CheckEvent, CargoError>>`
                // to display user-caused misconfiguration errors instead of just logging them here
                log::error!("Cargo watcher failed {:?}", err);
            }

            // We can ignore any error here, as we are already in the progress
            // of shutting down.
            let _ = message_send.send(CheckEvent::End);
        }))
    }

    fn send(&self, check_task: Message) {
        (self.sender)(check_task)
    }
}

enum CheckEvent {
    Begin,
    Msg(cargo_metadata::Message),
    End,
}

fn run_cargo(
    mut command: Command,
    on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool,
) -> io::Result<()> {
    let mut child =
        command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()).spawn()?;

    // We manually read a line at a time, instead of using serde's
    // stream deserializers, because the deserializer cannot recover
    // from an error, resulting in it getting stuck, because we try to
    // be resillient against failures.
    //
    // Because cargo only outputs one JSON object per line, we can
    // simply skip a line if it doesn't parse, which just ignores any
    // erroneus output.
    let stdout = BufReader::new(child.stdout.take().unwrap());
    let mut read_at_least_one_message = false;
    for message in cargo_metadata::Message::parse_stream(stdout) {
        let message = match message {
            Ok(message) => message,
            Err(err) => {
                log::error!("Invalid json from cargo check, ignoring ({})", err);
                continue;
            }
        };

        read_at_least_one_message = true;

        if !on_message(message) {
            break;
        }
    }

    // It is okay to ignore the result, as it only errors if the process is already dead
    let _ = child.kill();

    let exit_status = child.wait()?;
    if !exit_status.success() && !read_at_least_one_message {
        // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
        // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
        return Err(io::Error::new(
            io::ErrorKind::Other,
            format!(
                "the command produced no valid metadata (exit code: {:?}): {:?}",
                exit_status, command
            ),
        ));
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Synchronization primitives for Vulkan objects.
//!
//! In Vulkan, you have to manually ensure two things:
//!
//! - That a buffer or an image are not read and written simultaneously (similarly to the CPU).
//! - That writes to a buffer or an image are propagated to other queues by inserting memory
//!   barriers.
//!
//! But don't worry ; this is automatically enforced by this library (as long as you don't use
//! any unsafe function). See the `memory` module for more info.
//!
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;

use device::Device;
use device::Queue;
use OomError;
use Success;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

pub unsafe trait Resource {
    /// Returns in which queue family or families this resource can be used.
    fn sharing_mode(&self) -> &SharingMode;

    /// Returns true if the `gpu_access` function should be passed a fence.
    #[inline]
    fn requires_fence(&self) -> bool {
        true
    }

    /// Returns true if the `gpu_access` function should be passed a semaphore.
    #[inline]
    fn requires_semaphore(&self) -> bool {
        true
    }

    /// Instructs the resource that it is going to be used by the GPU soon in the future. The
    /// function should block if the memory is currently being accessed by the CPU.
    ///
    /// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
    /// be written.
    ///
    /// `queue` is the queue where the command buffer that accesses the memory will be submitted.
    /// If the `gpu_access` function submits something to that queue, it will thus be submitted
    /// beforehand. This behavior can be used for example to submit sparse binding commands.
    ///
    /// `fence` is a fence that will be signaled when this GPU access will stop. It should be
    /// waited upon whenever the user wants to read this memory from the CPU. If `requires_fence`
    /// returned false, then this value will be `None`.
    ///
    /// `semaphore` is a semaphore that will be signaled when this GPU access will stop. This value
    /// is intended to be returned later, in a follow-up call to `gpu_access`. If
    /// `requires_semaphore` returned false, then this value will be `None`.
    ///
    /// The function is allowed to return up to two semaphores which will be waited up by the GPU
    /// before the work starts.
    fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
                  semaphore: Option<Arc<Semaphore>>)
                  -> (Option<Arc<Semaphore>>, Option<Arc<Semaphore>>);
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SharingMode {
    Exclusive(u32),
    Concurrent(Vec<u32>),       // TODO: Vec is too expensive here
}

impl<'a> From<&'a Arc<Mutex<Queue>>> for SharingMode {
    #[inline]
    fn from(queue: &'a Arc<Mutex<Queue>>) -> SharingMode {
        let queue = queue.lock().unwrap();      // TODO: meh
        SharingMode::Exclusive(queue.family().id())
    }
}

impl<'a> From<&'a [&'a Arc<Mutex<Queue>>]> for SharingMode {
    #[inline]
    fn from(queues: &'a [&'a Arc<Mutex<Queue>>]) -> SharingMode {
        SharingMode::Concurrent(queues.iter().map(|queue| {
            let queue = queue.lock().unwrap();      // TODO: meh
            queue.family().id()
        }).collect())
    }
}

/// A fence is used to know when a command buffer submission has finished its execution.
///
/// When a command buffer accesses a ressource, you have to ensure that the CPU doesn't access
/// the same ressource simultaneously (except for concurrent reads). Therefore in order to know
/// when the CPU can access a ressource again, a fence has to be used.
pub struct Fence {
    device: Arc<Device>,
    fence: vk::Fence,
}

impl Fence {
    /// Builds a new fence.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Fence>, OomError> {
        Fence::new_impl(device, false)
    }

    /// Builds a new fence already in the "signaled" state.
    #[inline]
    pub fn signaled(device: &Arc<Device>) -> Result<Arc<Fence>, OomError> {
        Fence::new_impl(device, true)
    }

    fn new_impl(device: &Arc<Device>, signaled: bool) -> Result<Arc<Fence>, OomError> {
        let vk = device.pointers();

        let fence = unsafe {
            let infos = vk::FenceCreateInfo {
                sType: vk::STRUCTURE_TYPE_FENCE_CREATE_INFO,
                pNext: ptr::null(),
                flags: if signaled { vk::FENCE_CREATE_SIGNALED_BIT } else { 0 },
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateFence(device.internal_object(), &infos, ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Fence {
            device: device.clone(),
            fence: fence,
        }))
    }

    /// Returns true if the fence is signaled.
    #[inline]
    pub fn ready(&self) -> Result<bool, OomError> {
        unsafe {
            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetFenceStatus(self.device.internal_object(),
                                                             self.fence)));
            match result {
                Success::Success => Ok(true),
                Success::NotReady => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Waits until the fence is signaled, or at least until the number of nanoseconds of the
    /// timeout has elapsed.
    ///
    /// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead.
    pub fn wait(&self, timeout_ns: u64) -> Result<(), ()> {
        unsafe {
            let vk = self.device.pointers();
            vk.WaitForFences(self.device.internal_object(), 1, &self.fence, vk::TRUE, timeout_ns);
            Ok(())      // FIXME:
        }
    }

    /// Resets the fence.
    #[inline]
    pub fn reset(&self) {
        unsafe {
            let vk = self.device.pointers();
            vk.ResetFences(self.device.internal_object(), 1, &self.fence);
        }
    }

    /// Resets multiple fences at once.
    ///
    /// # Panic
    ///
    /// Panicks if not all fences belong to the same device.
    pub fn multi_reset<'a, I>(iter: I)
        where I: IntoIterator<Item = &'a Fence>
    {
        let mut device = None;

        let fences: Vec<vk::Fence> = iter.into_iter().map(|fence| {
            match &mut device {
                dev @ &mut None => *dev = Some(fence.device.clone()),
                &mut Some(ref dev) if &**dev as *const Device == &*fence.device as *const Device => {},
                _ => panic!("Tried to reset multiple fences that didn't belong to the same device"),
            };

            fence.fence
        }).collect();

        if let Some(device) = device {
            unsafe {
                let vk = device.pointers();
                vk.ResetFences(device.internal_object(), fences.len() as u32, fences.as_ptr());
            }
        }
    }
}

impl VulkanObject for Fence {
    type Object = vk::Fence;

    #[inline]
    fn internal_object(&self) -> vk::Fence {
        self.fence
    }
}

impl Drop for Fence {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyFence(self.device.internal_object(), self.fence, ptr::null());
        }
    }
}

/// Used to provide synchronization between command buffers during their execution.
///
/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
/// semaphore's status or wait for it to be signaled.
///
pub struct Semaphore {
    device: Arc<Device>,
    semaphore: vk::Semaphore,
}

impl Semaphore {
    /// Builds a new semaphore.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Semaphore>, OomError> {
        let vk = device.pointers();

        let semaphore = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::SemaphoreCreateInfo = vk::SemaphoreCreateInfo {
                sType: vk::STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
                pNext: 0 as *const _,   // ptr::null()
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSemaphore(device.internal_object(), &INFOS,
                                                 ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Semaphore {
            device: device.clone(),
            semaphore: semaphore,
        }))
    }
}

impl VulkanObject for Semaphore {
    type Object = vk::Semaphore;

    #[inline]
    fn internal_object(&self) -> vk::Semaphore {
        self.semaphore
    }
}

impl Drop for Semaphore {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySemaphore(self.device.internal_object(), self.semaphore, ptr::null());
        }
    }
}

/// Used to block the GPU execution until an event on the CPU occurs.
///
/// Note that Vulkan implementations may have limits on how long a command buffer will wait for an
/// event to be signaled, in order to avoid interfering with progress of other clients of the GPU.
/// If the event isn't signaled within these limits, results are undefined and may include
/// device loss.
pub struct Event {
    device: Arc<Device>,
    event: vk::Event,
}

impl Event {
    /// Builds a new event.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Event>, OomError> {
        let vk = device.pointers();

        let event = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::EventCreateInfo = vk::EventCreateInfo {
                sType: vk::STRUCTURE_TYPE_EVENT_CREATE_INFO,
                pNext: 0 as *const _, //ptr::null(),
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateEvent(device.internal_object(), &INFOS,
                                             ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Event {
            device: device.clone(),
            event: event,
        }))
    }

    /// Returns true if the event is signaled.
    #[inline]
    pub fn signaled(&self) -> Result<bool, OomError> {
        unsafe {
            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetEventStatus(self.device.internal_object(),
                                                             self.event)));
            match result {
                Success::EventSet => Ok(true),
                Success::EventReset => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Changes the `Event` to the signaled state.
    ///
    /// If a command buffer is waiting on this event, it is then unblocked.
    #[inline]
    pub fn set(&self) -> Result<(), OomError> {
        unsafe {
            let vk = self.device.pointers();
            try!(check_errors(vk.SetEvent(self.device.internal_object(), self.event)).map(|_| ()));
            Ok(())
        }
    }

    /// Changes the `Event` to the unsignaled state.
    #[inline]
    pub fn reset(&self) -> Result<(), OomError> {
        unsafe {
            let vk = self.device.pointers();
            try!(check_errors(vk.ResetEvent(self.device.internal_object(), self.event)).map(|_| ()));
            Ok(())
        }
    }
}

impl VulkanObject for Event {
    type Object = vk::Event;

    #[inline]
    fn internal_object(&self) -> vk::Event {
        self.event
    }
}

impl Drop for Event {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyEvent(self.device.internal_object(), self.event, ptr::null());
        }
    }
}
<commit_msg>Better error detection in fence waiting<commit_after>//! Synchronization primitives for Vulkan objects.
//!
//! In Vulkan, you have to manually ensure two things:
//!
//! - That a buffer or an image are not read and written simultaneously (similarly to the CPU).
//! - That writes to a buffer or an image are propagated to other queues by inserting memory
//!   barriers.
//!
//! But don't worry ; this is automatically enforced by this library (as long as you don't use
//! any unsafe function). See the `memory` module for more info.
//!
use std::mem;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;

use device::Device;
use device::Queue;
use OomError;
use Success;
use VulkanObject;
use VulkanPointers;
use check_errors;
use vk;

pub unsafe trait Resource {
    /// Returns in which queue family or families this resource can be used.
    fn sharing_mode(&self) -> &SharingMode;

    /// Returns true if the `gpu_access` function should be passed a fence.
    #[inline]
    fn requires_fence(&self) -> bool {
        true
    }

    /// Returns true if the `gpu_access` function should be passed a semaphore.
    #[inline]
    fn requires_semaphore(&self) -> bool {
        true
    }

    /// Instructs the resource that it is going to be used by the GPU soon in the future. The
    /// function should block if the memory is currently being accessed by the CPU.
    ///
    /// `write` indicates whether the GPU will write to the memory. If `false`, then it will only
    /// be written.
    ///
    /// `queue` is the queue where the command buffer that accesses the memory will be submitted.
    /// If the `gpu_access` function submits something to that queue, it will thus be submitted
    /// beforehand. This behavior can be used for example to submit sparse binding commands.
    ///
    /// `fence` is a fence that will be signaled when this GPU access will stop. It should be
    /// waited upon whenever the user wants to read this memory from the CPU. If `requires_fence`
    /// returned false, then this value will be `None`.
    ///
    /// `semaphore` is a semaphore that will be signaled when this GPU access will stop. This value
    /// is intended to be returned later, in a follow-up call to `gpu_access`. If
    /// `requires_semaphore` returned false, then this value will be `None`.
    ///
    /// The function is allowed to return up to two semaphores which will be waited up by the GPU
    /// before the work starts.
    fn gpu_access(&self, write: bool, queue: &mut Queue, fence: Option<Arc<Fence>>,
                  semaphore: Option<Arc<Semaphore>>)
                  -> (Option<Arc<Semaphore>>, Option<Arc<Semaphore>>);
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SharingMode {
    Exclusive(u32),
    Concurrent(Vec<u32>),       // TODO: Vec is too expensive here
}

impl<'a> From<&'a Arc<Mutex<Queue>>> for SharingMode {
    #[inline]
    fn from(queue: &'a Arc<Mutex<Queue>>) -> SharingMode {
        let queue = queue.lock().unwrap();      // TODO: meh
        SharingMode::Exclusive(queue.family().id())
    }
}

impl<'a> From<&'a [&'a Arc<Mutex<Queue>>]> for SharingMode {
    #[inline]
    fn from(queues: &'a [&'a Arc<Mutex<Queue>>]) -> SharingMode {
        SharingMode::Concurrent(queues.iter().map(|queue| {
            let queue = queue.lock().unwrap();      // TODO: meh
            queue.family().id()
        }).collect())
    }
}

/// A fence is used to know when a command buffer submission has finished its execution.
///
/// When a command buffer accesses a ressource, you have to ensure that the CPU doesn't access
/// the same ressource simultaneously (except for concurrent reads). Therefore in order to know
/// when the CPU can access a ressource again, a fence has to be used.
pub struct Fence {
    device: Arc<Device>,
    fence: vk::Fence,
}

impl Fence {
    /// Builds a new fence.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Fence>, OomError> {
        Fence::new_impl(device, false)
    }

    /// Builds a new fence already in the "signaled" state.
    #[inline]
    pub fn signaled(device: &Arc<Device>) -> Result<Arc<Fence>, OomError> {
        Fence::new_impl(device, true)
    }

    fn new_impl(device: &Arc<Device>, signaled: bool) -> Result<Arc<Fence>, OomError> {
        let vk = device.pointers();

        let fence = unsafe {
            let infos = vk::FenceCreateInfo {
                sType: vk::STRUCTURE_TYPE_FENCE_CREATE_INFO,
                pNext: ptr::null(),
                flags: if signaled { vk::FENCE_CREATE_SIGNALED_BIT } else { 0 },
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateFence(device.internal_object(), &infos, ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Fence {
            device: device.clone(),
            fence: fence,
        }))
    }

    /// Returns true if the fence is signaled.
    #[inline]
    pub fn ready(&self) -> Result<bool, OomError> {
        unsafe {
            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetFenceStatus(self.device.internal_object(),
                                                             self.fence)));
            match result {
                Success::Success => Ok(true),
                Success::NotReady => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Waits until the fence is signaled, or at least until the number of nanoseconds of the
    /// timeout has elapsed.
    ///
    /// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead.
    pub fn wait(&self, timeout_ns: u64) -> Result<(), OomError> {       // FIXME: wrong error
        unsafe {
            let vk = self.device.pointers();
            let r = try!(check_errors(vk.WaitForFences(self.device.internal_object(), 1,
                                                       &self.fence, vk::TRUE, timeout_ns)));

            match r {
                Success::Success => Ok(()),
                Success::Timeout => panic!(),        // FIXME:
                _ => unreachable!()
            }
        }
    }

    /// Resets the fence.
    #[inline]
    pub fn reset(&self) {
        unsafe {
            let vk = self.device.pointers();
            vk.ResetFences(self.device.internal_object(), 1, &self.fence);
        }
    }

    /// Resets multiple fences at once.
    ///
    /// # Panic
    ///
    /// Panicks if not all fences belong to the same device.
    pub fn multi_reset<'a, I>(iter: I)
        where I: IntoIterator<Item = &'a Fence>
    {
        let mut device = None;

        let fences: Vec<vk::Fence> = iter.into_iter().map(|fence| {
            match &mut device {
                dev @ &mut None => *dev = Some(fence.device.clone()),
                &mut Some(ref dev) if &**dev as *const Device == &*fence.device as *const Device => {},
                _ => panic!("Tried to reset multiple fences that didn't belong to the same device"),
            };

            fence.fence
        }).collect();

        if let Some(device) = device {
            unsafe {
                let vk = device.pointers();
                vk.ResetFences(device.internal_object(), fences.len() as u32, fences.as_ptr());
            }
        }
    }
}

impl VulkanObject for Fence {
    type Object = vk::Fence;

    #[inline]
    fn internal_object(&self) -> vk::Fence {
        self.fence
    }
}

impl Drop for Fence {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyFence(self.device.internal_object(), self.fence, ptr::null());
        }
    }
}

/// Used to provide synchronization between command buffers during their execution.
///
/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
/// semaphore's status or wait for it to be signaled.
///
pub struct Semaphore {
    device: Arc<Device>,
    semaphore: vk::Semaphore,
}

impl Semaphore {
    /// Builds a new semaphore.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Semaphore>, OomError> {
        let vk = device.pointers();

        let semaphore = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::SemaphoreCreateInfo = vk::SemaphoreCreateInfo {
                sType: vk::STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
                pNext: 0 as *const _,   // ptr::null()
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateSemaphore(device.internal_object(), &INFOS,
                                                 ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Semaphore {
            device: device.clone(),
            semaphore: semaphore,
        }))
    }
}

impl VulkanObject for Semaphore {
    type Object = vk::Semaphore;

    #[inline]
    fn internal_object(&self) -> vk::Semaphore {
        self.semaphore
    }
}

impl Drop for Semaphore {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroySemaphore(self.device.internal_object(), self.semaphore, ptr::null());
        }
    }
}

/// Used to block the GPU execution until an event on the CPU occurs.
///
/// Note that Vulkan implementations may have limits on how long a command buffer will wait for an
/// event to be signaled, in order to avoid interfering with progress of other clients of the GPU.
/// If the event isn't signaled within these limits, results are undefined and may include
/// device loss.
pub struct Event {
    device: Arc<Device>,
    event: vk::Event,
}

impl Event {
    /// Builds a new event.
    #[inline]
    pub fn new(device: &Arc<Device>) -> Result<Arc<Event>, OomError> {
        let vk = device.pointers();

        let event = unsafe {
            // since the creation is constant, we use a `static` instead of a struct on the stack
            static mut INFOS: vk::EventCreateInfo = vk::EventCreateInfo {
                sType: vk::STRUCTURE_TYPE_EVENT_CREATE_INFO,
                pNext: 0 as *const _, //ptr::null(),
                flags: 0,   // reserved
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateEvent(device.internal_object(), &INFOS,
                                             ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(Event {
            device: device.clone(),
            event: event,
        }))
    }

    /// Returns true if the event is signaled.
    #[inline]
    pub fn signaled(&self) -> Result<bool, OomError> {
        unsafe {
            let vk = self.device.pointers();
            let result = try!(check_errors(vk.GetEventStatus(self.device.internal_object(),
                                                             self.event)));
            match result {
                Success::EventSet => Ok(true),
                Success::EventReset => Ok(false),
                _ => unreachable!()
            }
        }
    }

    /// Changes the `Event` to the signaled state.
    ///
    /// If a command buffer is waiting on this event, it is then unblocked.
    #[inline]
    pub fn set(&self) -> Result<(), OomError> {
        unsafe {
            let vk = self.device.pointers();
            try!(check_errors(vk.SetEvent(self.device.internal_object(), self.event)).map(|_| ()));
            Ok(())
        }
    }

    /// Changes the `Event` to the unsignaled state.
    #[inline]
    pub fn reset(&self) -> Result<(), OomError> {
        unsafe {
            let vk = self.device.pointers();
            try!(check_errors(vk.ResetEvent(self.device.internal_object(), self.event)).map(|_| ()));
            Ok(())
        }
    }
}

impl VulkanObject for Event {
    type Object = vk::Event;

    #[inline]
    fn internal_object(&self) -> vk::Event {
        self.event
    }
}

impl Drop for Event {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyEvent(self.device.internal_object(), self.event, ptr::null());
        }
    }
}
<|endoftext|>


<commit_before>extern crate arrayfire as af;
extern crate time;

use time::PreciseTime;
use af::Dim4;
use af::Aftype;

fn main() {
    af::set_device(0);
    af::info();
    let samples = 20_000_000;
    let dims = Dim4::new(&[samples, 1, 1, 1]);

    let x = &af::randu(dims, Aftype::F32).unwrap();
    let y = &af::randu(dims, Aftype::F32).unwrap();

    let start = PreciseTime::now();
    let pi_val = af::add(&(x*x), &(y*y))
    //let pi_val = af::sqrt(&(x*x) + &(y*y))
        .and_then( |z| af::sqrt(&z) )
        .and_then( |z| af::le(&z, &af::constant(1, dims).unwrap()) )
        .and_then( |z| af::sum_all(&z) )
        .map( |z| z.0 * 4.0/(samples as  f64) )
        .unwrap();
    let end = PreciseTime::now();

    println!("Estimated Pi Value: {} in {} seconds", pi_val, start.to(end));
}
<commit_msg>Modified pi example to report benchmarked runtime<commit_after>extern crate arrayfire as af;
extern crate time;

use time::PreciseTime;
use af::Dim4;
use af::Aftype;

#[allow(unused_must_use)]
#[allow(unused_variables)]
fn main() {
    af::set_device(0);
    af::info();
    let samples = 20_000_000;
    let dims = Dim4::new(&[samples, 1, 1, 1]);

    let x = &af::randu(dims, Aftype::F32).unwrap();
    let y = &af::randu(dims, Aftype::F32).unwrap();

    let start = PreciseTime::now();

    for bench_iter in 0..100 {
        let pi_val = af::add(&(x*x), &(y*y))
            .and_then( |z| af::sqrt(&z) )
            .and_then( |z| af::le(&z, &af::constant(1, dims).unwrap()) )
            .and_then( |z| af::sum_all(&z) )
            .map( |z| z.0 * 4.0/(samples as  f64) )
            .unwrap();
    }

    let end = PreciseTime::now();

    println!("Estimated Pi Value in {} seconds", start.to(end) / 100);
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate serde;

use serde::Serialize;
use std::fs::File;
use std::path::Path;

use clap::{Arg, ArgMatches};

/// Defines a mapping between a template variable, and the file to
/// populate it.
///
#[derive(Debug)]
pub struct VarMapping<'a> {
    var_name: &'a str,
    file_path: &'a str
}

impl<'a> VarMapping<'a> {
    /// Builds a VarMapping from a String
    ///
    pub fn from_str(s: &'a str) -> Result<VarMapping<'a>, &'static str> {
        let mut splits = s.splitn(2, ":");
        let var_name = splits.next().unwrap();

        match splits.next() {
            Some(file_path) => {
                Ok(VarMapping {
                    var_name: var_name,
                    file_path: file_path,
                })
            }
            None => Err("Expected a ':' in var mapping string")
        }
    }

    /// Builds a VarMapping from a String, and panics if it fails.
    ///
    #[inline]
    pub fn from_str_panic(s: &'a str) -> VarMapping<'a> {
        match VarMapping::from_str(s) {
            Ok(s) => s,
            Err(e) => panic!(e),
        }
    }

    #[inline]
    pub fn file_path(&self) -> &'a str {
        self.file_path
    }

    #[inline]
    pub fn var_name(&self) -> &'a str {
        self.var_name
    }
}

/// A plugin that can assign a value to a variable in the Tera context from a
/// file.
///
pub trait CompileVariablePlugin {
    /// The serializable value to add to the Tera context.
    ///
    type RenderValue : Serialize;

    /// The name of the plugin.
    ///
    fn plugin_name() -> &'static str;

    /// The name of the argument that provides the variable name to file mapping.
    ///
    fn arg_full_name() -> &'static str;

    /// The help string to display.
    ///
    fn arg_help() -> &'static str;

    /// Optional arguments to supply. These should be prefixed to avoid namespace clashes.
    ///
    fn additional_args() -> Vec<Arg<'static, 'static>>;

    /// Constructor for building the plugin from the supplied command line arguments.
    ///
    fn from_args<'a>(args: &'a ArgMatches<'a>) -> Self;

    /// Reads and parses the supplied file. The result is stored in the Tera context.
    ///
    fn read_file(&self, file: File) -> Result<Self::RenderValue, String>;

    /// Reads and parses a file at a specific path.
    ///
    fn read_path<P: AsRef<Path>>(&self, path: P) -> Result<Self::RenderValue, String> {
        match File::open(path) {
            Ok(file) => self.read_file(file),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}
<commit_msg>formatting<commit_after>extern crate clap;
extern crate serde;

use serde::Serialize;
use std::fs::File;
use std::path::Path;

use clap::{Arg, ArgMatches};

/// Defines a mapping between a template variable, and the file to
/// populate it.
///
#[derive(Debug)]
pub struct VarMapping<'a> {
    var_name: &'a str,
    file_path: &'a str,
}

impl<'a> VarMapping<'a> {
    /// Builds a VarMapping from a String
    ///
    pub fn from_str(s: &'a str) -> Result<VarMapping<'a>, &'static str> {
        let mut splits = s.splitn(2, ":");
        let var_name = splits.next().unwrap();

        match splits.next() {
            Some(file_path) => {
                Ok(VarMapping {
                    var_name: var_name,
                    file_path: file_path,
                })
            }
            None => Err("Expected a ':' in var mapping string"),
        }
    }

    /// Builds a VarMapping from a String, and panics if it fails.
    ///
    #[inline]
    pub fn from_str_panic(s: &'a str) -> VarMapping<'a> {
        match VarMapping::from_str(s) {
            Ok(s) => s,
            Err(e) => panic!(e),
        }
    }

    #[inline]
    pub fn file_path(&self) -> &'a str {
        self.file_path
    }

    #[inline]
    pub fn var_name(&self) -> &'a str {
        self.var_name
    }
}

/// A plugin that can assign a value to a variable in the Tera context from a
/// file.
///
pub trait CompileVariablePlugin {
    /// The serializable value to add to the Tera context.
    ///
    type RenderValue: Serialize;

    /// The name of the plugin.
    ///
    fn plugin_name() -> &'static str;

    /// The name of the argument that provides the variable name to file mapping.
    ///
    fn arg_full_name() -> &'static str;

    /// The help string to display.
    ///
    fn arg_help() -> &'static str;

    /// Optional arguments to supply. These should be prefixed to avoid namespace clashes.
    ///
    fn additional_args() -> Vec<Arg<'static, 'static>>;

    /// Constructor for building the plugin from the supplied command line arguments.
    ///
    fn from_args<'a>(args: &'a ArgMatches<'a>) -> Self;

    /// Reads and parses the supplied file. The result is stored in the Tera context.
    ///
    fn read_file(&self, file: File) -> Result<Self::RenderValue, String>;

    /// Reads and parses a file at a specific path.
    ///
    fn read_path<P: AsRef<Path>>(&self, path: P) -> Result<Self::RenderValue, String> {
        match File::open(path) {
            Ok(file) => self.read_file(file),
            Err(e) => Err(format!("{:?}", e)),
        }
    }
}
<|endoftext|>


<commit_before>mod multiboot;
mod paging;
mod interrupt;
mod segmentation;

pub use self::paging::{KERNEL_PML4, KERNEL_PDPT, KERNEL_PD,
                       OBJECT_POOL_PT, OBJECT_POOL_START_VADDR,
                       LOCAL_APIC_PAGE_VADDR, IO_APIC_PAGE_VADDR};
pub use self::segmentation::{set_kernel_stack};

use ::{kmain};
use super::{kernel_end_paddr, kernel_start_paddr, kernel_start_vaddr, kernel_end_vaddr, KERNEL_BASE};
use super::paging::{BASE_PAGE_LENGTH, LARGE_PAGE_LENGTH,
                    PD, PT, PML4, PDPT, PTEntry, pd_index, pml4_index, pt_index, pdpt_index};
use self::multiboot::{Multiboot};

use util::{block_count, align_up};

use core::mem;
use core::slice::{self, Iter};
use core::ptr::{Unique};
use core::ops::{Deref};

use common::{PAddr, VAddr, MemoryRegion};

extern {
    static multiboot_sig: u32;
    static multiboot_ptr: u64;
}

// Helper functions
pub fn multiboot_paddr() -> PAddr {
    PAddr::from(multiboot_ptr)
}

pub struct FreeRegionsIterator<'a>(Iter<'a, Option<MemoryRegion>>);

impl<'a> Iterator for FreeRegionsIterator<'a> {
    type Item = MemoryRegion;

    fn next(&mut self) -> Option<Self::Item> {
        let item = self.0.next();

        if item.is_none() {
            None
        } else {
            if item.unwrap().is_none() {
                None
            } else {
                Some(item.unwrap().unwrap())
            }
        }
    }
}

#[derive(Debug)]
pub struct InitInfo {
    free_regions_size: usize,
    free_regions: [Option<MemoryRegion>; 16],
    rinit_region: MemoryRegion,
    kernel_region: MemoryRegion,
}

impl InitInfo {
    pub fn free_regions(&self) -> FreeRegionsIterator {
        FreeRegionsIterator(self.free_regions.iter())
    }

    pub fn kernel_region(&self) -> MemoryRegion {
        self.kernel_region
    }

    pub fn rinit_region(&self) -> MemoryRegion {
        self.rinit_region
    }

    pub fn new(kernel_region: MemoryRegion, rinit_region: MemoryRegion) -> InitInfo {
        InitInfo { free_regions_size: 0,
                   free_regions: [None; 16],
                   kernel_region: kernel_region,
                   rinit_region: rinit_region }
    }

    pub fn push_free_region(&mut self, region: MemoryRegion) {
        self.free_regions[self.free_regions_size] = Some(region);
        self.free_regions_size += 1;
    }
}

fn bootstrap_archinfo() -> (InitInfo, MemoryRegion) {
    let bootinfo = unsafe {
        multiboot::Multiboot::new(multiboot_paddr(), |addr, size| {
            let ptr = mem::transmute(super::kernel_paddr_to_vaddr(addr).into(): usize);
            Some(slice::from_raw_parts(ptr, size))
        })
    }.unwrap();

    log!("bootinfo: {:?}", bootinfo);

    let rinit_module = bootinfo.modules().unwrap().next().unwrap();
    log!("rinit module: {:?}", rinit_module);

    let mut archinfo = InitInfo::new(
        MemoryRegion::new(kernel_start_paddr(),
                          kernel_end_paddr().into(): usize + 1 -
                          kernel_start_paddr().into(): usize),
        MemoryRegion::new(rinit_module.start,
                          rinit_module.end.into(): usize + 1 -
                          rinit_module.start.into(): usize));
    let mut alloc_region: Option<MemoryRegion> = None;

    for area in bootinfo.memory_regions().unwrap() {
        use self::multiboot::{MemoryType};

        if !(area.memory_type() == MemoryType::RAM) {
            continue;
        }

        let mut cur_region = MemoryRegion::new(area.base_address(), area.length() as usize);

        if cur_region.skip_up(&archinfo.kernel_region()) {
            assert!(cur_region.skip_up(&archinfo.rinit_region()));
            alloc_region = Some(cur_region);
        } else {
            archinfo.push_free_region(cur_region);
        }
    }

    (archinfo, alloc_region.unwrap())
}

/// Kernel entrypoint
#[lang="start"]
#[no_mangle]
pub fn kinit() {
    let (mut archinfo, mut alloc_region) = bootstrap_archinfo();

    log!("kernel_start_vaddr: 0x{:x}", kernel_start_vaddr());
    log!("archinfo: {:?}", archinfo);
    log!("alloc_region: {:?}", alloc_region);

    paging::init(&mut alloc_region);
    segmentation::init();
    interrupt::init();

    archinfo.push_free_region(alloc_region);

    let local_apic = ::arch::interrupt::LOCAL_APIC.lock();
    let io_apic = ::arch::interrupt::IO_APIC.lock();
    log!("Local APIC id: 0x{:x}", local_apic.id());
    log!("Local APIC version: 0x{:x}", local_apic.version());
    log!("I/O APIC id: 0x{:x}", io_apic.id());
    log!("I/O APIC version: 0x{:x}", io_apic.version());

    kmain(archinfo);
}
<commit_msg>Fix a bug that LOCAL_APIC is locked in kmain<commit_after>mod multiboot;
mod paging;
mod interrupt;
mod segmentation;

pub use self::paging::{KERNEL_PML4, KERNEL_PDPT, KERNEL_PD,
                       OBJECT_POOL_PT, OBJECT_POOL_START_VADDR,
                       LOCAL_APIC_PAGE_VADDR, IO_APIC_PAGE_VADDR};
pub use self::segmentation::{set_kernel_stack};

use ::{kmain};
use super::{kernel_end_paddr, kernel_start_paddr, kernel_start_vaddr, kernel_end_vaddr, KERNEL_BASE};
use super::paging::{BASE_PAGE_LENGTH, LARGE_PAGE_LENGTH,
                    PD, PT, PML4, PDPT, PTEntry, pd_index, pml4_index, pt_index, pdpt_index};
use self::multiboot::{Multiboot};

use util::{block_count, align_up};

use core::mem;
use core::slice::{self, Iter};
use core::ptr::{Unique};
use core::ops::{Deref};

use common::{PAddr, VAddr, MemoryRegion};

extern {
    static multiboot_sig: u32;
    static multiboot_ptr: u64;
}

// Helper functions
pub fn multiboot_paddr() -> PAddr {
    PAddr::from(multiboot_ptr)
}

pub struct FreeRegionsIterator<'a>(Iter<'a, Option<MemoryRegion>>);

impl<'a> Iterator for FreeRegionsIterator<'a> {
    type Item = MemoryRegion;

    fn next(&mut self) -> Option<Self::Item> {
        let item = self.0.next();

        if item.is_none() {
            None
        } else {
            if item.unwrap().is_none() {
                None
            } else {
                Some(item.unwrap().unwrap())
            }
        }
    }
}

#[derive(Debug)]
pub struct InitInfo {
    free_regions_size: usize,
    free_regions: [Option<MemoryRegion>; 16],
    rinit_region: MemoryRegion,
    kernel_region: MemoryRegion,
}

impl InitInfo {
    pub fn free_regions(&self) -> FreeRegionsIterator {
        FreeRegionsIterator(self.free_regions.iter())
    }

    pub fn kernel_region(&self) -> MemoryRegion {
        self.kernel_region
    }

    pub fn rinit_region(&self) -> MemoryRegion {
        self.rinit_region
    }

    pub fn new(kernel_region: MemoryRegion, rinit_region: MemoryRegion) -> InitInfo {
        InitInfo { free_regions_size: 0,
                   free_regions: [None; 16],
                   kernel_region: kernel_region,
                   rinit_region: rinit_region }
    }

    pub fn push_free_region(&mut self, region: MemoryRegion) {
        self.free_regions[self.free_regions_size] = Some(region);
        self.free_regions_size += 1;
    }
}

fn bootstrap_archinfo() -> (InitInfo, MemoryRegion) {
    let bootinfo = unsafe {
        multiboot::Multiboot::new(multiboot_paddr(), |addr, size| {
            let ptr = mem::transmute(super::kernel_paddr_to_vaddr(addr).into(): usize);
            Some(slice::from_raw_parts(ptr, size))
        })
    }.unwrap();

    log!("bootinfo: {:?}", bootinfo);

    let rinit_module = bootinfo.modules().unwrap().next().unwrap();
    log!("rinit module: {:?}", rinit_module);

    let mut archinfo = InitInfo::new(
        MemoryRegion::new(kernel_start_paddr(),
                          kernel_end_paddr().into(): usize + 1 -
                          kernel_start_paddr().into(): usize),
        MemoryRegion::new(rinit_module.start,
                          rinit_module.end.into(): usize + 1 -
                          rinit_module.start.into(): usize));
    let mut alloc_region: Option<MemoryRegion> = None;

    for area in bootinfo.memory_regions().unwrap() {
        use self::multiboot::{MemoryType};

        if !(area.memory_type() == MemoryType::RAM) {
            continue;
        }

        let mut cur_region = MemoryRegion::new(area.base_address(), area.length() as usize);

        if cur_region.skip_up(&archinfo.kernel_region()) {
            assert!(cur_region.skip_up(&archinfo.rinit_region()));
            alloc_region = Some(cur_region);
        } else {
            archinfo.push_free_region(cur_region);
        }
    }

    (archinfo, alloc_region.unwrap())
}

/// Kernel entrypoint
#[lang="start"]
#[no_mangle]
pub fn kinit() {
    let (mut archinfo, mut alloc_region) = bootstrap_archinfo();

    log!("kernel_start_vaddr: 0x{:x}", kernel_start_vaddr());
    log!("archinfo: {:?}", archinfo);
    log!("alloc_region: {:?}", alloc_region);

    paging::init(&mut alloc_region);
    segmentation::init();
    interrupt::init();

    archinfo.push_free_region(alloc_region);

    {
        let local_apic = ::arch::interrupt::LOCAL_APIC.lock();
        let io_apic = ::arch::interrupt::IO_APIC.lock();
        log!("Local APIC id: 0x{:x}", local_apic.id());
        log!("Local APIC version: 0x{:x}", local_apic.version());
        log!("I/O APIC id: 0x{:x}", io_apic.id());
        log!("I/O APIC version: 0x{:x}", io_apic.version());
    }

    kmain(archinfo);
}
<|endoftext|>


<commit_before><commit_msg>auto merge of #220 : erickt/cargo/master, r=alexcrichton<commit_after><|endoftext|>


<commit_before>use std::env;

use serenity::{
    async_trait,
    model::{event::ResumedEvent, gateway::Ready, channel::Message},
    prelude::*,
    framework::standard::{
        CommandResult, StandardFramework,
        macros::{command, group, hook},
    },
};

use tracing::{debug, error, info, instrument};

struct Handler;

#[async_trait]
impl EventHandler for Handler {
    async fn ready(&self, _: Context, ready: Ready) {
        // Log at the INFO level. This is a macro from the `log` crate.
        info!("{} is connected!", ready.user.name);
    }

    // For instrument to work, all parameters must implement Debug.
    //
    // Handler doesn't implement Debug here, so we specify to skip that argument.
    // Context doesn't implement Debug either, but since it's ignored already, it
    // doesn't need to be skipped.
    #[instrument(skip(self))]
    async fn resume(&self, _: Context, resume: ResumedEvent) {
        // Log at the DEBUG level.
        //
        // In this example, this will not show up in the logs because DEBUG is
        // below INFO, which is the set debug level.
        debug!("Resumed; trace: {:?}", resume.trace);
    }
}

#[hook]
// instrument will show additional information on all the logs that happen inside
// the function.
//
// This additional information includes the function name, along with all it's arguments
// formatted with the Debug impl.
// This additional information will also only be shown if the LOG level is set to `debug`
#[instrument]
async fn before(_: &Context, msg: &Message, command_name: &str) -> bool {
    info!("Got command '{}' by user '{}'", command_name, msg.author.name);

    true
}

#[group]
#[commands(ping)]
struct General;

#[tokio::main]
#[instrument]
async fn main() {
    // Call tracing_subscriber's initialize function, which configures `log` via
    // environment variables.
    //
    // For example, you can say to log all levels INFO and up via setting the
    // environment variable `RUST_LOG` to `INFO`.
    //
    // This environment variable is already preset if you use cargo-make to run
    // the example.
    tracing_subscriber::fmt::init();

    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");

    let framework = StandardFramework::new()
        .configure(|c| c.prefix("~"))
        .before(before)
        .group(&GENERAL_GROUP);

    let mut client = Client::builder(&token)
        .event_handler(Handler)
        .framework(framework)
        .await
        .expect("Err creating client");

    if let Err(why) = client.start().await {
        error!("Client error: {:?}", why);
    }
}

// Currently, the instrument macro doesn't work with commands.
// if you wish to instrument commands, use it on the before function.
#[command]
async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
    if let Err(why) = msg.channel_id.say(&ctx.http, "Pong! : )").await {
        error!("Error sending message: {:?}", why);
    }

    Ok(())
}
<commit_msg>Update comments in the 7th example to mention `tracing` (#1210)<commit_after>use std::env;

use serenity::{
    async_trait,
    model::{event::ResumedEvent, gateway::Ready, channel::Message},
    prelude::*,
    framework::standard::{
        CommandResult, StandardFramework,
        macros::{command, group, hook},
    },
};

use tracing::{debug, error, info, instrument};

struct Handler;

#[async_trait]
impl EventHandler for Handler {
    async fn ready(&self, _: Context, ready: Ready) {
        // Log at the INFO level. This is a macro from the `tracing` crate.
        info!("{} is connected!", ready.user.name);
    }

    // For instrument to work, all parameters must implement Debug.
    //
    // Handler doesn't implement Debug here, so we specify to skip that argument.
    // Context doesn't implement Debug either, but since it's ignored already, it
    // doesn't need to be skipped.
    #[instrument(skip(self))]
    async fn resume(&self, _: Context, resume: ResumedEvent) {
        // Log at the DEBUG level.
        //
        // In this example, this will not show up in the logs because DEBUG is
        // below INFO, which is the set debug level.
        debug!("Resumed; trace: {:?}", resume.trace);
    }
}

#[hook]
// instrument will show additional information on all the logs that happen inside
// the function.
//
// This additional information includes the function name, along with all it's arguments
// formatted with the Debug impl.
// This additional information will also only be shown if the LOG level is set to `debug`
#[instrument]
async fn before(_: &Context, msg: &Message, command_name: &str) -> bool {
    info!("Got command '{}' by user '{}'", command_name, msg.author.name);

    true
}

#[group]
#[commands(ping)]
struct General;

#[tokio::main]
#[instrument]
async fn main() {
    // Call tracing_subscriber's initialize function, which configures `tracing`
    // via environment variables.
    //
    // For example, you can say to log all levels INFO and up via setting the
    // environment variable `RUST_LOG` to `INFO`.
    //
    // This environment variable is already preset if you use cargo-make to run
    // the example.
    tracing_subscriber::fmt::init();

    // Configure the client with your Discord bot token in the environment.
    let token = env::var("DISCORD_TOKEN")
        .expect("Expected a token in the environment");

    let framework = StandardFramework::new()
        .configure(|c| c.prefix("~"))
        .before(before)
        .group(&GENERAL_GROUP);

    let mut client = Client::builder(&token)
        .event_handler(Handler)
        .framework(framework)
        .await
        .expect("Err creating client");

    if let Err(why) = client.start().await {
        error!("Client error: {:?}", why);
    }
}

// Currently, the instrument macro doesn't work with commands.
// if you wish to instrument commands, use it on the before function.
#[command]
async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
    if let Err(why) = msg.channel_id.say(&ctx.http, "Pong! : )").await {
        error!("Error sending message: {:?}", why);
    }

    Ok(())
}
<|endoftext|>