<commit_before>use std::collections::HashMap;
use std::collections::hash_map::IterMut;
use std::collections::hash_map::Entry::{Vacant, Occupied};

use parser::ast::NodeId;

use parser::interner::Name;

#[derive(Debug)]
pub struct SymTable {
    map: HashMap<Name, Sym>
}

impl SymTable {
    // creates a new table
    pub fn new() -> SymTable {
        SymTable {
            map: HashMap::new()
        }
    }

    // finds symbol in table
    pub fn find(&self, name: Name) -> Option<&Sym> {
        self.map.get(&name)
    }

    // inserts symbol into the table
    pub fn insert(& mut self, name: Name, sym: Sym) -> Result<(), &Sym> {
        match self.map.entry(name) {
            Vacant(entry) => {
                entry.insert(sym);

                Ok(())
            }

            Occupied(old) => Err(old.into_mut())
        }
    }

    pub fn functions_mut(&mut self) -> SymFunctionIterMut {
        SymFunctionIterMut {
            iter: self.map.iter_mut()
        }
    }
}

#[derive(Debug)]
pub enum Sym {
    SymLocalVar(SymLocalVarType),
    SymFunction(SymFunctionType),
    SymType(SymTypeType),

    // only for testing purposes
    SymDummy(u8),
}

impl Sym {
    pub fn create_type(name: Name, builtin: BuiltinType) -> Sym {
        Sym::SymType(SymTypeType {
            name: name,
            builtin: builtin
        })
    }

    pub fn to_local_var(&self) -> Option<&SymLocalVarType> {
        match *self {
            Sym::SymLocalVar(ref sym) => Some(sym),
            _ => None
        }
    }

    pub fn to_function(&self) -> Option<&SymFunctionType> {
        match *self {
            Sym::SymFunction(ref sym) => Some(sym),
            _ => None
        }
    }

    pub fn to_type(&self) -> Option<&SymTypeType> {
        match *self {
            Sym::SymType(ref sym) => Some(sym),
            _ => None
        }
    }
}

#[derive(Debug)]
pub struct SymTypeType {
    pub name: Name,
    pub builtin: BuiltinType,
}

#[derive(Debug)]
pub enum Type {
    TypeBasic(TypeBasicType),
    TypeTuple(TypeTupleType),
    TypeArray(TypeArrayType),
    TypePtr(TypePtrType),
}

impl Type {
    pub fn create_unit() -> Type {
        Type::TypeTuple(TypeTupleType {
            subtypes: Vec::new()
        })
    }

    pub fn create_tuple(subtypes: Vec<Box<Type>>) -> Type {
        Type::TypeTuple(TypeTupleType {
            subtypes: subtypes
        })
    }

    pub fn create_basic(name: Name) -> Type {
        Type::TypeBasic(TypeBasicType {
            name: name
        })
    }

    pub fn create_ptr(subtype: Box<Type>) -> Type {
        Type::TypePtr(TypePtrType {
            subtype: subtype
        })
    }

    pub fn create_array(subtype: Box<Type>) -> Type {
        Type::TypeArray(TypeArrayType {
            subtype: subtype
        })
    }
}

#[derive(Debug)]
pub struct TypeBasicType {
    pub name: Name
}

#[derive(Debug)]
pub struct TypeTupleType {
    pub subtypes: Vec<Box<Type>>
}

#[derive(Debug)]
pub struct TypeArrayType {
    pub subtype: Box<Type>
}

#[derive(Debug)]
pub struct TypePtrType {
    pub subtype: Box<Type>
}

#[derive(Debug)]
pub enum BuiltinType {
    Int,
    Bool,
    Str,
}

#[derive(Debug)]
pub struct SymFunctionType {
    pub name: Name,
    pub return_type: Type,
    pub params: Vec<Param>,
    pub body: NodeId,
}

#[derive(Debug)]
pub struct Param {
    pub name: Name,
    pub data_type: Type
}

#[derive(Debug)]
pub struct SymLocalVarType {
    pub name: Name,
    pub data_type: Type,
    pub expr: Option<NodeId>,
}

struct SymFunctionIterMut<'a> {
    iter: IterMut<'a, Name, Sym>
}

impl<'a> Iterator for SymFunctionIterMut<'a> {
    type Item = &'a SymFunctionType;

    fn next(&mut self) -> Option<&'a SymFunctionType> {
        loop {
            let next = self.iter.next();

            match next {
                None => return None,

                Some(val) => {
                    if let Sym::SymFunction(ref fct) = *val.1 {
                        return Some(fct);
                    }
                }
            }
        }
    }
}

#[test]
fn test_insert_and_find_again() {
    let mut table = SymTable::new();

    assert!(table.insert(Name(1), Sym::SymDummy(1)).is_ok());
    assert!(table.find(Name(1)).is_some());
    assert!(table.find(Name(2)).is_none());
}

#[test]
fn test_insert_twice_into_same_level() {
    let mut table = SymTable::new();

    assert!(table.insert(Name(1), Sym::SymDummy(1)).is_ok());
    assert!(table.insert(Name(1), Sym::SymDummy(2)).is_err());
}

<commit_msg>sym: reworked Sym-Variants<commit_after>use std::collections::HashMap;
use std::collections::hash_map::IterMut;
use std::collections::hash_map::Entry::{Vacant, Occupied};

use parser::ast::NodeId;

use parser::interner::Name;

#[derive(Debug)]
pub struct SymTable {
    map: HashMap<Name, Sym>
}

impl SymTable {
    // creates a new table
    pub fn new() -> SymTable {
        SymTable {
            map: HashMap::new()
        }
    }

    // finds symbol in table
    pub fn find(&self, name: Name) -> Option<&Sym> {
        self.map.get(&name)
    }

    // inserts symbol into the table
    pub fn insert(& mut self, name: Name, sym: Sym) -> Result<(), &Sym> {
        match self.map.entry(name) {
            Vacant(entry) => {
                entry.insert(sym);

                Ok(())
            }

            Occupied(old) => Err(old.into_mut())
        }
    }
}

#[derive(Debug)]
pub enum Sym {
    SymType(BuiltinType),
    SymFunction(NodeId),
    SymVar(NodeId),
}

