<commit_before>extern crate core;

pub mod json_option;

pub use json_option::JsonOption;

use std::collections::HashMap;
use std::iter::Peekable;
use std::str::Chars;

use core::fmt::{ Display, Formatter, Error };

pub struct Json;

impl Json {
    pub fn parse(text: &str) -> JsonOption {
        let mut char_slice = text.chars();
        Json::parse_slice(&mut (&mut char_slice).peekable())
    }

    pub fn parse_slice(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut content = JsonOption::None;

        'tokenizer: loop {
            let current = match slice.peek() {
                Some(chr) => *chr,
                _         => { break 'tokenizer; }
            };

            match current {
                ' ' | '\r' | '\n' | '\t' => {
                    slice.next();
                },
                '0'...'9' | '-' => {
                    content = Json::parse_number(slice);
                },
                '"' => {
                    content = Json::parse_string(slice);
                },
                '[' => {
                    content = Json::parse_array(slice);
                },
                '{' => {
                    content = Json::parse_object(slice);
                },
                _ => { break 'tokenizer; }
            }
        }

        content
    }

    fn parse_number(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut token    = String::from("");
        let mut is_float = false;

        'tokenizer: loop {
            let chr = match slice.peek() {
                Some(chr) => *chr,
                None      => break 'tokenizer,
            };

            match chr {
                '-' | '0'...'9' => {
                    token.push(chr);
                    slice.next();
                },
                '.' => {
                    token.push(chr);
                    is_float = true;
                    slice.next();
                },
                _ => { break 'tokenizer; }
            }
        }

        if is_float {
            JsonOption::Number(token.parse::<f32>().unwrap())
        } else {
            JsonOption::Integer(token.parse::<i32>().unwrap())
        }
    }

    fn parse_string(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut token      = String::from("");
        let mut proper_end = false;
        let mut is_escaped = false;

        // Consume starting "
        slice.next();

        'tokenizer: for chr in slice {
            match chr {
                '\\' => {
                    if is_escaped {
                        token.push(chr);
                        is_escaped = false;

                    } else {
                        is_escaped = true;
                    }
                },
                '"' => {
                    if is_escaped {
                        token.push(chr);
                        is_escaped = false;

                    } else {
                        proper_end = true;
                        break 'tokenizer;
                    }
                },
                _ => { token.push(chr); }
            }
        }

        if !proper_end {
            panic!("String wasn't properly terminated.");
        }

        JsonOption::String(token)
    }

    fn parse_array(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut content: Vec<JsonOption> = vec![];
        let mut proper_sep = true;
        let mut proper_end = false;

        // Consume starting [
        slice.next();

        'tokenizer: loop {
            loop {
                let chr = match slice.peek() {
                    Some(chr) => *chr,
                    None      => { println!("Broke"); break 'tokenizer },
                };

                match chr {
                    ' ' | '\n' | '\r' | '\t' => { slice.next(); },
                    ',' => {
                        if proper_sep {
                            panic!("Array has no elements between separator.");
                        }

                        proper_sep = true;
                        slice.next();
                    },
                    ']' => {
                        proper_sep = true;
                        proper_end = true;
                        slice.next();
                        break 'tokenizer;
                    },
                    _ => {
                        if !proper_sep {
                            break 'tokenizer;
                        }

                        content.push(Json::parse_slice(slice));
                        proper_sep = false;
                    }
                }
            }
        }

        if !proper_sep {
            panic!("Array has elements without separator.");
        }

        if !proper_end {
            panic!("Array wasn't properly terminated.");
        }

        JsonOption::Array(content)
    }

    fn parse_object(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut content    = HashMap::new();
        let mut proper_kv  = false;
        let mut proper_sep = true;
        let mut proper_end = false;

        let mut value;
        // Consume starting {
        slice.next();

        'tokenizer: loop {
            let mut key   = String::from("");

            'sepcheck: loop {
                let chr = match slice.peek() {
                    Some(chr) => *chr,
                    None      => { println!("Broke"); break 'tokenizer },
                };

                match chr {
                    ' ' | '\n' | '\r' | '\t' => { slice.next(); },
                    ',' => {
                        if proper_sep {
                            panic!("Object has no elements between separator.");
                        }

                        proper_sep = true;
                        slice.next();
                    },
                    ':' => {
                        if proper_kv {
                            panic!("Object has two or more key-value separators together.");
                        }

                        proper_kv = true;
                        slice.next();
                    },
                    '}' => {
                        proper_sep = true;
                        proper_end = true;
                        slice.next();
                        break 'tokenizer;
                    },
                    _ => {
                        if !proper_sep {
                            break 'tokenizer;
                        }

                        if !proper_kv && (key != "") {
                            panic!("Object has no separator between key and value.");
                        }

                        if !proper_kv {
                            key = match Json::parse_slice(slice) {
                                JsonOption::String(string) => string,
                                _ => panic!("Object has invalid element as key."),
                            };

                        } else {
                            value      = Json::parse_slice(slice);
                            proper_kv  = false;
                            proper_sep = false;
                            break 'sepcheck;
                        }
                    }
                }
            }

            content.insert(key, value);
        }

        if !proper_sep {
            panic!("Object has elements without separator.");
        }

        if !proper_end {
            panic!("Object wasn't properly terminated.");
        }

        JsonOption::Object(content)
    }
}

impl Display for Json {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        write!(formatter, "{}", self)
    }
}

<commit_msg>Removing more debug printlns<commit_after>extern crate core;

pub mod json_option;

pub use json_option::JsonOption;

use std::collections::HashMap;
use std::iter::Peekable;
use std::str::Chars;

use core::fmt::{ Display, Formatter, Error };

pub struct Json;

impl Json {
    pub fn parse(text: &str) -> JsonOption {
        let mut char_slice = text.chars();
        Json::parse_slice(&mut (&mut char_slice).peekable())
    }

    pub fn parse_slice(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut content = JsonOption::None;

        'tokenizer: loop {
            let current = match slice.peek() {
                Some(chr) => *chr,
                _         => { break 'tokenizer; }
            };

            match current {
                ' ' | '\r' | '\n' | '\t' => {
                    slice.next();
                },
                '0'...'9' | '-' => {
                    content = Json::parse_number(slice);
                },
                '"' => {
                    content = Json::parse_string(slice);
                },
                '[' => {
                    content = Json::parse_array(slice);
                },
                '{' => {
                    content = Json::parse_object(slice);
                },
                _ => { break 'tokenizer; }
            }
        }

        content
    }

    fn parse_number(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut token    = String::from("");
        let mut is_float = false;

        'tokenizer: loop {
            let chr = match slice.peek() {
                Some(chr) => *chr,
                None      => break 'tokenizer,
            };

            match chr {
                '-' | '0'...'9' => {
                    token.push(chr);
                    slice.next();
                },
                '.' => {
                    token.push(chr);
                    is_float = true;
                    slice.next();
                },
                _ => { break 'tokenizer; }
            }
        }

        if is_float {
            JsonOption::Number(token.parse::<f32>().unwrap())
        } else {
            JsonOption::Integer(token.parse::<i32>().unwrap())
        }
    }

    fn parse_string(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut token      = String::from("");
        let mut proper_end = false;
        let mut is_escaped = false;

        // Consume starting "
        slice.next();

        'tokenizer: for chr in slice {
            match chr {
                '\\' => {
                    if is_escaped {
                        token.push(chr);
                        is_escaped = false;

                    } else {
                        is_escaped = true;
                    }
                },
                '"' => {
                    if is_escaped {
                        token.push(chr);
                        is_escaped = false;

                    } else {
                        proper_end = true;
                        break 'tokenizer;
                    }
                },
                _ => { token.push(chr); }
            }
        }

        if !proper_end {
            panic!("String wasn't properly terminated.");
        }

        JsonOption::String(token)
    }

    fn parse_array(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut content: Vec<JsonOption> = vec![];
        let mut proper_sep = true;
        let mut proper_end = false;

        // Consume starting [
        slice.next();

        'tokenizer: loop {
            loop {
                let chr = match slice.peek() {
                    Some(chr) => *chr,
                    None      => { break 'tokenizer },
                };

                match chr {
                    ' ' | '\n' | '\r' | '\t' => { slice.next(); },
                    ',' => {
                        if proper_sep {
                            panic!("Array has no elements between separator.");
                        }

                        proper_sep = true;
                        slice.next();
                    },
                    ']' => {
                        proper_sep = true;
                        proper_end = true;
                        slice.next();
                        break 'tokenizer;
                    },
                    _ => {
                        if !proper_sep {
                            break 'tokenizer;
                        }

                        content.push(Json::parse_slice(slice));
                        proper_sep = false;
                    }
                }
            }
        }

        if !proper_sep {
            panic!("Array has elements without separator.");
        }

        if !proper_end {
            panic!("Array wasn't properly terminated.");
        }

        JsonOption::Array(content)
    }

    fn parse_object(slice: &mut Peekable<&mut Chars>) -> JsonOption {
        let mut content    = HashMap::new();
        let mut proper_kv  = false;
        let mut proper_sep = true;
        let mut proper_end = false;

        let mut value;
        // Consume starting {
        slice.next();

        'tokenizer: loop {
            let mut key   = String::from("");

            'sepcheck: loop {
                let chr = match slice.peek() {
                    Some(chr) => *chr,
                    None      => { break 'tokenizer },
                };

                match chr {
                    ' ' | '\n' | '\r' | '\t' => { slice.next(); },
                    ',' => {
                        if proper_sep {
                            panic!("Object has no elements between separator.");
                        }

                        proper_sep = true;
                        slice.next();
                    },
                    ':' => {
                        if proper_kv {
                            panic!("Object has two or more key-value separators together.");
                        }

                        proper_kv = true;
                        slice.next();
                    },
                    '}' => {
                        proper_sep = true;
                        proper_end = true;
                        slice.next();
                        break 'tokenizer;
                    },
                    _ => {
                        if !proper_sep {
                            break 'tokenizer;
                        }

                        if !proper_kv && (key != "") {
                            panic!("Object has no separator between key and value.");
                        }

                        if !proper_kv {
                            key = match Json::parse_slice(slice) {
                                JsonOption::String(string) => string,
                                _ => panic!("Object has invalid element as key."),
                            };

                        } else {
                            value      = Json::parse_slice(slice);
                            proper_kv  = false;
                            proper_sep = false;
                            break 'sepcheck;
                        }
                    }
                }
            }

            content.insert(key, value);
        }

        if !proper_sep {
            panic!("Object has elements without separator.");
        }

        if !proper_end {
            panic!("Object wasn't properly terminated.");
        }

        JsonOption::Object(content)
    }
}

impl Display for Json {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
        write!(formatter, "{}", self)
    }
}

<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(lang_items)]

#![feature(alloc)]
#![allow(unknown_lints)]
#![no_std]

extern crate alloc;
#[cfg(not(test))]
extern crate allocator;
extern crate spin;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate collections;

#[macro_use]
pub mod linux;

pub mod cli;
pub mod dispatch_table;
pub mod gdt;
pub mod hash_map;
pub mod interrupts;
pub mod runtime;
pub mod vmx;

#[no_mangle]
pub extern "C" fn entry(_heap: *mut u8, _heap_size: u64, _: *mut u8, _: u64) -> u32 {
    unsafe {
        linux::printk(cstring!("Hello Linux!\n"));
    }

    #[cfg(feature = "runtime_tests")]
    runtime_tests();

    #[cfg(not(test))]
    allocator::init_global_allocator(_heap_size, _heap);
    0
}

#[cfg(feature = "runtime_tests")]
fn runtime_tests() {
    gdt::runtime_tests::run();
    interrupts::runtime_tests::run();
}
<commit_msg>Messages around runtime tests<commit_after>#![feature(collections)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(lang_items)]

#![feature(alloc)]
#![allow(unknown_lints)]
#![no_std]

extern crate alloc;
#[cfg(not(test))]
extern crate allocator;
extern crate spin;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate collections;

#[macro_use]
pub mod linux;

pub mod cli;
pub mod dispatch_table;
pub mod gdt;
pub mod hash_map;
pub mod interrupts;
pub mod runtime;
pub mod vmx;

#[no_mangle]
pub extern "C" fn entry(_heap: *mut u8, _heap_size: u64, _: *mut u8, _: u64) -> u32 {
    unsafe {
        linux::printk(cstring!("Hello Linux!\n"));
    }

    #[cfg(feature = "runtime_tests")]
    runtime_tests();

    #[cfg(not(test))]
    allocator::init_global_allocator(_heap_size, _heap);
    0
}