#[derive(Debug)]
pub enum BuiltinType {
    Int,
    Bool,
    Str,
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate mount;

use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::path::Path;

use iron::{Iron, Request, Response, IronResult};
use iron::status;
use mount::Mount;

use git2::{Repository, Oid};
use rustc_serialize::json;

use processor;

pub fn start(port: u16) {
    let addr = SocketAddr::new(IpAddr::from_str("127.0.0.1").unwrap(), port);
    let mut mount = Mount::new();

    mount.mount("/", index);
    mount.mount("/api", api);

    Iron::new(mount).http(addr).unwrap();
}

fn index(req: &mut Request) -> IronResult<Response> {
    println!("Running index handler, URL path: {:?}", req.url.path);
    Ok(Response::with((status::Ok, "Index!!")))
}

fn api(req: &mut Request) -> IronResult<Response> {
    println!("Running repo handler, URL path: {:?}, Query: {:?}", req.url.path, req.url.query);
    // match req.url.query {
    //     3 => {
    //         let path = Path::new(&req.url.path[0]);
    //         let repo = match Repository::discover(&path) {
    //             Ok(repo) => repo,
    //             Err(_) => return Ok(Response::with((status::BadRequest, "Your input falls short of expectations"))),
    //         };
    //
    //         let old = match Oid::from_str(&req.url.path[1][..]) {
    //                Ok(oid) => oid,
    //                Err(_) => return Ok(Response::with((status::BadRequest, "Your input falls short of expectations"))),
    //         };
    //         let new = match Oid::from_str(&req.url.path[2][..]) {
    //                Ok(oid) => oid,
    //                Err(_) => return Ok(Response::with((status::BadRequest, "Your input falls short of expectations"))),
    //         };
    //         let out = match processor::commits(repo, old, new) {
    //             Ok(output) => output,
    //             Err(_) => return Ok(Response::with((status::InternalServerError, "Hold steadfast and report bugs."))),
    //         };
    //
    //         Ok(Response::with((status::Ok, json::encode(&out).unwrap())))
    //     },
    //     1 => {
    //         let path = Path::new(&req.url.path[0]);
    //         let repo = match Repository::discover(&path) {
    //             Ok(repo) => repo,
    //             Err(_) => return Ok(Response::with((status::BadRequest, "Your input falls short of expectations"))),
    //         };
    //
    //         let out = match processor::repo(repo) {
    //             Ok(output) => output,
    //             Err(_) => return Ok(Response::with((status::InternalServerError, "Hold steadfast and report bugs."))),
    //         };
    //         Ok(Response::with((status::Ok, json::encode(&out).unwrap())))
    //     },
    //     _ => Ok(Response::with((status::NotFound, "Your work is nothingness.")))
    // }

}
<commit_msg>API for #11, #12<commit_after>extern crate iron;
extern crate mount;

use std::net::{IpAddr, SocketAddr};
use std::str::FromStr;
use std::path::Path;

use iron::{Iron, Request, Response, IronResult};
use iron::status;
use mount::Mount;

use git2::{Repository, Oid};
use rustc_serialize::json;

use processor;

pub fn start(port: u16) {
    let addr = SocketAddr::new(IpAddr::from_str("127.0.0.1").unwrap(), port);
    let mut mount = Mount::new();

    mount.mount("/", index);
    mount.mount("/api", api);

    Iron::new(mount).http(addr).unwrap();
}

fn index(req: &mut Request) -> IronResult<Response> {
    println!("Running index handler, URL path: {:?}", req.url.path);
    Ok(Response::with((status::Ok, "Index!!")))
}

fn api(req: &mut Request) -> IronResult<Response> {
    let query_pairs = req.url.clone().into_generic_url().query_pairs().unwrap_or(vec![]);
    let mut repo = None;
    let mut old = None;
    let mut new = None;
    for (key, val) in query_pairs {
        match &key[..] {
            "repo" => repo = match Repository::discover(&val) {
                Ok(repo) => Some(repo),
                Err(_) => return Ok(Response::with((status::BadRequest, "Repository Invalid."))),
            },
            "old" => old = match Oid::from_str(&val) {
                Ok(commit) => Some(commit),
                Err(_) => return Ok(Response::with((status::BadRequest, "Old Commit Invalid."))),
            },
            "new" => new = match Oid::from_str(&val) {
                Ok(commit) => Some(commit),
                Err(_) => return Ok(Response::with((status::BadRequest, "New Commit Invalid"))),
            },
            _ => return Ok(Response::with((status::BadRequest, "Your input falls short of expectations"))),
        }
    }
    match (repo, old, new) {
        (Some(repo), Some(old), Some(new)) => {
            let out = match processor::commits(repo, old, new) {
                Ok(output) => output,
                Err(_) => return Ok(Response::with((status::InternalServerError, "Hold steadfast and report bugs."))),
            };
            Ok(Response::with((status::Ok, json::encode(&out).unwrap())))
        },
        (Some(repo), None, None) => {
            let out = match processor::repo(repo) {
                Ok(output) => output,
                Err(_) => return Ok(Response::with((status::InternalServerError, "Hold steadfast and report bugs."))),
            };
            Ok(Response::with((status::Ok, json::encode(&out).unwrap())))
        },
        _ => Ok(Response::with((status::BadRequest, "Your input falls short of expectations")))
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

//! jsonrpc server over win named pipes
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate json_ipc_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use json_ipc_server::Server;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new("/tmp/json-ipc-test.ipc", &Arc::new(io)).unwrap();
//!     ::std::thread::spawn(move || server.run());
//! }
//! ```

//! Named pipes library

use miow::pipe::{NamedPipe, NamedPipeBuilder};
use miow::Overlapped;
use miow::iocp::CompletionPort;
use std;
use std::io;
use std::io::{Read, Write};
use std::sync::atomic::*;
use std::sync::Arc;
use jsonrpc_core::IoHandler;
use validator;

pub type Result<T> = std::result::Result<T, Error>;

const MAX_REQUEST_LEN: u32 = 65536;
const REQUEST_READ_BATCH: usize = 4096;
const POLL_PARK_TIMEOUT_MS: u64 = 10;
const STARTING_PIPE_TOKEN: u32 = 1;

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    NotStarted,
    AlreadyStopping,
    NotStopped,
    IsStopping,
}

impl std::convert::From<std::io::Error> for Error {
    fn from(io_error: std::io::Error) -> Error {
        Error::Io(io_error)
    }
}

pub struct PipeHandler {
    waiting_pipe: NamedPipe,
    io_handler: Arc<IoHandler>,
    handle_counter: u32,
}

impl PipeHandler {
    /// start ipc rpc server (blocking)
    pub fn start(addr: &str, io_handler: &Arc<IoHandler>) -> Result<PipeHandler> {
        Ok(PipeHandler {
            waiting_pipe: try!(
                NamedPipeBuilder::new(addr)
                    .first(true)
                    .accept_remote(true)
                    .max_instances(255)
                    .inbound(true)
                    .outbound(true)
                    .out_buffer_size(MAX_REQUEST_LEN)
                    .in_buffer_size(MAX_REQUEST_LEN)
                    .create()
            ),
            io_handler: io_handler.clone(),
            handle_counter: STARTING_PIPE_TOKEN,
        })
    }

    fn handle_incoming(&mut self, addr: &str, stop: Arc<AtomicBool>) -> io::Result<()> {
        let cp = try!(CompletionPort::new(self.handle_counter));
        let pipe_token = self.handle_counter as usize + 1;
        try!(cp.add_handle(pipe_token, &self.waiting_pipe));

        let mut overlapped = Overlapped::zero();
        unsafe { try!(self.waiting_pipe.connect_overlapped(&mut overlapped)); };
        trace!(target: "ipc", "Waiting for client: [{}, {}] [{}]", self.handle_counter, pipe_token, addr);
        while !stop.load(Ordering::Relaxed) {
            if let Ok(status) = cp.get(None) {
                if status.token() == pipe_token
                {
                    trace!(target: "ipc", "Received connection to address [{}]", addr);
                    break;
                }
            }
            std::thread::park_timeout(std::time::Duration::from_millis(POLL_PARK_TIMEOUT_MS));
        }

        if stop.load(Ordering::Relaxed) {
            trace!(target: "ipc", "Stopped listening sequence [{}]", addr);
            return Ok(())
        }

        let mut connected_pipe = std::mem::replace::<NamedPipe>(&mut self.waiting_pipe,
            try!(NamedPipeBuilder::new(addr)
                .first(false)
                .accept_remote(true)
                .inbound(true)
                .outbound(true)
                .out_buffer_size(MAX_REQUEST_LEN)
                .in_buffer_size(MAX_REQUEST_LEN)
                .create()));
        self.handle_counter += 2;

        let thread_handler = self.io_handler.clone();
        std::thread::spawn(move || {
            let mut buf = vec![0u8; MAX_REQUEST_LEN as usize];
            let mut fin = REQUEST_READ_BATCH;
            loop {
                let start = fin - REQUEST_READ_BATCH;
                match connected_pipe.read(&mut buf[start..fin]) {
                    Ok(size) => {
                        let effective = &buf[0..start + size];
                        fin = fin + REQUEST_READ_BATCH;
                        if !validator::is_valid(effective) {
                            continue;
                        }
                        trace!(target: "ipc", "Received rpc request: {} bytes", effective.len());

                        if let Err(parse_err) = String::from_utf8(effective.to_vec())
                            .map(|rpc_msg|
                                 {
                                    let response: Option<String> = thread_handler.handle_request(&rpc_msg);
                                    if let Some(response_str) = response {
                                        let response_bytes = response_str.into_bytes();
                                        if let Err(write_err) = connected_pipe.write_all(&response_bytes[..]) {
                                            trace!(target: "ipc", "Response write error: {:?}", write_err);
                                        }
                                        trace!(target: "ipc", "Sent rpc response:  {} bytes", response_bytes.len());
                                        connected_pipe.flush().unwrap();
                                    }
                                }
                            )
                        {
                            trace!(target: "ipc", "Response decode error: {:?}", parse_err);
                        }

                        fin = REQUEST_READ_BATCH;
                    },
                    Err(e) => {
                        // closed connection
                        trace!(target: "ipc", "Dropped connection {:?}", e);
                        break;
                    }
                }
            }
        });

        Ok(())
    }
}

pub struct Server {
    is_stopping: Arc<AtomicBool>,
    is_stopped: Arc<AtomicBool>,
    addr: String,
    io_handler: Arc<IoHandler>,
}

impl Server {
    /// New server
    pub fn new(socket_addr: &str, io_handler: &Arc<IoHandler>) -> Result<Server> {
        Ok(Server {
            io_handler: io_handler.clone(),
            is_stopping: Arc::new(AtomicBool::new(false)),
            is_stopped: Arc::new(AtomicBool::new(true)),
            addr: socket_addr.to_owned(),
        })
    }

    /// Run server (in this thread)
    pub fn run(&self) -> Result<()> {
        let mut pipe_handler = try!(PipeHandler::start(&self.addr, &self.io_handler));
        loop  {
            try!(pipe_handler.handle_incoming(&self.addr, Arc::new(AtomicBool::new(false))));
        }
    }

    /// Run server (in separate thread)
    pub fn run_async(&self) -> Result<()> {
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::IsStopping) }
        if !self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStopped) }

        trace!(target: "ipc", "Started named pipes server [{}]", self.addr);

        let thread_stopping = self.is_stopping.clone();
        let thread_stopped = self.is_stopped.clone();
        let thread_handler = self.io_handler.clone();
        let addr = self.addr.clone();
        std::thread::spawn(move || {
            let mut pipe_handler = PipeHandler::start(&addr, &thread_handler).unwrap();
            while !thread_stopping.load(Ordering::Relaxed) {
                if let Err(pipe_listener_error) = pipe_handler.handle_incoming(&addr, thread_stopping.clone()) {
                    trace!(target: "ipc", "Pipe listening error: {:?}", pipe_listener_error);
                }
            }
            thread_stopped.store(true, Ordering::Relaxed);
        });

        self.is_stopped.store(false, Ordering::Relaxed);
        Ok(())
    }

    pub fn stop_async(&self) -> Result<()> {
        if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
        self.is_stopping.store(true, Ordering::Relaxed);
        Ok(())
    }

    pub fn stop(&self) -> Result<()> {
        if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
        self.is_stopping.store(true, Ordering::Relaxed);
        while !self.is_stopped.load(Ordering::Relaxed) { std::thread::park_timeout(std::time::Duration::new(0, 50)); }
        Ok(())
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.stop_async().unwrap_or_else(|_| {}); // ignore error - can be stopped already
        // todo : no stable logging for windows?
        trace!(target: "ipc", "IPC Server : shutdown");
    }
}
<commit_msg>enhanced logging<commit_after>// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