#[cfg(feature = "runtime_tests")]
fn runtime_tests() {
    unsafe {
        linux::printk(cstring!("Executing runtime tests...\n"));
    }

    gdt::runtime_tests::run();
    interrupts::runtime_tests::run();

    unsafe {
        linux::printk(cstring!("Runtime tests succeeded.\n"));
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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/.

#[macro_use]
extern crate bitflags;
extern crate libc;

use std::io::{self, Error};
use std::os::unix::io::RawFd;

#[repr(i32)]
#[allow(non_camel_case_types)]
pub enum ControlOptions {
    /// Indicates an addition to the interest list.
    EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD,
    /// Indicates a modification of flags for an interest already in list.
    EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD,
    /// Indicates a removal of an interest from the list.
    EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL,
}

bitflags! {
    pub struct Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32;
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32;
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32;
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32;
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32;
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32;
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32;
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32;
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32;
        /// Sets an exclusive wakeup mode for the epoll file descriptor that is being attached to
        /// the target file descriptor, `fd`. When a wakeup event occurs and multiple epoll file
        /// descriptors are attached to the same target file using `EPOLLEXCLUSIVE`, one or more of
        /// the epoll file descriptors will receive an event with `wait`. The default in this
        /// scenario (when `EPOLLEXCLUSIVE` is not set) is for all epoll file descriptors to
        /// receive an event. `EPOLLEXCLUSIVE` is thus useful for avoiding thundering herd problems
        /// in certain scenarios.
        ///
        /// If the same file descriptor is in multiple epoll instances, some with the
        /// `EPOLLEXCLUSIVE` flag, and others without, then events will be provided to all epoll
        /// instances that did not specify `EPOLLEXCLUSIVE`, and at least one of the epoll
        /// instances that did specify `EPOLLEXCLUSIVE`.
        ///
        /// The following values may be specified in conjunction with `EPOLLEXCLUSIVE`: `EPOLLIN`,
        /// `EPOLLOUT`, `EPOLLWAKEUP`, and `EPOLLET`. `EPOLLHUP` and `EPOLLERR` can also be
        /// specified, but this is not required: as usual, these events are always reported if they
        /// occur, regardless of whether they are specified in `Events`. Attempts to specify other
        /// values in `Events` yield the error `EINVAL`.
        ///
        /// `EPOLLEXCLUSIVE` may be used only in an `EPOLL_CTL_ADD` operation; attempts to employ
        /// it with `EPOLL_CTL_MOD` yield an error. If `EPOLLEXCLUSIVE` has been set using `ctl`,
        /// then a subsequent `EPOLL_CTL_MOD` on the same `epfd`, `fd` pair yields an error. A call
        /// to `ctl` that specifies `EPOLLEXCLUSIVE` in `Events` and specifies the target file
        /// descriptor `fd` as an epoll instance will likewise fail. The error in all of these
        /// cases is `EINVAL`.
        ///
        /// The `EPOLLEXCLUSIVE` flag is an input flag for the `Event.events` field when calling
        /// `ctl`; it is never returned by `wait`.
        const EPOLLEXCLUSIVE = libc::EPOLLEXCLUSIVE as u32;
    }
}

/// 'libc::epoll_event' equivalent.
#[repr(C)]
#[cfg_attr(target_arch = "x86_64", repr(packed))]
#[derive(Clone, Copy)]
pub struct Event {
    pub events: u32,
    pub data: u64,
}

impl Event {
    pub fn new(events: Events, data: u64) -> Event {
        Event {
            events: events.bits(),
            data: data,
        }
    }
}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create1()` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let flags = if cloexec { libc::EPOLL_CLOEXEC } else { 0 };
    unsafe { cvt(libc::epoll_create1(flags)) }
}

/// Safe wrapper for `libc::epoll_ctl`
pub fn ctl(
    epfd: RawFd,
    op: ControlOptions,
    fd: RawFd,
    mut event: Event,
) -> io::Result<()> {
    let e = &mut event as *mut _ as *mut libc::epoll_event;
    unsafe { cvt(libc::epoll_ctl(epfd, op as i32, fd, e))? };
    Ok(())
}

/// Safe wrapper for `libc::epoll_wait`
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd, timeout: i32, buf: &mut [Event]) -> io::Result<usize> {
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        cvt(libc::epoll_wait(
            epfd,
            buf.as_mut_ptr() as *mut libc::epoll_event,
            buf.len() as i32,
            timeout,
        ))? as usize
    };
    Ok(num_events)
}

/// Safe wrapper for `libc::close`
pub fn close(epfd: RawFd) -> io::Result<()> {
    cvt(unsafe { libc::close(epfd) })?;
    Ok(())
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 {
        Err(Error::last_os_error())
    } else {
        Ok(result)
    }
}
<commit_msg>Implementation of the debug trait for Event<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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/.

#[macro_use]
extern crate bitflags;
extern crate libc;

use std::fmt::{Formatter, Debug, Result};
use std::io::{self, Error};
use std::os::unix::io::RawFd;

#[repr(i32)]
#[allow(non_camel_case_types)]
pub enum ControlOptions {
    /// Indicates an addition to the interest list.
    EPOLL_CTL_ADD = libc::EPOLL_CTL_ADD,
    /// Indicates a modification of flags for an interest already in list.
    EPOLL_CTL_MOD = libc::EPOLL_CTL_MOD,
    /// Indicates a removal of an interest from the list.
    EPOLL_CTL_DEL = libc::EPOLL_CTL_DEL,
}

bitflags! {
    pub struct Events: u32 {
        /// Sets the Edge Triggered behavior for the associated file descriptor.
        ///
        /// The default behavior for epoll is Level Triggered.
        const EPOLLET      = libc::EPOLLET as u32;
        /// The associated file is available for read operations.
        const EPOLLIN      = libc::EPOLLIN as u32;
        /// Error condition happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; is not necessary to set it in events.
        const EPOLLERR     = libc::EPOLLERR as u32;
        /// Hang up happened on the associated file descriptor.
        ///
        /// `wait` will always wait for this event; it is not necessary to set it in events.
        /// Note that when reading from a channel such as a pipe or a stream socket, this event
        /// merely indicates that the peer closed its end of the channel. Subsequent reads from
        /// the channel will return 0 (end of file) only after all outstanding data in the
        /// channel has been consumed.
        const EPOLLHUP     = libc::EPOLLHUP as u32;
        /// The associated file is available for write operations.
        const EPOLLOUT     = libc::EPOLLOUT as u32;
        /// There is urgent data available for read operations.
        const EPOLLPRI     = libc::EPOLLPRI as u32;
        /// Stream socket peer closed connection, or shut down writing half of connection.
        ///
        /// This flag is especially useful for writing simple code to detect peer shutdown when
        /// using Edge Triggered monitoring.
        const EPOLLRDHUP   = libc::EPOLLRDHUP as u32;
        /// If `EPOLLONESHOT` and `EPOLLET` are clear and the process has the `CAP_BLOCK_SUSPEND`
        /// capability, ensure that the system does not enter "suspend" or "hibernate" while this
        /// event is pending or being processed.
        ///
        /// The event is considered as being "processed" from the time when it is returned by
        /// a call to `wait` until the next call to `wait` on the same `EpollInstance`
        /// descriptor, the closure of that file descriptor, the removal of the event file
        /// descriptor with `EPOLL_CTL_DEL`, or the clearing of `EPOLLWAKEUP` for the event file
        /// descriptor with `EPOLL_CTL_MOD`.
        const EPOLLWAKEUP  = libc::EPOLLWAKEUP as u32;
        /// Sets the one-shot behavior for the associated file descriptor.
        ///
        /// This means that after an event is pulled out with `wait` the associated file
        /// descriptor is internally disabled and no other events will be reported by the epoll
        /// interface.  The user must call `ctl` with `EPOLL_CTL_MOD` to rearm the file
        /// descriptor with a new event mask.
        const EPOLLONESHOT = libc::EPOLLONESHOT as u32;
        /// Sets an exclusive wakeup mode for the epoll file descriptor that is being attached to
        /// the target file descriptor, `fd`. When a wakeup event occurs and multiple epoll file
        /// descriptors are attached to the same target file using `EPOLLEXCLUSIVE`, one or more of
        /// the epoll file descriptors will receive an event with `wait`. The default in this
        /// scenario (when `EPOLLEXCLUSIVE` is not set) is for all epoll file descriptors to
        /// receive an event. `EPOLLEXCLUSIVE` is thus useful for avoiding thundering herd problems
        /// in certain scenarios.
        ///
        /// If the same file descriptor is in multiple epoll instances, some with the
        /// `EPOLLEXCLUSIVE` flag, and others without, then events will be provided to all epoll
        /// instances that did not specify `EPOLLEXCLUSIVE`, and at least one of the epoll
        /// instances that did specify `EPOLLEXCLUSIVE`.
        ///
        /// The following values may be specified in conjunction with `EPOLLEXCLUSIVE`: `EPOLLIN`,
        /// `EPOLLOUT`, `EPOLLWAKEUP`, and `EPOLLET`. `EPOLLHUP` and `EPOLLERR` can also be
        /// specified, but this is not required: as usual, these events are always reported if they
        /// occur, regardless of whether they are specified in `Events`. Attempts to specify other
        /// values in `Events` yield the error `EINVAL`.
        ///
        /// `EPOLLEXCLUSIVE` may be used only in an `EPOLL_CTL_ADD` operation; attempts to employ
        /// it with `EPOLL_CTL_MOD` yield an error. If `EPOLLEXCLUSIVE` has been set using `ctl`,
        /// then a subsequent `EPOLL_CTL_MOD` on the same `epfd`, `fd` pair yields an error. A call
        /// to `ctl` that specifies `EPOLLEXCLUSIVE` in `Events` and specifies the target file
        /// descriptor `fd` as an epoll instance will likewise fail. The error in all of these
        /// cases is `EINVAL`.
        ///
        /// The `EPOLLEXCLUSIVE` flag is an input flag for the `Event.events` field when calling
        /// `ctl`; it is never returned by `wait`.
        const EPOLLEXCLUSIVE = libc::EPOLLEXCLUSIVE as u32;
    }
}

/// 'libc::epoll_event' equivalent.
#[repr(C)]
#[cfg_attr(target_arch = "x86_64", repr(packed))]
#[derive(Clone, Copy)]
pub struct Event {
    pub events: u32,
    pub data: u64,
}

impl Event {
    pub fn new(events: Events, data: u64) -> Event {
        Event {
            events: events.bits(),
            data: data,
        }
    }
}

impl Debug for Event {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
        let data = self.data;
        f.debug_struct("Event")
            .field("events", unsafe {
                //Unsafe since we'd like to show which bits were wrongly set
                &Events::from_bits_unchecked(self.events)
            })
            .field("data", &data)
            .finish()
    }
}

/// Creates a new epoll file descriptor.
///
/// If `cloexec` is true, `FD_CLOEXEC` will be set on the returned file descriptor.
///
/// ## Notes
///
/// * `epoll_create1()` is the underlying syscall.
pub fn create(cloexec: bool) -> io::Result<RawFd> {
    let flags = if cloexec { libc::EPOLL_CLOEXEC } else { 0 };
    unsafe { cvt(libc::epoll_create1(flags)) }
}

/// Safe wrapper for `libc::epoll_ctl`
pub fn ctl(
    epfd: RawFd,
    op: ControlOptions,
    fd: RawFd,
    mut event: Event,
) -> io::Result<()> {
    let e = &mut event as *mut _ as *mut libc::epoll_event;
    unsafe { cvt(libc::epoll_ctl(epfd, op as i32, fd, e))? };
    Ok(())
}

/// Safe wrapper for `libc::epoll_wait`
///
/// ## Notes
///
/// * If `timeout` is negative, it will block until an event is received.
pub fn wait(epfd: RawFd, timeout: i32, buf: &mut [Event]) -> io::Result<usize> {
    let timeout = if timeout < -1 { -1 } else { timeout };
    let num_events = unsafe {
        cvt(libc::epoll_wait(
            epfd,
            buf.as_mut_ptr() as *mut libc::epoll_event,
            buf.len() as i32,
            timeout,
        ))? as usize
    };
    Ok(num_events)
}

/// Safe wrapper for `libc::close`
pub fn close(epfd: RawFd) -> io::Result<()> {
    cvt(unsafe { libc::close(epfd) })?;
    Ok(())
}

fn cvt(result: libc::c_int) -> io::Result<libc::c_int> {
    if result < 0 {
        Err(Error::last_os_error())
    } else {
        Ok(result)
    }
}
<|endoftext|>


<commit_before>//! atty is a simple utility that answers one question
//! > is this a tty?
//!
//! usage is just as simple
//!
//! ```
//! if atty::is(atty::Stream::Stdout) {
//!   println!("i'm a tty")
//! }
//! ```
//!
//! ```
//! if atty::isnt(atty::Stream::Stdout) {
//!   println!("i'm not a tty")
//! }
//! ```

#[cfg(windows)]
extern crate kernel32;
#[cfg(not(windows))]
extern crate libc;
#[cfg(windows)]
extern crate winapi;

#[cfg(windows)]
use winapi::minwindef::DWORD;

/// possible stream sources
#[derive(Clone, Copy, Debug)]
pub enum Stream {
    Stdout,
    Stderr,
    Stdin,
}

/// returns true if this is a tty
#[cfg(unix)]
pub fn is(stream: Stream) -> bool {
    extern crate libc;

    let fd = match stream {
        Stream::Stdout => libc::STDOUT_FILENO,
        Stream::Stderr => libc::STDERR_FILENO,
        Stream::Stdin => libc::STDIN_FILENO,
    };
    unsafe { libc::isatty(fd) != 0 }
}

/// returns true if this is a tty
#[cfg(windows)]
pub fn is(stream: Stream) -> bool {
    use winapi::{
        STD_INPUT_HANDLE as STD_INPUT,
        STD_ERROR_HANDLE as STD_ERROR,
        STD_OUTPUT_HANDLE as STD_OUTPUT
    };

    let (fd, others) = match stream {
        Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]),
        Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]),
        Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]),
    };
    if unsafe { console_on_any(&[fd]) } {
        // False positives aren't possible. If we got a console then
        // we definitely have a tty on stdin.
        return true;
    }

    // At this point, we *could* have a false negative. We can determine that
    // this is true negative if we can detect the presence of a console on
    // any of the other streams. If another stream has a console, then we know
    // we're in a Windows console and can therefore trust the negative.
    if unsafe { console_on_any(&others) } {
        return false;
    }

    // Otherwise, we fall back to a very strange msys hack to see if we can
    // sneakily detect the presence of a tty.
    unsafe { msys_tty_on(fd) }
}

/// returns true if this is _not_ a tty
pub fn isnt(stream: Stream) -> bool {
    !is(stream)
}

/// Returns true if any of the given fds are on a console.
#[cfg(windows)]
unsafe fn console_on_any(fds: &[DWORD]) -> bool {
    for &fd in fds {
        let mut out = 0;
        let handle = kernel32::GetStdHandle(fd);
        if kernel32::GetConsoleMode(handle, &mut out) != 0 {
            return true;
        }
    }
    false
}

/// Returns true if there is an MSYS tty on the given handle.
#[cfg(windows)]
unsafe fn msys_tty_on(fd: DWORD) -> bool {
    use std::ffi::OsString;
    use std::mem;
    use std::os::raw::c_void;
    use std::os::windows::ffi::OsStringExt;
    use std::slice;

    use kernel32::GetFileInformationByHandleEx;
    use winapi::fileapi::FILE_NAME_INFO;
    use winapi::minwinbase::FileNameInfo;
    use winapi::minwindef::MAX_PATH;

    let size = mem::size_of::<FILE_NAME_INFO>();
    let mut name_info_bytes = vec![0u8; size + MAX_PATH];
    let res = GetFileInformationByHandleEx(
        kernel32::GetStdHandle(fd),
        FileNameInfo,
        &mut *name_info_bytes as *mut _ as *mut c_void,
        name_info_bytes.len() as u32);
    if res == 0 {
        return true;
    }
    let name_info: FILE_NAME_INFO =
        *(name_info_bytes[0..size].as_ptr() as *const FILE_NAME_INFO);
    let name_bytes =
        &name_info_bytes[size..size + name_info.FileNameLength as usize];
    let name_u16 = slice::from_raw_parts(
        name_bytes.as_ptr() as *const u16, name_bytes.len() / 2);
    let name = OsString::from_wide(name_u16)
        .as_os_str().to_string_lossy().into_owned();
    name.contains("msys-") || name.contains("-pty")
}