//! jsonrpc server over win named pipes
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate json_ipc_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use json_ipc_server::Server;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let server = Server::new("/tmp/json-ipc-test.ipc", &Arc::new(io)).unwrap();
//!     ::std::thread::spawn(move || server.run());
//! }
//! ```

//! Named pipes library

use miow::pipe::{NamedPipe, NamedPipeBuilder};
use miow::Overlapped;
use miow::iocp::CompletionPort;
use std;
use std::io;
use std::io::{Read, Write};
use std::sync::atomic::*;
use std::sync::Arc;
use jsonrpc_core::IoHandler;
use validator;

pub type Result<T> = std::result::Result<T, Error>;

const MAX_REQUEST_LEN: u32 = 65536;
const REQUEST_READ_BATCH: usize = 4096;
const POLL_PARK_TIMEOUT_MS: u64 = 10;
const STARTING_PIPE_TOKEN: u32 = 1;

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    NotStarted,
    AlreadyStopping,
    NotStopped,
    IsStopping,
}

impl std::convert::From<std::io::Error> for Error {
    fn from(io_error: std::io::Error) -> Error {
        Error::Io(io_error)
    }
}

pub struct PipeHandler {
    waiting_pipe: NamedPipe,
    io_handler: Arc<IoHandler>,
    handle_counter: u32,
}

impl PipeHandler {
    /// start ipc rpc server (blocking)
    pub fn start(addr: &str, io_handler: &Arc<IoHandler>) -> Result<PipeHandler> {
        Ok(PipeHandler {
            waiting_pipe: try!(
                NamedPipeBuilder::new(addr)
                    .first(true)
                    .accept_remote(true)
                    .max_instances(255)
                    .inbound(true)
                    .outbound(true)
                    .out_buffer_size(MAX_REQUEST_LEN)
                    .in_buffer_size(MAX_REQUEST_LEN)
                    .create()
            ),
            io_handler: io_handler.clone(),
            handle_counter: STARTING_PIPE_TOKEN,
        })
    }

    fn handle_incoming(&mut self, addr: &str, stop: Arc<AtomicBool>) -> io::Result<()> {
        let cp = try!(CompletionPort::new(self.handle_counter));
        let pipe_token = self.handle_counter as usize + 1;
        try!(cp.add_handle(pipe_token, &self.waiting_pipe));

        let mut overlapped = Overlapped::zero();
        unsafe { try!(self.waiting_pipe.connect_overlapped(&mut overlapped)); };
        trace!(target: "ipc", "Waiting for client: [{}, {}] [{}]", self.handle_counter, pipe_token, addr);
        while !stop.load(Ordering::Relaxed) {
            if let Ok(status) = cp.get(None) {
                if status.token() == pipe_token
                {
                    trace!(target: "ipc", "Received connection to address [{}]", addr);
                    break;
                }
            }
            std::thread::park_timeout(std::time::Duration::from_millis(POLL_PARK_TIMEOUT_MS));
        }

        if stop.load(Ordering::Relaxed) {
            trace!(target: "ipc", "Stopped listening sequence [{}]", addr);
            return Ok(())
        }

        let mut connected_pipe = std::mem::replace::<NamedPipe>(&mut self.waiting_pipe,
            try!(NamedPipeBuilder::new(addr)
                .first(false)
                .accept_remote(true)
                .inbound(true)
                .outbound(true)
                .out_buffer_size(MAX_REQUEST_LEN)
                .in_buffer_size(MAX_REQUEST_LEN)
                .create()));
        self.handle_counter += 2;

        let thread_handler = self.io_handler.clone();
        std::thread::spawn(move || {
            let mut buf = vec![0u8; MAX_REQUEST_LEN as usize];
            let mut fin = REQUEST_READ_BATCH;
            loop {
                let start = fin - REQUEST_READ_BATCH;
                match connected_pipe.read(&mut buf[start..fin]) {
                    Ok(size) => {
                        let effective = &buf[0..start + size];
                        fin = fin + REQUEST_READ_BATCH;
                        if !validator::is_valid(effective) {
                            continue;
                        }
                        trace!(target: "ipc", "Received rpc request: {} bytes", effective.len());

                        if let Err(parse_err) = String::from_utf8(effective.to_vec())
                            .map(|rpc_msg|
                                 {
                                     trace!(target: "ipc", "Request: {}", &rpc_msg);
                                     let response: Option<String> = thread_handler.handle_request(&rpc_msg);

                                     if let Some(response_str) = response {
                                        trace!(target: "ipc", "Response: {}", &response_str);
                                        let response_bytes = response_str.into_bytes();
                                        if let Err(write_err) = connected_pipe.write_all(&response_bytes[..]) {
                                            trace!(target: "ipc", "Response write error: {:?}", write_err);
                                        }
                                        trace!(target: "ipc", "Sent rpc response:  {} bytes", response_bytes.len());
                                        connected_pipe.flush().unwrap();
                                    }
                                }
                            )
                        {
                            trace!(target: "ipc", "Response decode error: {:?}", parse_err);
                        }

                        fin = REQUEST_READ_BATCH;
                    },
                    Err(e) => {
                        // closed connection
                        trace!(target: "ipc", "Dropped connection {:?}", e);
                        break;
                    }
                }
            }
        });

        Ok(())
    }
}

pub struct Server {
    is_stopping: Arc<AtomicBool>,
    is_stopped: Arc<AtomicBool>,
    addr: String,
    io_handler: Arc<IoHandler>,
}

impl Server {
    /// New server
    pub fn new(socket_addr: &str, io_handler: &Arc<IoHandler>) -> Result<Server> {
        Ok(Server {
            io_handler: io_handler.clone(),
            is_stopping: Arc::new(AtomicBool::new(false)),
            is_stopped: Arc::new(AtomicBool::new(true)),
            addr: socket_addr.to_owned(),
        })
    }

    /// Run server (in this thread)
    pub fn run(&self) -> Result<()> {
        let mut pipe_handler = try!(PipeHandler::start(&self.addr, &self.io_handler));
        loop  {
            try!(pipe_handler.handle_incoming(&self.addr, Arc::new(AtomicBool::new(false))));
        }
    }

    /// Run server (in separate thread)
    pub fn run_async(&self) -> Result<()> {
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::IsStopping) }
        if !self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStopped) }

        trace!(target: "ipc", "Started named pipes server [{}]", self.addr);

        let thread_stopping = self.is_stopping.clone();
        let thread_stopped = self.is_stopped.clone();
        let thread_handler = self.io_handler.clone();
        let addr = self.addr.clone();
        std::thread::spawn(move || {
            let mut pipe_handler = PipeHandler::start(&addr, &thread_handler).unwrap();
            while !thread_stopping.load(Ordering::Relaxed) {
                if let Err(pipe_listener_error) = pipe_handler.handle_incoming(&addr, thread_stopping.clone()) {
                    trace!(target: "ipc", "Pipe listening error: {:?}", pipe_listener_error);
                }
            }
            thread_stopped.store(true, Ordering::Relaxed);
        });

        self.is_stopped.store(false, Ordering::Relaxed);
        Ok(())
    }

    pub fn stop_async(&self) -> Result<()> {
        if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
        self.is_stopping.store(true, Ordering::Relaxed);
        Ok(())
    }

    pub fn stop(&self) -> Result<()> {
        if self.is_stopped.load(Ordering::Relaxed) { return Err(Error::NotStarted) }
        if self.is_stopping.load(Ordering::Relaxed) { return Err(Error::AlreadyStopping)}
        self.is_stopping.store(true, Ordering::Relaxed);
        while !self.is_stopped.load(Ordering::Relaxed) { std::thread::park_timeout(std::time::Duration::new(0, 50)); }
        Ok(())
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.stop_async().unwrap_or_else(|_| {}); // ignore error - can be stopped already
        // todo : no stable logging for windows?
        trace!(target: "ipc", "IPC Server : shutdown");
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]

use std::vec::Vec;

use raftserver::{Result, ConnData, Sender, TimerMsg};

pub trait ServerHandler :Sized {
    // Handle messages reading from connection with Token.
    // Return some messages for later writing to this connection.
    fn handle_read_data(&mut self,
                        sender: &Sender,
                        msgs: Vec<ConnData>)
                        -> Result<(Vec<ConnData>)> {
        Ok((msgs))
    }

    fn handle_tick(&mut self, sender: &Sender) -> Result<()> {
        Ok(())
    }

    fn handle_timer(&mut self, sender: &Sender, msg: TimerMsg) -> Result<()> {
        Ok(())
    }
}
<commit_msg>raftserver: Address comment.<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]