#[cfg(test)]
mod tests {
    use super::{is, Stream};

    #[test]
    #[cfg(windows)]
    fn is_err() {
        // appveyor pipes its output
        assert!(!is(Stream::Stderr))
    }

    #[test]
    #[cfg(windows)]
    fn is_out() {
        // appveyor pipes its output
        assert!(!is(Stream::Stdout))
    }

    #[test]
    #[cfg(windows)]
    fn is_in() {
        assert!(is(Stream::Stdin))
    }

    #[test]
    #[cfg(unix)]
    fn is_err() {
        assert!(is(Stream::Stderr))
    }

    #[test]
    #[cfg(unix)]
    fn is_out() {
        assert!(is(Stream::Stdout))
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn is_in() {
        // macos on travis seems to pipe its input
        assert!(!is(Stream::Stdin))
    }

    #[test]
    #[cfg(all(not(target_os = "macos"), unix))]
    fn is_in() {
        assert!(is(Stream::Stdin))
    }
}
<commit_msg>add no_std attribute<commit_after>//! atty is a simple utility that answers one question
//! > is this a tty?
//!
//! usage is just as simple
//!
//! ```
//! if atty::is(atty::Stream::Stdout) {
//!   println!("i'm a tty")
//! }
//! ```
//!
//! ```
//! if atty::isnt(atty::Stream::Stdout) {
//!   println!("i'm not a tty")
//! }
//! ```

#![cfg_attr(not(windows), no_std)]

#[cfg(windows)]
extern crate kernel32;
#[cfg(not(windows))]
extern crate libc;
#[cfg(windows)]
extern crate winapi;

#[cfg(windows)]
use winapi::minwindef::DWORD;

/// possible stream sources
#[derive(Clone, Copy, Debug)]
pub enum Stream {
    Stdout,
    Stderr,
    Stdin,
}

/// returns true if this is a tty
#[cfg(unix)]
pub fn is(stream: Stream) -> bool {
    extern crate libc;

    let fd = match stream {
        Stream::Stdout => libc::STDOUT_FILENO,
        Stream::Stderr => libc::STDERR_FILENO,
        Stream::Stdin => libc::STDIN_FILENO,
    };
    unsafe { libc::isatty(fd) != 0 }
}

/// returns true if this is a tty
#[cfg(windows)]
pub fn is(stream: Stream) -> bool {
    use winapi::{
        STD_INPUT_HANDLE as STD_INPUT,
        STD_ERROR_HANDLE as STD_ERROR,
        STD_OUTPUT_HANDLE as STD_OUTPUT
    };

    let (fd, others) = match stream {
        Stream::Stdin => (STD_INPUT, [STD_ERROR, STD_OUTPUT]),
        Stream::Stderr => (STD_ERROR, [STD_INPUT, STD_OUTPUT]),
        Stream::Stdout => (STD_OUTPUT, [STD_INPUT, STD_ERROR]),
    };
    if unsafe { console_on_any(&[fd]) } {
        // False positives aren't possible. If we got a console then
        // we definitely have a tty on stdin.
        return true;
    }

    // At this point, we *could* have a false negative. We can determine that
    // this is true negative if we can detect the presence of a console on
    // any of the other streams. If another stream has a console, then we know
    // we're in a Windows console and can therefore trust the negative.
    if unsafe { console_on_any(&others) } {
        return false;
    }

    // Otherwise, we fall back to a very strange msys hack to see if we can
    // sneakily detect the presence of a tty.
    unsafe { msys_tty_on(fd) }
}

/// returns true if this is _not_ a tty
pub fn isnt(stream: Stream) -> bool {
    !is(stream)
}

/// Returns true if any of the given fds are on a console.
#[cfg(windows)]
unsafe fn console_on_any(fds: &[DWORD]) -> bool {
    for &fd in fds {
        let mut out = 0;
        let handle = kernel32::GetStdHandle(fd);
        if kernel32::GetConsoleMode(handle, &mut out) != 0 {
            return true;
        }
    }
    false
}

/// Returns true if there is an MSYS tty on the given handle.
#[cfg(windows)]
unsafe fn msys_tty_on(fd: DWORD) -> bool {
    use std::ffi::OsString;
    use std::mem;
    use std::os::raw::c_void;
    use std::os::windows::ffi::OsStringExt;
    use std::slice;

    use kernel32::GetFileInformationByHandleEx;
    use winapi::fileapi::FILE_NAME_INFO;
    use winapi::minwinbase::FileNameInfo;
    use winapi::minwindef::MAX_PATH;

    let size = mem::size_of::<FILE_NAME_INFO>();
    let mut name_info_bytes = vec![0u8; size + MAX_PATH];
    let res = GetFileInformationByHandleEx(
        kernel32::GetStdHandle(fd),
        FileNameInfo,
        &mut *name_info_bytes as *mut _ as *mut c_void,
        name_info_bytes.len() as u32);
    if res == 0 {
        return true;
    }
    let name_info: FILE_NAME_INFO =
        *(name_info_bytes[0..size].as_ptr() as *const FILE_NAME_INFO);
    let name_bytes =
        &name_info_bytes[size..size + name_info.FileNameLength as usize];
    let name_u16 = slice::from_raw_parts(
        name_bytes.as_ptr() as *const u16, name_bytes.len() / 2);
    let name = OsString::from_wide(name_u16)
        .as_os_str().to_string_lossy().into_owned();
    name.contains("msys-") || name.contains("-pty")
}

#[cfg(test)]
mod tests {
    use super::{is, Stream};

    #[test]
    #[cfg(windows)]
    fn is_err() {
        // appveyor pipes its output
        assert!(!is(Stream::Stderr))
    }

    #[test]
    #[cfg(windows)]
    fn is_out() {
        // appveyor pipes its output
        assert!(!is(Stream::Stdout))
    }

    #[test]
    #[cfg(windows)]
    fn is_in() {
        assert!(is(Stream::Stdin))
    }

    #[test]
    #[cfg(unix)]
    fn is_err() {
        assert!(is(Stream::Stderr))
    }

    #[test]
    #[cfg(unix)]
    fn is_out() {
        assert!(is(Stream::Stdout))
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn is_in() {
        // macos on travis seems to pipe its input
        assert!(!is(Stream::Stdin))
    }

    #[test]
    #[cfg(all(not(target_os = "macos"), unix))]
    fn is_in() {
        assert!(is(Stream::Stdin))
    }
}
<|endoftext|>


<commit_before>// Streambuffer -- Fast asynchronous file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Streambuffer, a library for fast asynchronous file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as an array of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`, but it will block upon first access.
//!
//! ```
//! use streambuffer::StreamBuffer;
//! let fstream = StreamBuffer::open("src/lib.rs").unwrap();
//! let buffer = fstream.as_slice();
//! assert_eq!(buffer[3..49], b"Streambuffer -- Fast asynchronous file reading"[..]);
//! ```
//!
//! TODO: More and better (non-blocking) examples.

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::os::unix::io::AsRawFd;
use std::path::Path;
use std::slice;
use std::thread;

extern crate libc;

/// A memory-mapped file.
pub struct StreamBuffer {
    page_size: usize,
    buffer: *const u8,
    length: usize,
}

fn map_file(file: &fs::File) -> io::Result<(*const u8, usize)> {
    let fd = file.as_raw_fd();
    let length = try!(file.metadata()).len();

    if length > usize::max_value() as u64 {
        return Err(io::Error::new(io::ErrorKind::Other, "file is larger than address space"));
    }

    if length == 0 {
        return Err(io::Error::new(io::ErrorKind::Other, "file has size zero"));
    }

    let null = 0 as *mut libc::c_void;
    let result = unsafe {
        libc::mmap(null, length as usize, libc::PROT_READ, libc::MAP_PRIVATE, fd, 0)
    };

    if result == libc::MAP_FAILED {
        Err(io::Error::last_os_error())
    } else {
        Ok((result as *const u8, length as usize))
    }
}

fn unmap_file(buffer: *const u8, length: usize) {
    let result = unsafe { libc::munmap(buffer as *mut libc::c_void, length) };

    // `munmap` only fails due to incorrect usage, which is a program error, not a runtime failure.
    assert!(result == 0);
}

/// Writes whether the pages in the range starting at `buffer` with a length of `length` bytes
/// are resident in physical memory into `residency`. The size of `residency` must be at least
/// `length / page_size`. Both `buffer` and `length` must be a multiple of the page size.
fn get_resident(buffer: *const u8, length: usize, residency: &mut [bool]) {
    let result = unsafe {
        let residency_uchar = residency.as_mut_ptr() as *mut libc::c_uchar;
        libc::mincore(buffer as *mut libc::c_void, length, residency_uchar)
    };

    // Any error code except EAGAIN indicates a programming error.
    assert!(result == libc::EAGAIN || result == 0);

    // In the rare occasion that the kernel is busy, yield so we don't spam the kernel with
    // `mincore` calls, then try again.
    if result == libc::EAGAIN {
        thread::yield_now();
        get_resident(buffer, length, residency)
    }
}

/// Requests the kernel to make the specified range of bytes resident in physical memory. `buffer`
/// must be page-aligned.
fn prefetch(buffer: *const u8, length: usize) {
    let result = unsafe {
        libc::posix_madvise(buffer as *mut libc::c_void, length, libc::POSIX_MADV_WILLNEED)
    };

    // Any returned error code indicates a programming error, not a runtime error.
    assert_eq!(0, result);
}

fn get_page_size() -> usize {
    let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };

    // Assert that the page size is a power of two, which is assumed when the page size is used.
    assert!(page_size != 0);
    assert_eq!(0, page_size & (page_size - 1));

    page_size
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl StreamBuffer {
    /// Maps the file at `path` into memory.
    ///
    /// TODO: Document what happens when the file is changed after opening.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<StreamBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when it goes out of scope, but
        // `mmap` only requires the descriptor to be open for the `mmap` call, so this is fine.
        let file = try!(fs::File::open(path));
        let (buffer, length) = try!(map_file(&file));
        let fstream = StreamBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
        };
        Ok(fstream)
    }

    /// Returns the file contents as a slice.
    ///
    /// Accessing elements of the slice might cause a page fault, blocking until the data has been
    /// read from disk. To avoid blocking, call `prefetch()` and check whether the memory is
    /// resident with `resident_len()`.
    pub fn as_slice(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }

    /// Returns the length of the mapped file in bytes.
    pub fn len(&self) -> usize {
        self.length
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }

    /// Advises the kernel to make a slice of the file resident in physical memory.
    ///
    /// This method does not block, meaning that when the function returns, the slice is not
    /// necessarily resident. After this function returns, the kernel may read the requested slice
    /// from disk and make it resident. Note that this is only an advice, the kernel need not honor
    /// it.
    ///
    /// To check whether the slice is resident at a later time, use `resident_len()`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn prefetch(&self, offset: usize, length: usize) {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);

        let buffer = unsafe { self.buffer.offset(aligned_offset as isize) };
        prefetch(buffer, aligned_length);
    }

    /// Returns a slice if the requested range is resident in physical memory.
    ///
    /// If the slice is not resident, `prefetch()` is called, so that if the same slice is
    /// requested after a while, it likely is resident.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn try_slice(&self, offset: usize, length: usize) -> Option<&[u8]> {
        // The bounds check assertion is done in `resident_len()`, no need to duplicate it here.
        if self.resident_len(offset, length) < length {
            self.prefetch(offset, length);
            None
        } else {
            Some(&self.as_slice()[offset..offset + length])
        }
    }
}

impl Drop for StreamBuffer {
    fn drop(&mut self) {
        unmap_file(self.buffer, self.length);
    }
}

#[test]
fn open_file() {
    let fstream = StreamBuffer::open("src/lib.rs");
    assert!(fstream.is_ok());
}

#[test]
fn make_resident() {
    let fstream = StreamBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(fstream.as_slice()[3..15], b"Streambuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fstream.resident_len(3, 12), 12);

    // If it is resident, `try_slice` should return a slice.
    assert_eq!(fstream.try_slice(3, 12), Some(&b"Streambuffer"[..]));
}

#[test]
fn prefetch_is_not_harmful() {
    let fstream = StreamBuffer::open("src/lib.rs").unwrap();

    // It is impossible to test that this actually works without root access to instruct the kernel
    // to drop its caches, but at least we can verify that calling `prefetch` is not harmful.
    fstream.prefetch(0, fstream.len());

    // Reading from the file should still work as normal.
    assert_eq!(fstream.as_slice()[3..15], b"Streambuffer"[..]);
}
<commit_msg>Reorder methods, improve documentation<commit_after>// Streambuffer -- Fast asynchronous file reading
// Copyright 2016 Ruud van Asseldonk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// A copy of the License has been included in the root of the repository.

//! Streambuffer, a library for fast asynchronous file reading.
//!
//! # Examples
//!
//! Map a file into memory and access it as an array of bytes. This is simple and will generally
//! outperform `Read::read_to_end()`, but it will block upon first access.
//!
//! ```
//! use streambuffer::StreamBuffer;
//! let fstream = StreamBuffer::open("src/lib.rs").unwrap();
//! let buffer = fstream.as_slice();
//! assert_eq!(buffer[3..49], b"Streambuffer -- Fast asynchronous file reading"[..]);
//! ```
//!
//! TODO: More and better (non-blocking) examples.

#![warn(missing_docs)]

use std::cmp;
use std::io;
use std::fs;
use std::os::unix::io::AsRawFd;
use std::path::Path;
use std::slice;
use std::thread;

extern crate libc;

/// A memory-mapped file.
pub struct StreamBuffer {
    page_size: usize,
    buffer: *const u8,
    length: usize,
}

fn map_file(file: &fs::File) -> io::Result<(*const u8, usize)> {
    let fd = file.as_raw_fd();
    let length = try!(file.metadata()).len();

    if length > usize::max_value() as u64 {
        return Err(io::Error::new(io::ErrorKind::Other, "file is larger than address space"));
    }

    if length == 0 {
        return Err(io::Error::new(io::ErrorKind::Other, "file has size zero"));
    }

    let null = 0 as *mut libc::c_void;
    let result = unsafe {
        libc::mmap(null, length as usize, libc::PROT_READ, libc::MAP_PRIVATE, fd, 0)
    };

    if result == libc::MAP_FAILED {
        Err(io::Error::last_os_error())
    } else {
        Ok((result as *const u8, length as usize))
    }
}

fn unmap_file(buffer: *const u8, length: usize) {
    let result = unsafe { libc::munmap(buffer as *mut libc::c_void, length) };

    // `munmap` only fails due to incorrect usage, which is a program error, not a runtime failure.
    assert!(result == 0);
}

/// Writes whether the pages in the range starting at `buffer` with a length of `length` bytes
/// are resident in physical memory into `residency`. The size of `residency` must be at least
/// `length / page_size`. Both `buffer` and `length` must be a multiple of the page size.
fn get_resident(buffer: *const u8, length: usize, residency: &mut [bool]) {
    let result = unsafe {
        let residency_uchar = residency.as_mut_ptr() as *mut libc::c_uchar;
        libc::mincore(buffer as *mut libc::c_void, length, residency_uchar)
    };

    // Any error code except EAGAIN indicates a programming error.
    assert!(result == libc::EAGAIN || result == 0);

    // In the rare occasion that the kernel is busy, yield so we don't spam the kernel with
    // `mincore` calls, then try again.
    if result == libc::EAGAIN {
        thread::yield_now();
        get_resident(buffer, length, residency)
    }
}

/// Requests the kernel to make the specified range of bytes resident in physical memory. `buffer`
/// must be page-aligned.
fn prefetch(buffer: *const u8, length: usize) {
    let result = unsafe {
        libc::posix_madvise(buffer as *mut libc::c_void, length, libc::POSIX_MADV_WILLNEED)
    };

    // Any returned error code indicates a programming error, not a runtime error.
    assert_eq!(0, result);
}

fn get_page_size() -> usize {
    let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize };

    // Assert that the page size is a power of two, which is assumed when the page size is used.
    assert!(page_size != 0);
    assert_eq!(0, page_size & (page_size - 1));

    page_size
}

/// Rounds `size` up to the nearest multiple of `power_of_two`.
fn round_up_to(size: usize, power_of_two: usize) -> usize {
    (size + (power_of_two - 1)) & !(power_of_two - 1)
}

#[test]
fn verify_round_up_to() {
    assert_eq!(1024, round_up_to(23, 1024));
    assert_eq!(1024, round_up_to(1024, 1024));
    assert_eq!(2048, round_up_to(1025, 1024));
}

/// Rounds `size` down to the nearest multiple of `power_of_two`.
fn round_down_to(size: usize, power_of_two: usize) -> usize {
    size & !(power_of_two - 1)
}

#[test]
fn verify_round_down_to() {
    assert_eq!(0, round_down_to(23, 1024));
    assert_eq!(1024, round_down_to(1024, 1024));
    assert_eq!(1024, round_down_to(1025, 1024));
}

impl StreamBuffer {
    /// Maps the file at `path` into memory.
    ///
    /// TODO: Document what happens when the file is changed after opening.
    pub fn open<P: AsRef<Path>>(path: P) -> io::Result<StreamBuffer> {
        // Open the `fs::File` so we get all of std's error handling for free, then use it to
        // extract the file descriptor. The file is closed again when it goes out of scope, but
        // `mmap` only requires the descriptor to be open for the `mmap` call, so this is fine.
        let file = try!(fs::File::open(path));
        let (buffer, length) = try!(map_file(&file));
        let fstream = StreamBuffer {
            page_size: get_page_size(),
            buffer: buffer,
            length: length,
        };
        Ok(fstream)
    }

    /// Returns the length of the mapped file in bytes.
    pub fn len(&self) -> usize {
        self.length
    }

    /// Returns the number of bytes resident in physical memory, starting from `offset`.
    ///
    /// The slice `[offset..offset + resident_len]` can be accessed without causing page faults or
    /// disk access. Note that this is only a snapshot, and the kernel might decide to evict pages
    /// or make them resident at any time.
    ///
    /// The returned resident length is at most `length`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn resident_len(&self, offset: usize, length: usize) -> usize {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);
        let num_pages = aligned_length / self.page_size;

        // There is a tradeoff here: to store residency information, we need an array of booleans.
        // The requested range can potentially be very large and it is only known at runtime. We
        // could allocate a vector here, but that requires a heap allocation just to get residency
        // information (which might in turn cause a page fault). Instead, check at most 32 pages at
        // once. This means more syscalls for large ranges, but it saves us the heap allocation,
        // and for ranges up to 32 pages (128 KiB typically) there is only one syscall.
        let mut residency = [false; 32];
        let mut pages_checked = 0;
        let mut pages_resident = 0;