use std::vec::Vec;

use raftserver::{Result, ConnData, Sender, TimerMsg};

// ServerHandler is for logic, we must implement it for our raft server.
// We use a event loop to handle all events, when an event is triggered,
// event loop will can its associated event handler, after we do something
// in this event handler, we can call server handler for outer logic use.
// The event flow is event loop -> event handler (Server) -> server handler.
// E.g, event loop finds a connection is ready to read, so it calls event handler
// to read data, after the event handler reads whole data, it calls server handler
// for outer use.
pub trait ServerHandler :Sized {
    // Handles messages reading from connection with Token.
    // Returns some messages for later writing to this connection.
    // You can use sender to communicate with event loop.
    fn handle_read_data(&mut self,
                        sender: &Sender,
                        msgs: Vec<ConnData>)
                        -> Result<(Vec<ConnData>)> {
        Ok((msgs))
    }

    // Handles tick.
    fn handle_tick(&mut self, sender: &Sender) -> Result<()> {
        Ok(())
    }

    // Handles customized timer.
    fn handle_timer(&mut self, sender: &Sender, msg: TimerMsg) -> Result<()> {
        Ok(())
    }
}
<|endoftext|>


<commit_before>//! Types and functions related to PG's Sqlite's `ON CONFLICT` clause
//!
//! See [the methods on `InsertStatement`](../../query_builder/struct.InsertStatement.html#impl-1)
//! for usage examples.

mod on_conflict_actions;
mod on_conflict_clause;
mod on_conflict_extension;
mod on_conflict_target;

pub use self::on_conflict_actions::excluded;
pub use self::on_conflict_extension::*;
pub use self::on_conflict_target::on_constraint;
<commit_msg>Fix comment<commit_after>//! Types and functions related to PG's and Sqlite's `ON CONFLICT` clause
//!
//! See [the methods on `InsertStatement`](../../query_builder/struct.InsertStatement.html#impl-1)
//! for usage examples.

mod on_conflict_actions;
mod on_conflict_clause;
mod on_conflict_extension;
mod on_conflict_target;

pub use self::on_conflict_actions::excluded;
pub use self::on_conflict_extension::*;
pub use self::on_conflict_target::on_constraint;
<|endoftext|>


<commit_before>#[cfg(feature = "bigdecimal")]
mod bigdecimal {
    extern crate bigdecimal;
    extern crate num_bigint;
    extern crate num_integer;
    extern crate num_traits;

    use self::bigdecimal::BigDecimal;
    use self::num_bigint::{BigInt, BigUint, Sign};
    use self::num_integer::Integer;
    use self::num_traits::{Signed, ToPrimitive, Zero};
    use std::io::prelude::*;

    use crate::deserialize::{self, FromSql};
    use crate::pg::data_types::PgNumeric;
    use crate::pg::{Pg, PgValue};
    use crate::serialize::{self, Output, ToSql};
    use crate::sql_types::Numeric;

    use std::convert::{TryFrom, TryInto};
    use std::error::Error;

    /// Iterator over the digits of a big uint in base 10k.
    /// The digits will be returned in little endian order.
    struct ToBase10000(Option<BigUint>);

    impl Iterator for ToBase10000 {
        type Item = i16;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().map(|v| {
                let (div, rem) = v.div_rem(&BigUint::from(10_000u16));
                if !div.is_zero() {
                    self.0 = Some(div);
                }
                rem.to_i16().expect("10000 always fits in an i16")
            })
        }
    }

    impl<'a> TryFrom<&'a PgNumeric> for BigDecimal {
        type Error = Box<dyn Error + Send + Sync>;

        fn try_from(numeric: &'a PgNumeric) -> deserialize::Result<Self> {
            let (sign, weight, scale, digits) = match *numeric {
                PgNumeric::Positive {
                    weight,
                    scale,
                    ref digits,
                } => (Sign::Plus, weight, scale, digits),
                PgNumeric::Negative {
                    weight,
                    scale,
                    ref digits,
                } => (Sign::Minus, weight, scale, digits),
                PgNumeric::NaN => {
                    return Err(Box::from("NaN is not (yet) supported in BigDecimal"))
                }
            };

            let mut result = BigUint::default();
            let count = digits.len() as i64;
            for digit in digits {
                result *= BigUint::from(10_000u64);
                result += BigUint::from(*digit as u64);
            }
            // First digit got factor 10_000^(digits.len() - 1), but should get 10_000^weight
            let correction_exp = 4 * (i64::from(weight) - count + 1);
            let result = BigDecimal::new(BigInt::from_biguint(sign, result), -correction_exp)
                .with_scale(i64::from(scale));
            Ok(result)
        }
    }

    impl TryFrom<PgNumeric> for BigDecimal {
        type Error = Box<dyn Error + Send + Sync>;

        fn try_from(numeric: PgNumeric) -> deserialize::Result<Self> {
            (&numeric).try_into()
        }
    }

    impl<'a> From<&'a BigDecimal> for PgNumeric {
        // NOTE(clippy): No `std::ops::MulAssign` impl for `BigInt`
        // NOTE(clippy): Clippy suggests to replace the `.take_while(|i| i.is_zero())`
        // with `.take_while(Zero::is_zero)`, but that's a false positive.
        // The closure gets an `&&i16` due to autoderef `<i16 as Zero>::is_zero(&self) -> bool`
        // is called. There is no impl for `&i16` that would work with this closure.
        #[allow(clippy::assign_op_pattern, clippy::redundant_closure)]
        fn from(decimal: &'a BigDecimal) -> Self {
            let (mut integer, scale) = decimal.as_bigint_and_exponent();
            let scale = scale as u16;
            integer = integer.abs();

            // Ensure that the decimal will always lie on a digit boundary
            for _ in 0..(4 - scale % 4) {
                integer = integer * 10;
            }
            let integer = integer.to_biguint().expect("integer is always positive");

            let mut digits = ToBase10000(Some(integer)).collect::<Vec<_>>();
            digits.reverse();
            let digits_after_decimal = scale as u16 / 4 + 1;
            let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;

            let unnecessary_zeroes = if weight >= 0 {
                let index_of_decimal = (weight + 1) as usize;
                digits
                    .get(index_of_decimal..)
                    .expect("enough digits exist")
                    .iter()
                    .rev()
                    .take_while(|i| i.is_zero())
                    .count()
            } else {
                0
            };

            let relevant_digits = digits.len() - unnecessary_zeroes;
            digits.truncate(relevant_digits);

            match decimal.sign() {
                Sign::Plus => PgNumeric::Positive {
                    digits,
                    scale,
                    weight,
                },
                Sign::Minus => PgNumeric::Negative {
                    digits,
                    scale,
                    weight,
                },
                Sign::NoSign => PgNumeric::Positive {
                    digits: vec![0],
                    scale: 0,
                    weight: 0,
                },
            }
        }
    }

    impl From<BigDecimal> for PgNumeric {
        fn from(bigdecimal: BigDecimal) -> Self {
            (&bigdecimal).into()
        }
    }

    impl ToSql<Numeric, Pg> for BigDecimal {
        fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
            let numeric = PgNumeric::from(self);
            ToSql::<Numeric, Pg>::to_sql(&numeric, out)
        }
    }

    impl FromSql<Numeric, Pg> for BigDecimal {
        fn from_sql(numeric: PgValue<'_>) -> deserialize::Result<Self> {
            PgNumeric::from_sql(numeric)?.try_into()
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;
        use std::str::FromStr;

        #[test]
        fn bigdecimal_to_pgnumeric_converts_digits_to_base_10000() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![10],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10000").unwrap();
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 0],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 0,
                digits: vec![1, 0, 0],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_properly_adjusts_scale() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.0").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 1,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 1,
                digits: vec![1, 1000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.10").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 2,
                digits: vec![1, 1000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000.0001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 4,
                digits: vec![1, 0, 0, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("0.1").unwrap();
            let expected = PgNumeric::Positive {
                weight: -1,
                scale: 1,
                digits: vec![1000],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_retains_sign() {
            let decimal = BigDecimal::from_str("123.456").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("-123.456").unwrap();
            let expected = PgNumeric::Negative {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        #[cfg(feature = "unstable")]
        fn pg_numeric_to_bigdecimal_works() {
            let expected = BigDecimal::from_str("123.456").unwrap();
            let pg_numeric = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            let res: BigDecimal = pg_numeric.try_into().unwrap();
            assert_eq!(res, expected);

            let expected = BigDecimal::from_str("-56.78").unwrap();
            let pg_numeric = PgNumeric::Negative {
                weight: 0,
                scale: 2,
                digits: vec![56, 7800],
            };
            let res: BigDecimal = pg_numeric.try_into().unwrap();
            assert_eq!(res, expected);
        }
    }
}
<commit_msg>Postgres: BigDecimal with negative scale<commit_after>#[cfg(feature = "bigdecimal")]
mod bigdecimal {
    extern crate bigdecimal;
    extern crate num_bigint;
    extern crate num_integer;
    extern crate num_traits;

    use self::bigdecimal::BigDecimal;
    use self::num_bigint::{BigInt, BigUint, Sign};
    use self::num_integer::Integer;
    use self::num_traits::{Signed, ToPrimitive, Zero};
    use std::io::prelude::*;

    use crate::deserialize::{self, FromSql};
    use crate::pg::data_types::PgNumeric;
    use crate::pg::{Pg, PgValue};
    use crate::serialize::{self, Output, ToSql};
    use crate::sql_types::Numeric;

    use std::convert::{TryFrom, TryInto};
    use std::error::Error;

    /// Iterator over the digits of a big uint in base 10k.
    /// The digits will be returned in little endian order.
    struct ToBase10000(Option<BigUint>);

    impl Iterator for ToBase10000 {
        type Item = i16;

        fn next(&mut self) -> Option<Self::Item> {
            self.0.take().map(|v| {
                let (div, rem) = v.div_rem(&BigUint::from(10_000u16));
                if !div.is_zero() {
                    self.0 = Some(div);
                }
                rem.to_i16().expect("10000 always fits in an i16")
            })
        }
    }

    impl<'a> TryFrom<&'a PgNumeric> for BigDecimal {
        type Error = Box<dyn Error + Send + Sync>;

        fn try_from(numeric: &'a PgNumeric) -> deserialize::Result<Self> {
            let (sign, weight, scale, digits) = match *numeric {
                PgNumeric::Positive {
                    weight,
                    scale,
                    ref digits,
                } => (Sign::Plus, weight, scale, digits),
                PgNumeric::Negative {
                    weight,
                    scale,
                    ref digits,
                } => (Sign::Minus, weight, scale, digits),
                PgNumeric::NaN => {
                    return Err(Box::from("NaN is not (yet) supported in BigDecimal"))
                }
            };

            let mut result = BigUint::default();
            let count = digits.len() as i64;
            for digit in digits {
                result *= BigUint::from(10_000u64);
                result += BigUint::from(*digit as u64);
            }
            // First digit got factor 10_000^(digits.len() - 1), but should get 10_000^weight
            let correction_exp = 4 * (i64::from(weight) - count + 1);
            let result = BigDecimal::new(BigInt::from_biguint(sign, result), -correction_exp)
                .with_scale(i64::from(scale));
            Ok(result)
        }
    }

    impl TryFrom<PgNumeric> for BigDecimal {
        type Error = Box<dyn Error + Send + Sync>;

        fn try_from(numeric: PgNumeric) -> deserialize::Result<Self> {
            (&numeric).try_into()
        }
    }

    impl<'a> From<&'a BigDecimal> for PgNumeric {
        // NOTE(clippy): No `std::ops::MulAssign` impl for `BigInt`
        // NOTE(clippy): Clippy suggests to replace the `.take_while(|i| i.is_zero())`
        // with `.take_while(Zero::is_zero)`, but that's a false positive.
        // The closure gets an `&&i16` due to autoderef `<i16 as Zero>::is_zero(&self) -> bool`
        // is called. There is no impl for `&i16` that would work with this closure.
        #[allow(clippy::assign_op_pattern, clippy::redundant_closure)]
        fn from(decimal: &'a BigDecimal) -> Self {
            let (mut integer, scale) = decimal.as_bigint_and_exponent();

            // Handling of negative scale
            let scale = if scale < 0 {
                for _ in 0..(-scale) {
                    integer = integer * 10;
                }
                0
            } else {
                scale as u16
            };

            integer = integer.abs();

            // Ensure that the decimal will always lie on a digit boundary
            for _ in 0..(4 - scale % 4) {
                integer = integer * 10;
            }
            let integer = integer.to_biguint().expect("integer is always positive");

            let mut digits = ToBase10000(Some(integer)).collect::<Vec<_>>();
            digits.reverse();
            let digits_after_decimal = scale / 4 + 1;
            let weight = digits.len() as i16 - digits_after_decimal as i16 - 1;

            let unnecessary_zeroes = if weight >= 0 {
                let index_of_decimal = (weight + 1) as usize;
                digits
                    .get(index_of_decimal..)
                    .expect("enough digits exist")
                    .iter()
                    .rev()
                    .take_while(|i| i.is_zero())
                    .count()
            } else {
                0
            };

            let relevant_digits = digits.len() - unnecessary_zeroes;
            digits.truncate(relevant_digits);

            match decimal.sign() {
                Sign::Plus => PgNumeric::Positive {
                    digits,
                    scale,
                    weight,
                },
                Sign::Minus => PgNumeric::Negative {
                    digits,
                    scale,
                    weight,
                },
                Sign::NoSign => PgNumeric::Positive {
                    digits: vec![0],
                    scale: 0,
                    weight: 0,
                },
            }
        }
    }

    impl From<BigDecimal> for PgNumeric {
        fn from(bigdecimal: BigDecimal) -> Self {
            (&bigdecimal).into()
        }
    }

    impl ToSql<Numeric, Pg> for BigDecimal {
        fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
            let numeric = PgNumeric::from(self);
            ToSql::<Numeric, Pg>::to_sql(&numeric, out)
        }
    }

    impl FromSql<Numeric, Pg> for BigDecimal {
        fn from_sql(numeric: PgValue<'_>) -> deserialize::Result<Self> {
            PgNumeric::from_sql(numeric)?.try_into()
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;
        use std::str::FromStr;

        #[test]
        fn bigdecimal_to_pgnumeric_converts_digits_to_base_10000() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![10],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10000").unwrap();
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 0],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("10001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 0,
                digits: vec![1, 0, 0],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_properly_adjusts_scale() {
            let decimal = BigDecimal::from_str("1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.0").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 1,
                digits: vec![1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.1").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 1,
                digits: vec![1, 1000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("1.10").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 2,
                digits: vec![1, 1000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("100000000.0001").unwrap();
            let expected = PgNumeric::Positive {
                weight: 2,
                scale: 4,
                digits: vec![1, 0, 0, 1],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("0.1").unwrap();
            let expected = PgNumeric::Positive {
                weight: -1,
                scale: 1,
                digits: vec![1000],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_to_pg_numeric_retains_sign() {
            let decimal = BigDecimal::from_str("123.456").unwrap();
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::from_str("-123.456").unwrap();
            let expected = PgNumeric::Negative {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        fn bigdecimal_with_negative_scale_to_pg_numeric_works() {
            let decimal = BigDecimal::new(50.into(), -2);
            let expected = PgNumeric::Positive {
                weight: 0,
                scale: 0,
                digits: vec![5000],
            };
            assert_eq!(expected, decimal.into());

            let decimal = BigDecimal::new(1.into(), -4);
            let expected = PgNumeric::Positive {
                weight: 1,
                scale: 0,
                digits: vec![1, 0],
            };
            assert_eq!(expected, decimal.into());
        }

        #[test]
        #[cfg(feature = "unstable")]
        fn pg_numeric_to_bigdecimal_works() {
            let expected = BigDecimal::from_str("123.456").unwrap();
            let pg_numeric = PgNumeric::Positive {
                weight: 0,
                scale: 3,
                digits: vec![123, 4560],
            };
            let res: BigDecimal = pg_numeric.try_into().unwrap();
            assert_eq!(res, expected);

            let expected = BigDecimal::from_str("-56.78").unwrap();
            let pg_numeric = PgNumeric::Negative {
                weight: 0,
                scale: 2,
                digits: vec![56, 7800],
            };
            let res: BigDecimal = pg_numeric.try_into().unwrap();
            assert_eq!(res, expected);
        }
    }
}
<|endoftext|>


<commit_before>use registers::control::Cr3;
use structures::paging::page_table::{PageTable, PageTableEntry, PageTableFlags};
use structures::paging::{Page, PhysFrame, VirtAddr};
use ux::u9;

pub struct RecursivePageTable<'a> {
    p4: &'a mut PageTable,
    recursive_index: u9,
}

#[derive(Debug)]
pub struct NotRecursivelyMapped;

#[derive(Debug)]
pub enum MapToError {
    FrameAllocationFailed,
    EntryWithInvalidFlagsPresent,
    PageAlreadyInUse,
}

#[derive(Debug)]
pub enum UnmapError {
    EntryWithInvalidFlagsPresent(Page, PageTableEntry),
    PageNotMapped(Page),
}

impl<'a> RecursivePageTable<'a> {
    pub fn new(table: &'a mut PageTable) -> Result<Self, NotRecursivelyMapped> {
        let page = Page::containing_address(VirtAddr::new(table as *const _ as u64));
        let recursive_index = page.p4_index();

        if page.p3_index() != recursive_index || page.p2_index() != recursive_index
            || page.p1_index() != recursive_index
        {
            return Err(NotRecursivelyMapped);
        }
        if Some(Cr3::read().0) != table[recursive_index].frame() {
            return Err(NotRecursivelyMapped);
        }

        Ok(RecursivePageTable {
            p4: table,
            recursive_index,
        })
    }

    pub fn map_to<A>(
        &mut self,
        page: Page,
        frame: PhysFrame,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;
        let p4 = &mut self.p4;

        let mut create_next_table = |entry: &mut PageTableEntry| {
            if entry.is_unused() {
                if let Some(frame) = allocator() {
                    entry.set(frame, Flags::PRESENT | Flags::WRITABLE);
                    return Ok(true);
                } else {
                    return Err(MapToError::FrameAllocationFailed);
                }
            }
            if entry.flags().contains(Flags::HUGE_PAGE) {
                return Err(MapToError::EntryWithInvalidFlagsPresent);
            }
            Ok(false)
        };

        let p3_created = create_next_table(&mut p4[page.p4_index()])?;
        let p3 = unsafe { &mut *(p3_ptr(&page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        let p2_created = create_next_table(&mut p3[page.p3_index()])?;
        let p2 = unsafe { &mut *(p2_ptr(&page, self.recursive_index)) };
        if p2_created {
            p2.zero()
        }

        let p1_created = create_next_table(&mut p2[page.p2_index()])?;
        let p1 = unsafe { &mut *(p1_ptr(&page, self.recursive_index)) };
        if p1_created {
            p1.zero()
        }

        if !p1[page.p1_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p1[page.p1_index()].set(frame, flags);

        Ok(())
    }

    pub fn identity_map<A>(
        &mut self,
        frame: PhysFrame,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64()));
        self.map_to(page, frame, flags, allocator)
    }

    pub fn unmap<A>(&mut self, page: Page, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame),
    {
        use structures::paging::PageTableFlags as Flags;

        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];
        if p4_entry.is_unused() {
            return Err(UnmapError::PageNotMapped(page));
        }
        if p4_entry.flags().contains(Flags::HUGE_PAGE) {
            return Err(UnmapError::EntryWithInvalidFlagsPresent(
                page,
                p4_entry.clone(),
            ));
        }

        let p3 = unsafe { &mut *(p3_ptr(&page, self.recursive_index)) };
        let p3_entry = &p3[page.p3_index()];
        if p3_entry.is_unused() {
            return Err(UnmapError::PageNotMapped(page));
        }
        if p3_entry.flags().contains(Flags::HUGE_PAGE) {
            return Err(UnmapError::EntryWithInvalidFlagsPresent(
                page,
                p3_entry.clone(),
            ));
        }

        let p2 = unsafe { &mut *(p2_ptr(&page, self.recursive_index)) };
        let p2_entry = &mut p2[page.p2_index()];
        if p2_entry.is_unused() {
            return Err(UnmapError::PageNotMapped(page));
        }
        if p2_entry.flags().contains(Flags::PRESENT | Flags::HUGE_PAGE) {
            let frame = match p2_entry.frame() {
                Some(frame) => frame,
                None => {
                    return Err(UnmapError::EntryWithInvalidFlagsPresent(
                        page,
                        p2_entry.clone(),
                    ))
                }
            };
            allocator(frame);
            p2_entry.set_unused();
            return Ok(());
        }

        let p1 = unsafe { &mut *(p1_ptr(&page, self.recursive_index)) };
        let p1_entry = &mut p1[page.p1_index()];
        if p1_entry.is_unused() {
            return Err(UnmapError::PageNotMapped(page));
        }
        if p1_entry.flags().contains(Flags::PRESENT) {
            let frame = match p1_entry.frame() {
                Some(frame) => frame,
                None => {
                    return Err(UnmapError::EntryWithInvalidFlagsPresent(
                        page,
                        p1_entry.clone(),
                    ))
                }
            };
            allocator(frame);
            p1_entry.set_unused();
            return Ok(());
        }
        Err(UnmapError::EntryWithInvalidFlagsPresent(
            page,
            p1_entry.clone(),
        ))
    }
}

fn p3_ptr(page: &Page, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        recursive_index,
        recursive_index,
        page.p4_index(),
    ).start_address()
        .as_mut_ptr()
}

fn p2_ptr(page: &Page, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        recursive_index,
        page.p4_index(),
        page.p3_index(),
    ).start_address()
        .as_mut_ptr()
}

fn p1_ptr(page: &Page, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        page.p4_index(),
        page.p3_index(),
        page.p2_index(),
    ).start_address()
        .as_mut_ptr()
}
<commit_msg>Reimplement recursive paging module with huge page support<commit_after>use registers::control::Cr3;
use structures::paging::page_table::{PageTable, PageTableEntry, PageTableFlags, FrameError};
use structures::paging::{Page, PhysFrame, PageSize, NotGiantPageSize, Size4KB, Size2MB, Size1GB};
use VirtAddr;
use ux::u9;

pub trait Mapper<S: PageSize> {
    fn map_to<A>(
        &mut self,
        page: Page<S>,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>;

    fn unmap<A>(&mut self, page: Page<S>, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame<S>);
}

pub struct RecursivePageTable<'a> {
    p4: &'a mut PageTable,
    recursive_index: u9,
}

#[derive(Debug)]
pub struct NotRecursivelyMapped;

#[derive(Debug)]
pub enum MapToError {
    FrameAllocationFailed,
    EntryWithInvalidFlagsPresent,
    PageAlreadyInUse,
}

#[derive(Debug)]
pub enum UnmapError {
    EntryWithInvalidFlagsPresent(PageTableFlags),
    PageNotMapped,
    InvalidFrameAddressInPageTable,
}

impl<'a> RecursivePageTable<'a> {
    pub fn new(table: &'a mut PageTable) -> Result<Self, NotRecursivelyMapped> {
        let page = Page::containing_address(VirtAddr::new(table as *const _ as u64));
        let recursive_index = page.p4_index();

        if page.p3_index() != recursive_index || page.p2_index() != recursive_index
            || page.p1_index() != recursive_index
        {
            return Err(NotRecursivelyMapped);
        }
        if Ok(Cr3::read().0) != table[recursive_index].frame() {
            return Err(NotRecursivelyMapped);
        }

        Ok(RecursivePageTable {
            p4: table,
            recursive_index,
        })
    }

    pub fn identity_map<A, S> (
        &mut self,
        frame: PhysFrame<S>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
        S: PageSize,
        Self: Mapper<S>,
    {
        let page = Page::containing_address(VirtAddr::new(frame.start_address().as_u64()));
        self.map_to(page, frame, flags, allocator)
    }

    fn create_next_table<A>(entry: &mut PageTableEntry, allocator: &mut A) -> Result<bool, MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;

        if entry.is_unused() {
            if let Some(frame) = allocator() {
                entry.set_frame(frame, Flags::PRESENT | Flags::WRITABLE);
                return Ok(true);
            } else {
                return Err(MapToError::FrameAllocationFailed);
            }
        }
        if entry.flags().contains(Flags::HUGE_PAGE) {
            return Err(MapToError::EntryWithInvalidFlagsPresent);
        }
        Ok(false)
    }
}

impl<'a> Mapper<Size1GB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size1GB>,
        frame: PhysFrame<Size1GB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        if !p3[page.p3_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p3[page.p3_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE);

        Ok(())
    }

    fn unmap<A>(&mut self, page: Page<Size1GB>, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame<Size1GB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];

        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &mut p3[page.p3_index()];
        let flags = p3_entry.flags();

        if !flags.contains(PageTableFlags::PRESENT) {
            return Err(UnmapError::PageNotMapped);
        }
        if !flags.contains(PageTableFlags::HUGE_PAGE) {
            return Err(UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()));
        }

        let frame = PhysFrame::from_start_address(p3_entry.addr()).map_err(|()| {
            UnmapError::InvalidFrameAddressInPageTable
        })?;
        allocator(frame);
        p3_entry.set_unused();
        Ok(())
    }
}

impl<'a> Mapper<Size2MB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size2MB>,
        frame: PhysFrame<Size2MB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        use structures::paging::PageTableFlags as Flags;
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        let p2_created = Self::create_next_table(&mut p3[page.p3_index()], allocator)?;
        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        if p2_created {
            p2.zero()
        }

        if !p2[page.p2_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p2[page.p2_index()].set_addr(frame.start_address(), flags | Flags::HUGE_PAGE);

        Ok(())
    }

    fn unmap<A>(&mut self, page: Page<Size2MB>, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame<Size2MB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];
        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &p3[page.p3_index()];
        p3_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        let p2_entry = &mut p2[page.p2_index()];
        let flags = p2_entry.flags();

        if !flags.contains(PageTableFlags::PRESENT) {
            return Err(UnmapError::PageNotMapped);
        }
        if !flags.contains(PageTableFlags::HUGE_PAGE) {
            return Err(UnmapError::EntryWithInvalidFlagsPresent(p2_entry.flags()));
        }

        let frame = PhysFrame::from_start_address(p2_entry.addr()).map_err(|()| {
            UnmapError::InvalidFrameAddressInPageTable
        })?;
        allocator(frame);
        p2_entry.set_unused();
        Ok(())
    }
}

impl<'a> Mapper<Size4KB> for RecursivePageTable<'a> {
    fn map_to<A>(
        &mut self,
        page: Page<Size4KB>,
        frame: PhysFrame<Size4KB>,
        flags: PageTableFlags,
        allocator: &mut A,
    ) -> Result<(), MapToError>
    where
        A: FnMut() -> Option<PhysFrame>,
    {
        let p4 = &mut self.p4;

        let p3_created = Self::create_next_table(&mut p4[page.p4_index()], allocator)?;
        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        if p3_created {
            p3.zero()
        }

        let p2_created = Self::create_next_table(&mut p3[page.p3_index()], allocator)?;
        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        if p2_created {
            p2.zero()
        }

        let p1_created = Self::create_next_table(&mut p2[page.p2_index()], allocator)?;
        let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) };
        if p1_created {
            p1.zero()
        }

        if !p1[page.p1_index()].is_unused() {
            return Err(MapToError::PageAlreadyInUse);
        }
        p1[page.p1_index()].set_frame(frame, flags);

        Ok(())
    }

    fn unmap<A>(&mut self, page: Page<Size4KB>, allocator: &mut A) -> Result<(), UnmapError>
    where
        A: FnMut(PhysFrame<Size4KB>),
    {
        let p4 = &mut self.p4;
        let p4_entry = &p4[page.p4_index()];
        p4_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p4_entry.flags()),
        })?;

        let p3 = unsafe { &mut *(p3_ptr(page, self.recursive_index)) };
        let p3_entry = &p3[page.p3_index()];
        p3_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p2 = unsafe { &mut *(p2_ptr(page, self.recursive_index)) };
        let p2_entry = &p2[page.p2_index()];
        p2_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;

        let p1 = unsafe { &mut *(p1_ptr(page, self.recursive_index)) };
        let p1_entry = &mut p1[page.p1_index()];

        let frame = p1_entry.frame().map_err(|err| match err {
            FrameError::FrameNotPresent => UnmapError::PageNotMapped,
            FrameError::HugeFrame => UnmapError::EntryWithInvalidFlagsPresent(p3_entry.flags()),
        })?;
        allocator(frame);
        p1_entry.set_unused();
        Ok(())
    }
}