        while pages_checked < num_pages {
            let pages_to_check = cmp::min(32, num_pages - pages_checked);
            let check_offset = (aligned_offset + pages_checked * self.page_size) as isize;
            let check_buffer = unsafe { self.buffer.offset(check_offset) };
            let check_length = pages_to_check * self.page_size;
            get_resident(check_buffer, check_length, &mut residency);

            // Count the number of resident pages.
            match residency[..pages_to_check].iter().position(|resident| !resident) {
                Some(non_resident) => {
                    // The index of the non-resident page is the number of resident pages.
                    pages_resident += non_resident;
                    break;
                }
                None => {
                    pages_resident += pages_to_check;
                    pages_checked += pages_to_check;
                }
            }
        }

        let resident_length = pages_resident * self.page_size + aligned_offset - offset;

        // Never return more than the requested length. The resident length might be larger than
        // the length of the buffer, because it is rounded up to the page size.
        cmp::min(length, resident_length)
    }

    /// Returns the file contents as a slice.
    ///
    /// Accessing elements of the slice might cause a page fault, blocking until the data has been
    /// read from disk.
    ///
    /// To avoid blocking, call `prefetch()` and check whether the memory is resident with
    /// `resident_len()`. The `try_slice()` method is similar to `as_slice()`, but it returns
    /// `None` if accessing the slice would block.
    pub fn as_slice(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self.buffer, self.length) }
    }

    /// Returns a slice if the requested range is resident in physical memory.
    ///
    /// If the slice is not resident, `prefetch()` is called, so that if the same slice is
    /// requested after a while, it likely is resident.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn try_slice(&self, offset: usize, length: usize) -> Option<&[u8]> {
        // The bounds check assertion is done in `resident_len()`, no need to duplicate it here.
        if self.resident_len(offset, length) < length {
            self.prefetch(offset, length);
            None
        } else {
            Some(&self.as_slice()[offset..offset + length])
        }
    }

    /// Advises the kernel to make a slice of the file resident in physical memory.
    ///
    /// This method does not block, meaning that when the function returns, the slice is not
    /// necessarily resident. After this function returns, the kernel may read the requested slice
    /// from disk and make it resident. Note that this is only an advice, the kernel need not honor
    /// it.
    ///
    /// To check whether the slice is resident at a later time, use `resident_len()`.
    ///
    /// # Panics
    ///
    /// Panics if the specified range lies outside of the buffer.
    pub fn prefetch(&self, offset: usize, length: usize) {
        // The specified offset and length must lie within the buffer.
        assert!(offset + length <= self.length);

        let aligned_offset = round_down_to(offset, self.page_size);
        let aligned_length = round_up_to(length + (offset - aligned_offset), self.page_size);

        let buffer = unsafe { self.buffer.offset(aligned_offset as isize) };
        prefetch(buffer, aligned_length);
    }
}

impl Drop for StreamBuffer {
    fn drop(&mut self) {
        unmap_file(self.buffer, self.length);
    }
}

#[test]
fn open_file() {
    let fstream = StreamBuffer::open("src/lib.rs");
    assert!(fstream.is_ok());
}

#[test]
fn make_resident() {
    let fstream = StreamBuffer::open("src/lib.rs").unwrap();

    // Touch the first page to make it resident.
    assert_eq!(fstream.as_slice()[3..15], b"Streambuffer"[..]);

    // Now at least that part should be resident.
    assert_eq!(fstream.resident_len(3, 12), 12);

    // If it is resident, `try_slice` should return a slice.
    assert_eq!(fstream.try_slice(3, 12), Some(&b"Streambuffer"[..]));
}

#[test]
fn prefetch_is_not_harmful() {
    let fstream = StreamBuffer::open("src/lib.rs").unwrap();

    // It is impossible to test that this actually works without root access to instruct the kernel
    // to drop its caches, but at least we can verify that calling `prefetch` is not harmful.
    fstream.prefetch(0, fstream.len());

    // Reading from the file should still work as normal.
    assert_eq!(fstream.as_slice()[3..15], b"Streambuffer"[..]);
}
<|endoftext|>


<commit_before>#![feature(
    rustc_private,
    decl_macro,
    type_alias_impl_trait,
    associated_type_bounds,
    never_type,
    try_blocks,
    hash_drain_filter,
    str_split_once
)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]

#[cfg(feature = "jit")]
extern crate libc;
extern crate snap;
#[macro_use]
extern crate rustc_middle;
extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

use std::any::Any;
use std::str::FromStr;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc_middle::ty::query::Providers;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;

use cranelift_codegen::settings::{self, Configurable};

use crate::constant::ConstantCx;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod atomic_shim;
mod backend;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod inline_asm;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod num;
mod optimize;
mod pointer;
mod pretty_clif;
mod toolchain;
mod trap;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub(crate) use std::convert::{TryFrom, TryInto};

    pub(crate) use rustc_span::Span;

    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
    pub(crate) use rustc_middle::bug;
    pub(crate) use rustc_middle::mir::{self, *};
    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
    pub(crate) use rustc_middle::ty::{
        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
        TypeFoldable, UintTy,
    };
    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};

    pub(crate) use rustc_data_structures::fx::FxHashMap;

    pub(crate) use rustc_index::vec::Idx;

    pub(crate) use cranelift_codegen::entity::EntitySet;
    pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
    pub(crate) use cranelift_codegen::ir::function::Function;
    pub(crate) use cranelift_codegen::ir::types;
    pub(crate) use cranelift_codegen::ir::{
        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
    };
    pub(crate) use cranelift_codegen::isa::{self, CallConv};
    pub(crate) use cranelift_codegen::Context;
    pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
    pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module};

    pub(crate) use crate::abi::*;
    pub(crate) use crate::base::{codegen_operand, codegen_place};
    pub(crate) use crate::cast::*;
    pub(crate) use crate::common::*;
    pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
    pub(crate) use crate::pointer::Pointer;
    pub(crate) use crate::trap::*;
    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
}

struct PrintOnPanic<F: Fn() -> String>(F);
impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
    fn drop(&mut self) {
        if ::std::thread::panicking() {
            println!("{}", (self.0)());
        }
    }
}

struct CodegenCx<'tcx, M: Module> {
    tcx: TyCtxt<'tcx>,
    module: M,
    global_asm: String,
    constants_cx: ConstantCx,
    cached_context: Context,
    vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
    debug_context: Option<DebugContext<'tcx>>,
    unwind_context: UnwindContext<'tcx>,
}

impl<'tcx, M: Module> CodegenCx<'tcx, M> {
    fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool, pic_eh_frame: bool) -> Self {
        let unwind_context = UnwindContext::new(tcx, module.isa(), pic_eh_frame);
        let debug_context = if debug_info {
            Some(DebugContext::new(tcx, module.isa()))
        } else {
            None
        };
        CodegenCx {
            tcx,
            module,
            global_asm: String::new(),
            constants_cx: ConstantCx::default(),
            cached_context: Context::new(),
            vtables: FxHashMap::default(),
            debug_context,
            unwind_context,
        }
    }

    fn finalize(mut self) -> (M, String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
        self.constants_cx.finalize(self.tcx, &mut self.module);
        (
            self.module,
            self.global_asm,
            self.debug_context,
            self.unwind_context,
        )
    }
}

#[derive(Copy, Clone, Debug)]
pub enum CodegenMode {
    Aot,
    Jit,
    JitLazy,
}

impl Default for CodegenMode {
    fn default() -> Self {
        CodegenMode::Aot
    }
}

impl FromStr for CodegenMode {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "aot" => Ok(CodegenMode::Aot),
            "jit" => Ok(CodegenMode::Jit),
            "jit-lazy" => Ok(CodegenMode::JitLazy),
            _ => Err(format!("Unknown codegen mode `{}`", s)),
        }
    }
}

#[derive(Copy, Clone, Debug, Default)]
pub struct BackendConfig {
    pub codegen_mode: CodegenMode,
}

impl BackendConfig {
    fn from_opts(opts: &[String]) -> Result<Self, String> {
        let mut config = BackendConfig::default();
        for opt in opts {
            if let Some((name, value)) = opt.split_once('=') {
                match name {
                    "mode" => config.codegen_mode = value.parse()?,
                    _ => return Err(format!("Unknown option `{}`", name)),
                }
            } else {
                return Err(format!("Invalid option `{}`", opt));
            }
        }
        Ok(config)
    }
}

pub struct CraneliftCodegenBackend {
    pub config: Option<BackendConfig>,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        if sess.lto() != rustc_session::config::Lto::No && sess.opts.cg.embed_bitcode {
            sess.warn("LTO is not supported. You may get a linker error.");
        }
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, _providers: &mut Providers) {}
    fn provide_extern(&self, _providers: &mut Providers) {}

    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
        vec![]
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        let config = if let Some(config) = self.config {
            config
        } else {
            BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
                .unwrap_or_else(|err| tcx.sess.fatal(&err))
        };
        let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config);

        res
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        Ok(*ongoing_codegen
            .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
            .unwrap())
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let target_cpu = crate::target_triple(sess).to_string();
        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
            sess,
            &codegen_results,
            outputs,
            &codegen_results.crate_name.as_str(),
            &target_cpu,
        );

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    sess.target.llvm_target.parse().unwrap()
}

fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
    use target_lexicon::BinaryFormat;

    let target_triple = crate::target_triple(sess);

    let mut flags_builder = settings::builder();
    flags_builder.enable("is_pic").unwrap();
    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
    flags_builder
        .set(
            "enable_verifier",
            if cfg!(debug_assertions) {
                "true"
            } else {
                "false"
            },
        )
        .unwrap();

    let tls_model = match target_triple.binary_format {
        BinaryFormat::Elf => "elf_gd",
        BinaryFormat::Macho => "macho",
        BinaryFormat::Coff => "coff",
        _ => "none",
    };
    flags_builder.set("tls_model", tls_model).unwrap();

    flags_builder.set("enable_simd", "true").unwrap();

    use rustc_session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "none").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "speed_and_size").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }

    let flags = settings::Flags::new(flags_builder);

    let variant = if cfg!(feature = "oldbe") {
        cranelift_codegen::isa::BackendVariant::Legacy
    } else {
        cranelift_codegen::isa::BackendVariant::MachInst
    };
    let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
    // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
    // is interpreted as `bsr`.
    isa_builder.enable("nehalem").unwrap();
    isa_builder.finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend { config: None })
}
<commit_msg>Stabilize str_split_once<commit_after>#![feature(
    rustc_private,
    decl_macro,
    type_alias_impl_trait,
    associated_type_bounds,
    never_type,
    try_blocks,
    hash_drain_filter
)]
#![warn(rust_2018_idioms)]
#![warn(unused_lifetimes)]
#![warn(unreachable_pub)]

#[cfg(feature = "jit")]
extern crate libc;
extern crate snap;
#[macro_use]
extern crate rustc_middle;
extern crate rustc_ast;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_fs_util;
extern crate rustc_hir;
extern crate rustc_incremental;
extern crate rustc_index;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
extern crate rustc_driver;

use std::any::Any;
use std::str::FromStr;

use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_codegen_ssa::CodegenResults;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader};
use rustc_middle::ty::query::Providers;
use rustc_session::config::OutputFilenames;
use rustc_session::Session;

use cranelift_codegen::settings::{self, Configurable};

use crate::constant::ConstantCx;
use crate::prelude::*;

mod abi;
mod allocator;
mod analyze;
mod archive;
mod atomic_shim;
mod backend;
mod base;
mod cast;
mod codegen_i128;
mod common;
mod constant;
mod debuginfo;
mod discriminant;
mod driver;
mod inline_asm;
mod intrinsics;
mod linkage;
mod main_shim;
mod metadata;
mod num;
mod optimize;
mod pointer;
mod pretty_clif;
mod toolchain;
mod trap;
mod unsize;
mod value_and_place;
mod vtable;

mod prelude {
    pub(crate) use std::convert::{TryFrom, TryInto};

    pub(crate) use rustc_span::Span;

    pub(crate) use rustc_hir::def_id::{DefId, LOCAL_CRATE};
    pub(crate) use rustc_middle::bug;
    pub(crate) use rustc_middle::mir::{self, *};
    pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout};
    pub(crate) use rustc_middle::ty::{
        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut,
        TypeFoldable, UintTy,
    };
    pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx};

    pub(crate) use rustc_data_structures::fx::FxHashMap;

    pub(crate) use rustc_index::vec::Idx;

    pub(crate) use cranelift_codegen::entity::EntitySet;
    pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
    pub(crate) use cranelift_codegen::ir::function::Function;
    pub(crate) use cranelift_codegen::ir::types;
    pub(crate) use cranelift_codegen::ir::{
        AbiParam, Block, ExternalName, FuncRef, Inst, InstBuilder, MemFlags, Signature, SourceLoc,
        StackSlot, StackSlotData, StackSlotKind, TrapCode, Type, Value,
    };
    pub(crate) use cranelift_codegen::isa::{self, CallConv};
    pub(crate) use cranelift_codegen::Context;
    pub(crate) use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
    pub(crate) use cranelift_module::{self, DataContext, DataId, FuncId, Linkage, Module};

    pub(crate) use crate::abi::*;
    pub(crate) use crate::base::{codegen_operand, codegen_place};
    pub(crate) use crate::cast::*;
    pub(crate) use crate::common::*;
    pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
    pub(crate) use crate::pointer::Pointer;
    pub(crate) use crate::trap::*;
    pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
}

struct PrintOnPanic<F: Fn() -> String>(F);
impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
    fn drop(&mut self) {
        if ::std::thread::panicking() {
            println!("{}", (self.0)());
        }
    }
}

struct CodegenCx<'tcx, M: Module> {
    tcx: TyCtxt<'tcx>,
    module: M,
    global_asm: String,
    constants_cx: ConstantCx,
    cached_context: Context,
    vtables: FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
    debug_context: Option<DebugContext<'tcx>>,
    unwind_context: UnwindContext<'tcx>,
}

impl<'tcx, M: Module> CodegenCx<'tcx, M> {
    fn new(tcx: TyCtxt<'tcx>, module: M, debug_info: bool, pic_eh_frame: bool) -> Self {
        let unwind_context = UnwindContext::new(tcx, module.isa(), pic_eh_frame);
        let debug_context = if debug_info {
            Some(DebugContext::new(tcx, module.isa()))
        } else {
            None
        };
        CodegenCx {
            tcx,
            module,
            global_asm: String::new(),
            constants_cx: ConstantCx::default(),
            cached_context: Context::new(),
            vtables: FxHashMap::default(),
            debug_context,
            unwind_context,
        }
    }

    fn finalize(mut self) -> (M, String, Option<DebugContext<'tcx>>, UnwindContext<'tcx>) {
        self.constants_cx.finalize(self.tcx, &mut self.module);
        (
            self.module,
            self.global_asm,
            self.debug_context,
            self.unwind_context,
        )
    }
}

#[derive(Copy, Clone, Debug)]
pub enum CodegenMode {
    Aot,
    Jit,
    JitLazy,
}

impl Default for CodegenMode {
    fn default() -> Self {
        CodegenMode::Aot
    }
}

impl FromStr for CodegenMode {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "aot" => Ok(CodegenMode::Aot),
            "jit" => Ok(CodegenMode::Jit),
            "jit-lazy" => Ok(CodegenMode::JitLazy),
            _ => Err(format!("Unknown codegen mode `{}`", s)),
        }
    }
}

#[derive(Copy, Clone, Debug, Default)]
pub struct BackendConfig {
    pub codegen_mode: CodegenMode,
}

impl BackendConfig {
    fn from_opts(opts: &[String]) -> Result<Self, String> {
        let mut config = BackendConfig::default();
        for opt in opts {
            if let Some((name, value)) = opt.split_once('=') {
                match name {
                    "mode" => config.codegen_mode = value.parse()?,
                    _ => return Err(format!("Unknown option `{}`", name)),
                }
            } else {
                return Err(format!("Invalid option `{}`", opt));
            }
        }
        Ok(config)
    }
}

pub struct CraneliftCodegenBackend {
    pub config: Option<BackendConfig>,
}

impl CodegenBackend for CraneliftCodegenBackend {
    fn init(&self, sess: &Session) {
        if sess.lto() != rustc_session::config::Lto::No && sess.opts.cg.embed_bitcode {
            sess.warn("LTO is not supported. You may get a linker error.");
        }
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        Box::new(crate::metadata::CraneliftMetadataLoader)
    }

    fn provide(&self, _providers: &mut Providers) {}
    fn provide_extern(&self, _providers: &mut Providers) {}

    fn target_features(&self, _sess: &Session) -> Vec<rustc_span::Symbol> {
        vec![]
    }

    fn codegen_crate<'tcx>(
        &self,
        tcx: TyCtxt<'tcx>,
        metadata: EncodedMetadata,
        need_metadata_module: bool,
    ) -> Box<dyn Any> {
        let config = if let Some(config) = self.config {
            config
        } else {
            BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
                .unwrap_or_else(|err| tcx.sess.fatal(&err))
        };
        let res = driver::codegen_crate(tcx, metadata, need_metadata_module, config);

        res
    }

    fn join_codegen(
        &self,
        ongoing_codegen: Box<dyn Any>,
        _sess: &Session,
    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
        Ok(*ongoing_codegen
            .downcast::<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>)>()
            .unwrap())
    }

    fn link(
        &self,
        sess: &Session,
        codegen_results: CodegenResults,
        outputs: &OutputFilenames,
    ) -> Result<(), ErrorReported> {
        use rustc_codegen_ssa::back::link::link_binary;

        let target_cpu = crate::target_triple(sess).to_string();
        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
            sess,
            &codegen_results,
            outputs,
            &codegen_results.crate_name.as_str(),
            &target_cpu,
        );

        Ok(())
    }
}

fn target_triple(sess: &Session) -> target_lexicon::Triple {
    sess.target.llvm_target.parse().unwrap()
}

fn build_isa(sess: &Session) -> Box<dyn isa::TargetIsa + 'static> {
    use target_lexicon::BinaryFormat;

    let target_triple = crate::target_triple(sess);

    let mut flags_builder = settings::builder();
    flags_builder.enable("is_pic").unwrap();
    flags_builder.set("enable_probestack", "false").unwrap(); // __cranelift_probestack is not provided
    flags_builder
        .set(
            "enable_verifier",
            if cfg!(debug_assertions) {
                "true"
            } else {
                "false"
            },
        )
        .unwrap();

    let tls_model = match target_triple.binary_format {
        BinaryFormat::Elf => "elf_gd",
        BinaryFormat::Macho => "macho",
        BinaryFormat::Coff => "coff",
        _ => "none",
    };
    flags_builder.set("tls_model", tls_model).unwrap();

    flags_builder.set("enable_simd", "true").unwrap();

    use rustc_session::config::OptLevel;
    match sess.opts.optimize {
        OptLevel::No => {
            flags_builder.set("opt_level", "none").unwrap();
        }
        OptLevel::Less | OptLevel::Default => {}
        OptLevel::Aggressive => {
            flags_builder.set("opt_level", "speed_and_size").unwrap();
        }
        OptLevel::Size | OptLevel::SizeMin => {
            sess.warn("Optimizing for size is not supported. Just ignoring the request");
        }
    }

    let flags = settings::Flags::new(flags_builder);

    let variant = if cfg!(feature = "oldbe") {
        cranelift_codegen::isa::BackendVariant::Legacy
    } else {
        cranelift_codegen::isa::BackendVariant::MachInst
    };
    let mut isa_builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
    // Don't use "haswell", as it implies `has_lzcnt`.macOS CI is still at Ivy Bridge EP, so `lzcnt`
    // is interpreted as `bsr`.
    isa_builder.enable("nehalem").unwrap();
    isa_builder.finish(flags)
}