fn p3_ptr<S: PageSize>(page: Page<S>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        recursive_index,
        recursive_index,
        page.p4_index(),
    ).start_address()
        .as_mut_ptr()
}

fn p2_ptr<S: NotGiantPageSize>(page: Page<S>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        recursive_index,
        page.p4_index(),
        page.p3_index(),
    ).start_address()
        .as_mut_ptr()
}

fn p1_ptr(page: Page<Size4KB>, recursive_index: u9) -> *mut PageTable {
    Page::from_page_table_indices(
        recursive_index,
        page.p4_index(),
        page.p3_index(),
        page.p2_index(),
    ).start_address()
        .as_mut_ptr()
}
<|endoftext|>


<commit_before>/*
 * Copyright 2019 Sanguk Park
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use core::mem::MaybeUninit;
use core::ptr;
use core::sync::atomic::{AtomicBool, Ordering};

use crate::addr::*;
use crate::arch::*;
use crate::boot_params::*;
use crate::cpu::*;
use crate::load::*;
use crate::memiter::*;
use crate::mm::*;
use crate::mpool::*;
use crate::page::*;
use crate::types::*;
use crate::vm::*;

extern "C" {
    fn plat_console_init();
    fn arch_one_time_init();
    fn dlog_enable_lock();

    /// The stack to be used by the CPUs.
    static callstacks: [[u8; STACK_SIZE]; MAX_CPUS];

    /// A record for boot CPU. Its field `stack_bottom` is initialized.
    /// Hafnium loader writes booted CPU ID on `cpus.id` and initializes the CPU
    /// stack by the address in `cpus.stack_bottom`.
    /// (See src/arch/aarch64/hypervisor/plat_entry.S and cpu_entry.S.)
    ///
    /// Initializing static variables with pointers in Rust failed here. We left
    /// the initialization code of `cpus` in `src/cpu.c`.
    static boot_cpu: Cpu;
}

/// TODO(HfO2): Refactor api.rs and remove `pub` (#44.)
pub struct Hypervisor {
    pub mpool: MPool,
    pub memory_manager: MemoryManager,
    pub cpu_manager: CpuManager,
    pub vm_manager: VmManager,
}

/// Note(HfO2): this variable was originally of type
/// MaybeUninit<[u8; mem::size_of::<RawPageTable>() * HEAP_PAGES]>,
/// but it was not aligned to PAGE_SIZE.
static mut PTABLE_BUF: MaybeUninit<[RawPage; HEAP_PAGES]> = MaybeUninit::uninit();

static INITED: AtomicBool = AtomicBool::new(false);

/// A singleton collecting all managers in Hafnium.
///
/// This is dependency-free; Typical solutions of mutable and shared static
/// objects delay their initialization. Considering concurrency, they often use
/// std::sync features to prevent racy initialization. But Hafnium is different.
///
///  - The initialization is _always_ happened once in the specific time.
///  - During the time, no other thread is running; Hafnium runs as if it were
///    a single-thread program.
///  - After the initialization, Hafnium may make a non-exclusive reference of
///    singletons, but they have their own way for Hafnium to safely write them.
///
/// Therefore, I do not use a safe wrapper for initialization such as
/// `std::sync::Once` and `lazy_static`.
///
/// TODO(HfO2): This `pub` is required by mm_init, which is only used by unit
/// tests. Resolving #46 may help to remove the `pub`.
pub static mut HAFNIUM: MaybeUninit<Hypervisor> = MaybeUninit::uninit();

/// Performs one-time initialisation of the hypervisor.
#[no_mangle]
unsafe extern "C" fn one_time_init(c: *mut Cpu) -> *mut Cpu {
    if INITED.load(Ordering::Acquire) {
        return c;
    }

    // Make sure the console is initialised before calling dlog.
    plat_console_init();

    dlog!("Initialising hafnium\n");

    arch_one_time_init();
    arch_cpu_module_init();

    let mut ppool = MPool::new();
    ppool.free_pages(Pages::from_raw(
        PTABLE_BUF.get_mut().as_mut_ptr(),
        HEAP_PAGES,
    ));

    let mm = MemoryManager::new(&ppool).expect("mm_init failed");

    // We have to initialize memory manager early, because
    // Stage2::invalidate_tlb refers global state. TODO(HfO2): Refactor the
    // function to recieve the info from caller. Maybe MemoryManager should
    // have a wrapper function for page table.
    ptr::write(&mut HAFNIUM.get_mut().memory_manager, mm);
    let mm = &HAFNIUM.get_ref().memory_manager;

    // Enable locks now that mm is initialised.
    dlog_enable_lock();
    mpool_enable_locks();

    let mut hypervisor_ptable = mm.hypervisor_ptable.lock();

    let params = boot_params_get(&mut hypervisor_ptable, &mut ppool)
        .expect("unable to retrieve boot params");

    let cpum = CpuManager::new(
        &params.cpu_ids[..params.cpu_count],
        boot_cpu.id,
        &callstacks,
    );

    for i in 0..params.mem_ranges_count {
        dlog!(
            "Memory range: 0x{:x} - 0x{:x}\n",
            pa_addr(params.mem_ranges[i].begin),
            pa_addr(params.mem_ranges[i].end) - 1
        );
    }

    dlog!(
        "Ramdisk range: 0x{:x} - 0x{:x}\n",
        pa_addr(params.initrd_begin),
        pa_addr(params.initrd_end) - 1
    );

    // Map initrd in, and initialise cpio parser.
    hypervisor_ptable
        .identity_map(params.initrd_begin, params.initrd_end, Mode::R, &ppool)
        .expect("unable to map initrd in");

    let initrd = pa_addr(params.initrd_begin) as *mut _;
    let cpio = MemIter::from_raw(
        initrd,
        pa_difference(params.initrd_begin, params.initrd_end),
    );

    ptr::write(&mut HAFNIUM.get_mut().vm_manager, VmManager::new());

    // Load all VMs.
    let primary_initrd = load_primary(
        &mut HAFNIUM.get_mut().vm_manager,
        &mut hypervisor_ptable,
        &cpio,
        params.kernel_arg,
        &ppool,
    )
    .expect("unable to load primary VM");

    // load_secondary will add regions assigned to the secondary VMs from
    // mem_ranges to reserved_ranges.
    let mut update: BootParamsUpdate = BootParamsUpdate::new(
        pa_from_va(va_from_ptr(primary_initrd.get_next() as usize as *const _)),
        pa_from_va(va_from_ptr(primary_initrd.get_limit() as usize as *const _)),
    );

    load_secondary(
        &mut HAFNIUM.get_mut().vm_manager,
        &mut hypervisor_ptable,
        &cpio,
        &params,
        &mut update,
        &mut ppool,
    )
    .expect("unable to load secondary VMs");

    // Prepare to run by updating bootparams as seen by primary VM.
    boot_params_update(&mut hypervisor_ptable, &mut update, &mut ppool)
        .expect("plat_update_boot_params failed");

    hypervisor_ptable.defrag(&ppool);

    // Initialise HAFNIUM.
    ptr::write(&mut HAFNIUM.get_mut().mpool, ppool);
    ptr::write(&mut HAFNIUM.get_mut().cpu_manager, cpum);

    // Enable TLB invalidation for VM page table updates.
    mm_vm_enable_invalidation();

    dlog!("Hafnium initialisation completed\n");
    INITED.store(true, Ordering::Release);

    hafnium().cpu_manager.boot_cpu()

    // From now on, other pCPUs are on in order to run multiple vCPUs. Thus
    // you may safely make readonly references to the Hafnium singleton, but
    // may not modify the singleton without proper locking.
}

pub fn hafnium() -> &'static Hypervisor {
    unsafe { HAFNIUM.get_ref() }
}

// The entry point of CPUs when they are turned on. It is supposed to initialise
// all state and return the first vCPU to run.
#[no_mangle]
pub unsafe extern "C" fn cpu_main(c: *const Cpu) -> *mut VCpu {
    if !mm_cpu_init() {
        panic!("mm_cpu_init failed");
    }

    let primary = hafnium().vm_manager.get(HF_PRIMARY_VM_ID).unwrap();
    let vcpu = primary.vcpus.get(cpu_index(&*c)).unwrap();
    let vm = vcpu.vm;

    // TODO(HfO2): vcpu needs to be borrowed exclusively, which is safe but
    // discouraged. Move this code into one_time_init().
    let vcpu = vcpu as *const _ as usize as *mut VCpu;
    (*vcpu).set_cpu(c);

    // Reset the registers to give a clean start for the primary's vCPU.
    (*vcpu).inner.get_mut().regs.reset(true, &*vm, (*c).id);

    vcpu
}
<commit_msg>Revert a12d91d but check INITED only on boot CPU. Closes #55.<commit_after>/*
 * Copyright 2019 Sanguk Park
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use core::mem::MaybeUninit;
use core::ptr;
use core::sync::atomic::{AtomicBool, Ordering};

use crate::addr::*;
use crate::arch::*;
use crate::boot_params::*;
use crate::cpu::*;
use crate::load::*;
use crate::memiter::*;
use crate::mm::*;
use crate::mpool::*;
use crate::page::*;
use crate::types::*;
use crate::vm::*;

extern "C" {
    fn plat_console_init();
    fn arch_one_time_init();
    fn dlog_enable_lock();

    /// The stack to be used by the CPUs.
    static callstacks: [[u8; STACK_SIZE]; MAX_CPUS];

    /// A record for boot CPU. Its field `stack_bottom` is initialized.
    /// Hafnium loader writes booted CPU ID on `cpus.id` and initializes the CPU
    /// stack by the address in `cpus.stack_bottom`.
    /// (See src/arch/aarch64/hypervisor/plat_entry.S and cpu_entry.S.)
    ///
    /// Initializing static variables with pointers in Rust failed here. We left
    /// the initialization code of `cpus` in `src/cpu.c`.
    static boot_cpu: Cpu;
}

/// TODO(HfO2): Refactor api.rs and remove `pub` (#44.)
pub struct Hypervisor {
    pub mpool: MPool,
    pub memory_manager: MemoryManager,
    pub cpu_manager: CpuManager,
    pub vm_manager: VmManager,
}

/// Note(HfO2): this variable was originally of type
/// MaybeUninit<[u8; mem::size_of::<RawPageTable>() * HEAP_PAGES]>,
/// but it was not aligned to PAGE_SIZE.
static mut PTABLE_BUF: MaybeUninit<[RawPage; HEAP_PAGES]> = MaybeUninit::uninit();

/// A variable that stores if Hafnium is initialized. This is only read by boot
/// CPU, so its type is not `AtomicBool`.
static mut INITED: bool = false;

/// A singleton collecting all managers in Hafnium.
///
/// This is dependency-free; Typical solutions of mutable and shared static
/// objects delay their initialization. Considering concurrency, they often use
/// std::sync features to prevent racy initialization. But Hafnium is different.
///
///  - The initialization is _always_ happened once in the specific time.
///  - During the time, no other thread is running; Hafnium runs as if it were
///    a single-thread program.
///  - After the initialization, Hafnium may make a non-exclusive reference of
///    singletons, but they have their own way for Hafnium to safely write them.
///
/// Therefore, I do not use a safe wrapper for initialization such as
/// `std::sync::Once` and `lazy_static`.
///
/// TODO(HfO2): This `pub` is required by mm_init, which is only used by unit
/// tests. Resolving #46 may help to remove the `pub`.
pub static mut HAFNIUM: MaybeUninit<Hypervisor> = MaybeUninit::uninit();

/// Performs one-time initialisation of the hypervisor.
#[no_mangle]
unsafe extern "C" fn one_time_init(c: *const Cpu) -> *const Cpu {
    if &boot_cpu as *const _ != c || INITED {
        return c;
    }

    // Make sure the console is initialised before calling dlog.
    plat_console_init();

    dlog!("Initialising hafnium\n");

    arch_one_time_init();
    arch_cpu_module_init();

    let mut ppool = MPool::new();
    ppool.free_pages(Pages::from_raw(
        PTABLE_BUF.get_mut().as_mut_ptr(),
        HEAP_PAGES,
    ));

    let mm = MemoryManager::new(&ppool).expect("mm_init failed");

    // We have to initialize memory manager early, because
    // Stage2::invalidate_tlb refers global state. TODO(HfO2): Refactor the
    // function to recieve the info from caller. Maybe MemoryManager should
    // have a wrapper function for page table.
    ptr::write(&mut HAFNIUM.get_mut().memory_manager, mm);
    let mm = &HAFNIUM.get_ref().memory_manager;

    // Enable locks now that mm is initialised.
    dlog_enable_lock();
    mpool_enable_locks();

    let mut hypervisor_ptable = mm.hypervisor_ptable.lock();

    let params = boot_params_get(&mut hypervisor_ptable, &mut ppool)
        .expect("unable to retrieve boot params");

    let cpum = CpuManager::new(
        &params.cpu_ids[..params.cpu_count],
        boot_cpu.id,
        &callstacks,
    );

    for i in 0..params.mem_ranges_count {
        dlog!(
            "Memory range: 0x{:x} - 0x{:x}\n",
            pa_addr(params.mem_ranges[i].begin),
            pa_addr(params.mem_ranges[i].end) - 1
        );
    }

    dlog!(
        "Ramdisk range: 0x{:x} - 0x{:x}\n",
        pa_addr(params.initrd_begin),
        pa_addr(params.initrd_end) - 1
    );

    // Map initrd in, and initialise cpio parser.
    hypervisor_ptable
        .identity_map(params.initrd_begin, params.initrd_end, Mode::R, &ppool)
        .expect("unable to map initrd in");

    let initrd = pa_addr(params.initrd_begin) as *mut _;
    let cpio = MemIter::from_raw(
        initrd,
        pa_difference(params.initrd_begin, params.initrd_end),
    );

    ptr::write(&mut HAFNIUM.get_mut().vm_manager, VmManager::new());

    // Load all VMs.
    let primary_initrd = load_primary(
        &mut HAFNIUM.get_mut().vm_manager,
        &mut hypervisor_ptable,
        &cpio,
        params.kernel_arg,
        &ppool,
    )
    .expect("unable to load primary VM");

    // load_secondary will add regions assigned to the secondary VMs from
    // mem_ranges to reserved_ranges.
    let mut update: BootParamsUpdate = BootParamsUpdate::new(
        pa_from_va(va_from_ptr(primary_initrd.get_next() as usize as *const _)),
        pa_from_va(va_from_ptr(primary_initrd.get_limit() as usize as *const _)),
    );

    load_secondary(
        &mut HAFNIUM.get_mut().vm_manager,
        &mut hypervisor_ptable,
        &cpio,
        &params,
        &mut update,
        &mut ppool,
    )
    .expect("unable to load secondary VMs");

    // Prepare to run by updating bootparams as seen by primary VM.
    boot_params_update(&mut hypervisor_ptable, &mut update, &mut ppool)
        .expect("plat_update_boot_params failed");

    hypervisor_ptable.defrag(&ppool);

    // Initialise HAFNIUM.
    ptr::write(&mut HAFNIUM.get_mut().mpool, ppool);
    ptr::write(&mut HAFNIUM.get_mut().cpu_manager, cpum);

    // Enable TLB invalidation for VM page table updates.
    mm_vm_enable_invalidation();

    dlog!("Hafnium initialisation completed\n");
    INITED = true;

    hafnium().cpu_manager.boot_cpu()

    // From now on, other pCPUs are on in order to run multiple vCPUs. Thus
    // you may safely make readonly references to the Hafnium singleton, but
    // may not modify the singleton without proper locking.
}

pub fn hafnium() -> &'static Hypervisor {
    unsafe { HAFNIUM.get_ref() }
}

// The entry point of CPUs when they are turned on. It is supposed to initialise
// all state and return the first vCPU to run.
#[no_mangle]
pub unsafe extern "C" fn cpu_main(c: *const Cpu) -> *mut VCpu {
    if !mm_cpu_init() {
        panic!("mm_cpu_init failed");
    }

    let primary = hafnium().vm_manager.get(HF_PRIMARY_VM_ID).unwrap();
    let vcpu = primary.vcpus.get(cpu_index(&*c)).unwrap();
    let vm = vcpu.vm;

    // TODO(HfO2): vcpu needs to be borrowed exclusively, which is safe but
    // discouraged. Move this code into one_time_init().
    let vcpu = vcpu as *const _ as usize as *mut VCpu;
    (*vcpu).set_cpu(c);

    // Reset the registers to give a clean start for the primary's vCPU.
    (*vcpu).inner.get_mut().regs.reset(true, &*vm, (*c).id);

    vcpu
}
<|endoftext|>