/// This is the entrypoint for a hot plugged rustc_codegen_cranelift
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(CraneliftCodegenBackend { config: None })
}
<|endoftext|>


<commit_before>// Copyright (C) 2013-2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![crate_name = "gobject-2_0-sys"]
#![crate_type = "lib"]

#![allow(missing_copy_implementations)]

extern crate "glib-2_0-sys" as glib;

use glib::types::{gboolean, gchar, gdouble, gfloat, gint, glong};
use glib::types::{gsize, guchar, guint, gulong};
use glib::types::{gpointer, gconstpointer};

pub type GType = gsize;

#[repr(C)]
pub struct GTypeInstance {
    g_class: gpointer
}

#[repr(C)]
pub struct GObject {
    g_type_instance: GTypeInstance,
    ref_count: guint,
    data: gpointer
}

#[repr(C)]
pub struct GValue {
    pub g_type: GType,
    // If the data enum layout turns out to be different on some arch,
    // we'd need arch-specific redefinitions
    data: [u64; 2]
}

pub type GBoxedCopyFunc = extern "C" fn (gpointer) -> gpointer;
pub type GBoxedFreeFunc = extern "C" fn (gpointer);

extern {
    pub fn g_boxed_type_register_static(name: *const gchar, boxed_copy: GBoxedCopyFunc, boxed_free: GBoxedFreeFunc) -> GType;
    pub fn g_object_get_type() -> GType;
    pub fn g_object_ref(obj: gpointer) -> gpointer;
    pub fn g_object_unref(obj: gpointer);
    pub fn g_type_check_instance_is_a(instance: *const GTypeInstance, iface_type: GType) -> gboolean;
    pub fn g_type_from_name(name: *const gchar) -> GType;
    pub fn g_type_name(t: GType) -> *const gchar;
    pub fn g_value_copy(src: *const GValue, dst: *mut GValue);
    pub fn g_value_get_boolean(value: *const GValue) -> gboolean;
    pub fn g_value_get_boxed(value: *const GValue) -> gpointer;
    pub fn g_value_get_char(value: *const GValue) -> gchar;
    pub fn g_value_get_double(value: *const GValue) -> gdouble;
    pub fn g_value_get_float(value: *const GValue) -> gfloat;
    pub fn g_value_get_int(value: *const GValue) -> gint;
    pub fn g_value_get_int64(value: *const GValue) -> i64;
    pub fn g_value_get_long(value: *const GValue) -> glong;
    pub fn g_value_get_object(value: *const GValue) -> gpointer;
    pub fn g_value_get_schar(value: *const GValue) -> i8;
    pub fn g_value_get_string(value: *const GValue) -> *const gchar;
    pub fn g_value_get_uchar(value: *const GValue) -> guchar;
    pub fn g_value_get_uint(value: *const GValue) -> guint;
    pub fn g_value_get_uint64(value: *const GValue) -> u64;
    pub fn g_value_get_ulong(value: *const GValue) -> gulong;
    pub fn g_value_dup_boxed(value: *const GValue) -> gpointer;
    pub fn g_value_init(value: *mut GValue, type_id: GType) -> *mut GValue;
    pub fn g_value_set_boolean(value: *mut GValue, v_boolean: gboolean);
    pub fn g_value_set_char(value: *mut GValue, v_char: gchar);
    pub fn g_value_set_double(value: *mut GValue, v_double: gdouble);
    pub fn g_value_set_float(value: *mut GValue, v_float: gfloat);
    pub fn g_value_set_int(value: *mut GValue, v_int: gint);
    pub fn g_value_set_int64(value: *mut GValue, v_int: i64);
    pub fn g_value_set_long(value: *mut GValue, v_long: glong);
    pub fn g_value_set_object(value: *mut GValue, v_object: gpointer);
    pub fn g_value_set_schar(value: *mut GValue, v_char: i8);
    pub fn g_value_set_string(value: *mut GValue, v_string: *const gchar);
    pub fn g_value_set_static_string(value: *mut GValue, v_string: *const gchar);
    pub fn g_value_set_uchar(value: *mut GValue, v_char: guchar);
    pub fn g_value_set_uint(value: *mut GValue, v_uint: guint);
    pub fn g_value_set_uint64(value: *mut GValue, v_uint: u64);
    pub fn g_value_set_ulong(value: *mut GValue, v_ulong: gulong);
    pub fn g_value_take_boxed(value: *mut GValue, v_boxed: gconstpointer);
    pub fn g_value_take_string(value: *mut GValue, v_string: *mut gchar);
    pub fn g_value_unset(value: *mut GValue);
}
<commit_msg>Added g_value_reset()<commit_after>// Copyright (C) 2013-2015  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#![crate_name = "gobject-2_0-sys"]
#![crate_type = "lib"]

#![allow(missing_copy_implementations)]

extern crate "glib-2_0-sys" as glib;

use glib::types::{gboolean, gchar, gdouble, gfloat, gint, glong};
use glib::types::{gsize, guchar, guint, gulong};
use glib::types::{gpointer, gconstpointer};

pub type GType = gsize;

#[repr(C)]
pub struct GTypeInstance {
    g_class: gpointer
}

#[repr(C)]
pub struct GObject {
    g_type_instance: GTypeInstance,
    ref_count: guint,
    data: gpointer
}

#[repr(C)]
pub struct GValue {
    pub g_type: GType,
    // If the data enum layout turns out to be different on some arch,
    // we'd need arch-specific redefinitions
    data: [u64; 2]
}

pub type GBoxedCopyFunc = extern "C" fn (gpointer) -> gpointer;
pub type GBoxedFreeFunc = extern "C" fn (gpointer);

extern {
    pub fn g_boxed_type_register_static(name: *const gchar, boxed_copy: GBoxedCopyFunc, boxed_free: GBoxedFreeFunc) -> GType;
    pub fn g_object_get_type() -> GType;
    pub fn g_object_ref(obj: gpointer) -> gpointer;
    pub fn g_object_unref(obj: gpointer);
    pub fn g_type_check_instance_is_a(instance: *const GTypeInstance, iface_type: GType) -> gboolean;
    pub fn g_type_from_name(name: *const gchar) -> GType;
    pub fn g_type_name(t: GType) -> *const gchar;
    pub fn g_value_copy(src: *const GValue, dst: *mut GValue);
    pub fn g_value_get_boolean(value: *const GValue) -> gboolean;
    pub fn g_value_get_boxed(value: *const GValue) -> gpointer;
    pub fn g_value_get_char(value: *const GValue) -> gchar;
    pub fn g_value_get_double(value: *const GValue) -> gdouble;
    pub fn g_value_get_float(value: *const GValue) -> gfloat;
    pub fn g_value_get_int(value: *const GValue) -> gint;
    pub fn g_value_get_int64(value: *const GValue) -> i64;
    pub fn g_value_get_long(value: *const GValue) -> glong;
    pub fn g_value_get_object(value: *const GValue) -> gpointer;
    pub fn g_value_get_schar(value: *const GValue) -> i8;
    pub fn g_value_get_string(value: *const GValue) -> *const gchar;
    pub fn g_value_get_uchar(value: *const GValue) -> guchar;
    pub fn g_value_get_uint(value: *const GValue) -> guint;
    pub fn g_value_get_uint64(value: *const GValue) -> u64;
    pub fn g_value_get_ulong(value: *const GValue) -> gulong;
    pub fn g_value_dup_boxed(value: *const GValue) -> gpointer;
    pub fn g_value_init(value: *mut GValue, type_id: GType) -> *mut GValue;
    pub fn g_value_reset(value: *mut GValue) -> *mut GValue;
    pub fn g_value_set_boolean(value: *mut GValue, v_boolean: gboolean);
    pub fn g_value_set_char(value: *mut GValue, v_char: gchar);
    pub fn g_value_set_double(value: *mut GValue, v_double: gdouble);
    pub fn g_value_set_float(value: *mut GValue, v_float: gfloat);
    pub fn g_value_set_int(value: *mut GValue, v_int: gint);
    pub fn g_value_set_int64(value: *mut GValue, v_int: i64);
    pub fn g_value_set_long(value: *mut GValue, v_long: glong);
    pub fn g_value_set_object(value: *mut GValue, v_object: gpointer);
    pub fn g_value_set_schar(value: *mut GValue, v_char: i8);
    pub fn g_value_set_string(value: *mut GValue, v_string: *const gchar);
    pub fn g_value_set_static_string(value: *mut GValue, v_string: *const gchar);
    pub fn g_value_set_uchar(value: *mut GValue, v_char: guchar);
    pub fn g_value_set_uint(value: *mut GValue, v_uint: guint);
    pub fn g_value_set_uint64(value: *mut GValue, v_uint: u64);
    pub fn g_value_set_ulong(value: *mut GValue, v_ulong: gulong);
    pub fn g_value_take_boxed(value: *mut GValue, v_boxed: gconstpointer);
    pub fn g_value_take_string(value: *mut GValue, v_string: *mut gchar);
    pub fn g_value_unset(value: *mut GValue);
}
<|endoftext|>