<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/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::thread;
use std::thread::JoinHandle;
use std::net::TcpStream;
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver,
    TryRecvError
};

use super::types::*;
use super::epoll;
use super::epoll::util::*;
use super::epoll::EpollEvent;
use super::socket::Socket;
use super::simple_stream::nbetstream::NbetStream;

#[allow(dead_code)]
pub struct EventLoop {
    /// Handle to event loop process
    prox: JoinHandle<()>,
    /// Sender<T> to proc
    prox_tx: Sender<TcpStream>
}

impl EventLoop {

    /// Returns a new EventLoop
    pub fn new(server_tx: Sender<EventTuple>) -> EventLoop {
        let (tx, rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
        let prox = thread::Builder::new()
            .name("EventLoop".to_string())
            .spawn(move || {
                EventLoop::start(rx, server_tx);
            }).unwrap();

        EventLoop {
            prox: prox,
            prox_tx: tx
        }
    }

    /// Returns a clone of this EventLoop's Sender<TcpStream> channel
    pub fn sender(&self) -> Sender<TcpStream> {
        self.prox_tx.clone()
    }

    /// Main event loop
    fn start(rx: Receiver<TcpStream>, uspace_tx: Sender<EventTuple>) {
        // Master socket list
        let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

        // Our error handler for this thread and it's children
        let (err_tx, err_rx): (Sender<()>, Receiver<()>) = channel();

        // Create an epoll instance
        let result = epoll::create1(0);
        if result.is_err() {
            let err = result.unwrap_err();
            panic!("Unable to create epoll instance: {}", err)
        }
        let epoll_instance = result.unwrap();

        // Start the epoll thread
        let c_sockets = sockets.clone();
        let c_epoll_instance = epoll_instance.clone();
        let epoll_prox = thread::Builder::new()
            .name("EpollLoop".to_string())
            .spawn(move || {
                EventLoop::epoll_loop(uspace_tx, c_sockets, c_epoll_instance, err_rx);
            }).unwrap();

        for new_stream in rx.iter() {
            match NbetStream::new(new_stream) {
                Ok(s_stream) => {
                    // Add to master list
                    let socket = Socket::new(s_stream);

                    // TODO - Replace with recoverable version once into_inner() is stable
                    // Unfortunately, this is the only stable way to use mutexes at the moment
                    // Hopefully recovering from poisoning will be in 1.2
                    // let mut s_guard = match sockets.lock() {
                    //     Ok(guard) => guard,
                    //     Err(poisoned) => poisoned.into_inner()
                    // };
                    let mut s_guard = sockets.lock().unwrap();
                    let s_list = s_guard.deref_mut();
                    let s_fd = socket.raw_fd();
                    s_list.push_back(socket);

                    // Add to epoll
                    let event = Box::new(EpollEvent {
                        data: s_fd as u64,
                        events: (event_type::EPOLLIN | event_type::EPOLLET)
                    });
                    match epoll::ctl(epoll_instance, ctl_op::ADD, s_fd, event) {
                        Ok(()) => println!("New socket added to epoll list"),
                        Err(e) => println!("Epoll CtrlError during add: {}", e)
                    };
                }
                Err(e) => {
                    // TODO - write error to log file
                    println!("Error: {}", e);
                }
            };
        }

        // If we get here, shit is real bad. It means we have lost our
        // channel to the outside world.
        // Kill off event loop, so unwinding can begin
        println!("Rust.EventLoop.start - thread finished");
        let _ = err_tx.send(());
    }

    /// Calls epoll_wait forever waiting for events to be fired up from kernel
    fn epoll_loop(uspace_tx: Sender<EventTuple>,
                  sockets: SocketList,
                  epoll_instance: RawFd,
                  err_rx: Receiver<()>) {

        // This is the maximum number of events we want to be notified of at one time
        let mut events = Vec::<EpollEvent>::with_capacity(100);
        unsafe { events.set_len(100); }

        loop {
            // Wait for epoll events
            match epoll::wait(epoll_instance, &mut events[..], -1) {
                Ok(num_events) => {
                    println!("{} epoll event(s) received", num_events);
                    for x in 0..num_events {
                        let tx_clone = uspace_tx.clone();
                        let s_clone = sockets.clone();
                        let epfd_clone = epoll_instance.clone();

                        EventLoop::handle_epoll_event(epfd_clone,
                            &events[x as usize], s_clone, tx_clone);
                    }
                }
                Err(e) => {
                    panic!("Error on epoll::wait(): {}", e)
                }
            }

            // If we receive anything on this end or lose communication, we need to halt,
            // because we have no where to send up events, our "user space" channel is
            // gone
            match err_rx.try_recv() {
                Ok(_) => {
                    println!("Error, terminating epoll_loop");
                    break;
                }
                Err(e) => {
                    match e {
                        TryRecvError::Empty => {}
                        _ => {
                            println!("Error, terminating epoll_loo");
                            break;
                        }
                    }
                }
            }
        }
        println!("Rust.EventLoop.epoll_loop - thread finished");
    }

    /// Processes a read on the socket that is ready for reading
    ///
    /// An epoll event is passed to this function, with the fd that is ready to be read
    /// A traversal through the list of sockets is then performed in order to locate the
    /// NbetStream instance that is wrapping that file descriptor.
    /// After a read is performed on that socket, it's data will be passed back to the
    /// "user-space" section of the Server to process the payload however it needs to.
    ///
    /// TODO - Create a faster way to gain a safe reference to the NbetStream wrapping
    /// the fd instead of an O(n) lookup for every event. Currently lookup time is
    /// O(n) * MAX_EPOLL_EVENTS, where MAX_EPOLL_EVENTS is user defined in this function's
    /// caller.
    fn handle_epoll_event(epoll_instance: RawFd,
                          event: &EpollEvent,
                          sockets: SocketList,
                          uspace_tx: Sender<EventTuple>) {

        println!("Rust.EventLoop.handle_epoll_event");

        // The fd we are traversing the list for
        let fd = event.data;

        // We need a handle before the list gets locked and used
        let s_list_clone = sockets.clone();

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();
        for socket in s_list.iter_mut() {
            if socket.raw_fd() as u64 == fd {
                // We've found the socket for the event passed from epoll
                // Lets attempt to read from it
                match socket.read() {
                    Ok(()) => {
                        println!("Rust.EventLoop.handle_epoll_event.socket.read.Ok()");
                        for msg in socket.buffer().iter() {
                            let msg_for_debug = msg.clone();
                            match String::from_utf8(msg_for_debug) {
                                Ok(msg_str) => {
                                    println!("Rust.EventLoop.handle_epoll_event.socket.read.ok.msg_as_string: {}", msg_str);
                                }
                                Err(e) => {
                                    println!("Rust.EventLoop.handle_epoll_event.socket.read.ok.msg_as_string.Err: {}", e);
                                }
                            };

                            let list_handle = s_list_clone.clone();
                            let socket_clone = socket.clone();
                            let msg_clone = msg.clone();
                            let _ = uspace_tx.send((list_handle, socket_clone, msg_clone));
                        }
                    }
                    Err(e) => {
                        println!("Rust.EventLoop.handle_epoll_event.socket.read.Err(e): {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_clone = socket.clone();
                        let epfd_clone = epoll_instance.clone();
                        EventLoop::remove_socket_from_epoll(s_clone, epfd_clone);

                        let s_id = socket.id();
                        let list_clone = s_list_clone.clone();
                        EventLoop::remove_socket_from_list(s_id, list_clone);
                    }
                }
            }
        }
    }

    /// Removes socket from the epoll watch list
    fn remove_socket_from_epoll(socket: Socket, epoll_instance: RawFd) {
        println!("remove_socket_from_epoll");

        // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
        // a non-null pointer in event, even though this argument is ignored.
        // Since Linux 2.6.9, event can be specified as NULL when using
        // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
        // before 2.6.9 should specify a non-null pointer in event.
        let event = Box::new(EpollEvent {
            data: 0 as u64,
            events: 0 as u32
        });
        let s_fd = socket.raw_fd();

        // Depending on how fd are duplicated with .clone(), this may fail
        // If the failure case is CtlError::ENOENT, we do not care, because
        // epoll will clean the up the descriptor after they are all dropped from
        // program memory
        match epoll::ctl(epoll_instance, ctl_op::DEL, s_fd, event) {
            Ok(()) => println!("Socket removed from epoll watch list"),
            Err(e) => {
                match e {
                    CtlError::ENOENT => {
                        println!("Fd not found in epoll, will remove when fd is syscall closed");
                    }
                    _ => println!("Epoll CtrlError during del: {}", e)
                }
            }
        };
    }

    /// Removes socket from master list
    fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
        println!("remove_socket_from_list");

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();

        let mut socket_found = false;
        let mut index: usize = 1;
        for socket in s_list.iter() {
            if socket.id() == socket_id {
                socket_found = true;
                break;
            }
            index += 1;
        }

        if !socket_found {
            println!("Socket not found in list...?");
            return;
        }

        if index == 1 {
            s_list.pop_front();
        } else {
            let mut split = s_list.split_off(index - 1);
            split.pop_front();
            s_list.append(&mut split);
        }

        println!("Socket removed sucessfully");
    }
}
<commit_msg>Removed eternal spinlock<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/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::thread;
use std::thread::JoinHandle;
use std::net::TcpStream;
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver,
    TryRecvError
};

use super::types::*;
use super::epoll;
use super::epoll::util::*;
use super::epoll::EpollEvent;
use super::socket::Socket;
use super::simple_stream::nbetstream::NbetStream;

#[allow(dead_code)]
pub struct EventLoop {
    /// Handle to event loop process
    prox: JoinHandle<()>,
    /// Sender<T> to proc
    prox_tx: Sender<TcpStream>
}

impl EventLoop {

    /// Returns a new EventLoop
    pub fn new(server_tx: Sender<EventTuple>) -> EventLoop {
        let (tx, rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
        let prox = thread::Builder::new()
            .name("EventLoop".to_string())
            .spawn(move || {
                EventLoop::start(rx, server_tx);
            }).unwrap();

        EventLoop {
            prox: prox,
            prox_tx: tx
        }
    }

    /// Returns a clone of this EventLoop's Sender<TcpStream> channel
    pub fn sender(&self) -> Sender<TcpStream> {
        self.prox_tx.clone()
    }

    /// Main event loop
    fn start(rx: Receiver<TcpStream>, uspace_tx: Sender<EventTuple>) {
        // Master socket list
        let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

        // Our error handler for this thread and it's children
        let (err_tx, err_rx): (Sender<()>, Receiver<()>) = channel();

        // Create an epoll instance
        let result = epoll::create1(0);
        if result.is_err() {
            let err = result.unwrap_err();
            panic!("Unable to create epoll instance: {}", err)
        }
        let epoll_instance = result.unwrap();

        // Start the epoll thread
        let c_sockets = sockets.clone();
        let c_epoll_instance = epoll_instance.clone();
        let epoll_prox = thread::Builder::new()
            .name("EpollLoop".to_string())
            .spawn(move || {
                EventLoop::epoll_loop(uspace_tx, c_sockets, c_epoll_instance, err_rx);
            }).unwrap();

        for new_stream in rx.iter() {
            match NbetStream::new(new_stream) {
                Ok(s_stream) => {
                    // Add to master list
                    let socket = Socket::new(s_stream);

                    // TODO - Replace with recoverable version once into_inner() is stable
                    // Unfortunately, this is the only stable way to use mutexes at the moment
                    // Hopefully recovering from poisoning will be in 1.2
                    // let mut s_guard = match sockets.lock() {
                    //     Ok(guard) => guard,
                    //     Err(poisoned) => poisoned.into_inner()
                    // };
                    let mut s_guard = sockets.lock().unwrap();
                    let s_list = s_guard.deref_mut();
                    let s_fd = socket.raw_fd();
                    s_list.push_back(socket);

                    // Add to epoll
                    let event = Box::new(EpollEvent {
                        data: s_fd as u64,
                        events: (event_type::EPOLLIN | event_type::EPOLLET)
                    });
                    match epoll::ctl(epoll_instance, ctl_op::ADD, s_fd, event) {
                        Ok(()) => println!("New socket added to epoll list"),
                        Err(e) => println!("Epoll CtrlError during add: {}", e)
                    };
                }
                Err(e) => {
                    // TODO - write error to log file
                    println!("Error: {}", e);
                }
            };
        }

        // If we get here, shit is real bad. It means we have lost our
        // channel to the outside world.
        // Kill off event loop, so unwinding can begin
        println!("Rust.EventLoop.start - thread finished");
        let _ = err_tx.send(());
    }

    /// Calls epoll_wait forever waiting for events to be fired up from kernel
    fn epoll_loop(uspace_tx: Sender<EventTuple>,
                  sockets: SocketList,
                  epoll_instance: RawFd,
                  err_rx: Receiver<()>) {

        // This is the maximum number of events we want to be notified of at one time
        let mut events = Vec::<EpollEvent>::with_capacity(100);
        unsafe { events.set_len(100); }

        loop {
            // Wait for epoll events
            match epoll::wait(epoll_instance, &mut events[..], -1) {
                Ok(num_events) => {
                    println!("{} epoll event(s) received", num_events);
                    for x in 0..num_events {
                        let tx_clone = uspace_tx.clone();
                        let s_clone = sockets.clone();
                        let epfd_clone = epoll_instance.clone();

                        EventLoop::handle_epoll_event(epfd_clone,
                            &events[x as usize], s_clone, tx_clone);
                    }
                }
                Err(e) => {
                    panic!("Error on epoll::wait(): {}", e)
                }
            }

            // If we receive anything on this end or lose communication, we need to halt,
            // because we have no where to send up events, our "user space" channel is
            // gone
            match err_rx.try_recv() {
                Ok(_) => {
                    println!("Error, terminating epoll_loop");
                    break;
                }
                Err(e) => {
                    match e {
                        TryRecvError::Empty => {}
                        _ => {
                            println!("Error, terminating epoll_loo");
                            break;
                        }
                    }
                }
            }
        }
        println!("Rust.EventLoop.epoll_loop - thread finished");
    }

    /// Processes a read on the socket that is ready for reading
    ///
    /// An epoll event is passed to this function, with the fd that is ready to be read
    /// A traversal through the list of sockets is then performed in order to locate the
    /// NbetStream instance that is wrapping that file descriptor.
    /// After a read is performed on that socket, it's data will be passed back to the
    /// "user-space" section of the Server to process the payload however it needs to.
    ///
    /// TODO - Create a faster way to gain a safe reference to the NbetStream wrapping
    /// the fd instead of an O(n) lookup for every event. Currently lookup time is
    /// O(n) * MAX_EPOLL_EVENTS, where MAX_EPOLL_EVENTS is user defined in this function's
    /// caller.
    fn handle_epoll_event(epoll_instance: RawFd,
                          event: &EpollEvent,
                          sockets: SocketList,
                          uspace_tx: Sender<EventTuple>) {

        println!("Rust.EventLoop.handle_epoll_event");

        // List of socket id's that produced an Err on read attempt
        // Cannot do it within the match block because the list will need
        // access to the mutex, while this scope has the mutex, which will result
        // in a spinlock that will spin forever. And, that's a trip to bummer town
        let mut errd_socket_ids = Vec::<u32>::new();

        // The fd we are traversing the list for
        let fd = event.data;

        // We need a handle before the list gets locked and used
        let s_list_clone = sockets.clone();

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();
        for socket in s_list.iter_mut() {
            if socket.raw_fd() as u64 == fd {
                // We've found the socket for the event passed from epoll
                // Lets attempt to read from it
                match socket.read() {
                    Ok(()) => {
                        println!("Rust.EventLoop.handle_epoll_event.socket.read.Ok()");
                        for msg in socket.buffer().iter() {
                            let msg_for_debug = msg.clone();
                            match String::from_utf8(msg_for_debug) {
                                Ok(msg_str) => {
                                    println!("Rust.EventLoop.handle_epoll_event.socket.read.ok.msg_as_string: {}", msg_str);
                                }
                                Err(e) => {
                                    println!("Rust.EventLoop.handle_epoll_event.socket.read.ok.msg_as_string.Err: {}", e);
                                }
                            };

                            let list_handle = s_list_clone.clone();
                            let socket_clone = socket.clone();
                            let msg_clone = msg.clone();
                            let _ = uspace_tx.send((list_handle, socket_clone, msg_clone));
                        }
                    }
                    Err(e) => {
                        println!("Rust.EventLoop.handle_epoll_event.socket.read.Err(e): {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        errd_socket_ids.push(socket.id());
                        let s_clone = socket.clone();
                        let epfd_clone = epoll_instance.clone();
                        EventLoop::remove_socket_from_epoll(s_clone, epfd_clone);
                    }
                }
            }
        }

        // Remove any errd sockets from the master list of sockets
        EventLoop::remove_socket_from_list(errd_socket_ids, list_clone);
    }

    /// Removes socket from the epoll watch list
    fn remove_socket_from_epoll(socket: Socket, epoll_instance: RawFd) {
        println!("remove_socket_from_epoll");

        // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
        // a non-null pointer in event, even though this argument is ignored.
        // Since Linux 2.6.9, event can be specified as NULL when using
        // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
        // before 2.6.9 should specify a non-null pointer in event.
        let event = Box::new(EpollEvent {
            data: 0 as u64,
            events: 0 as u32
        });
        let s_fd = socket.raw_fd();

        // Depending on how fd are duplicated with .clone(), this may fail
        // If the failure case is CtlError::ENOENT, we do not care, because
        // epoll will clean the up the descriptor after they are all dropped from
        // program memory
        match epoll::ctl(epoll_instance, ctl_op::DEL, s_fd, event) {
            Ok(()) => println!("Socket removed from epoll watch list"),
            Err(e) => {
                match e {
                    CtlError::ENOENT => {
                        println!("Fd not found in epoll, will remove when fd is syscall closed");
                    }
                    _ => println!("Epoll CtrlError during del: {}", e)
                }
            }
        };
    }

    /// Removes socket from master list
    fn remove_socket_from_list(socket_ids: Vec<u32>, sockets: SocketList) {
        println!("remove_socket_from_list");

        // TODO - Replace with recoverable version once into_inner() is stable
        // Unfortunately, this is the only stable way to use mutexes at the moment
        // Hopefully recovering from poisoning will be in 1.2
        // let mut s_guard = match sockets.lock() {
        //     Ok(guard) => guard,
        //     Err(poisoned) => poisoned.into_inner()
        // };
        let mut s_guard = sockets.lock().unwrap();
        let s_list = s_guard.deref_mut();

        for socket_id in socket_ids.iter() {
            let mut socket_found = false;
            let mut index: usize = 1;
            for socket in s_list.iter() {
                if socket.id() == socket_id {
                    socket_found = true;
                    break;
                }
                index += 1;
            }

            if !socket_found {
                println!("Socket not found in list...?");
                return;
            }

            if index == 1 {
                s_list.pop_front();
            } else {
                let mut split = s_list.split_off(index - 1);
                split.pop_front();
                s_list.append(&mut split);
            }

            println!("Socket removed sucessfully");
        }
    }
}
<|endoftext|>


<commit_before>use failure::*;
use std::env::var;
use std::fs;
use std::io::*;
use std::path::*;
use std::process::Command;
use zip::ZipArchive;

fn download_archive_windows(out_dir: &Path) -> Fallible<()> {
    if out_dir.join("libfftw3.dll").exists() && out_dir.join("libfftw3f.dll").exists() {
        return Ok(());
    }

    let archive = out_dir.join("fftw_windows.zip");
    if !archive.exists() {
        // Download
        let mut conn = ftp::FtpStream::connect("ftp.fftw.org:21")?;
        conn.login("anonymous", "anonymous")?;
        conn.cwd("pub/fftw")?;
        let buf = conn.simple_retr("fftw-3.3.5-dll64.zip")?.into_inner();
        // TODO calc checksum
        let mut f = fs::File::create(&archive)?;
        f.write(&buf)?;
    }
    let f = fs::File::open(&archive)?;
    let mut zip = ZipArchive::new(f)?;
    let target = var("TARGET").unwrap();
    for name in &["fftw3-3", "fftw3f-3"] {
        for ext in &["dll", "def"] {
            let filename = format!("lib{}.{}", name, ext);
            let mut zf = zip.by_name(&filename)?;
            let mut f = fs::File::create(out_dir.join(filename))?;
            copy(&mut zf, &mut f)?;
        }
        run(cc::windows_registry::find_tool(&target, "lib.exe")
            .unwrap()
            .to_command()
            .arg("/MACHINE:X64")
            .arg(format!("/DEF:lib{}.def", name))
            .arg(format!("/OUT:lib{}.lib", name))
            .current_dir(out_dir))
    }
    Ok(())
}

fn build_unix(out_dir: &Path) {
    let root_dir = PathBuf::from(var("CARGO_MANIFEST_DIR").unwrap());
    let archive_dir = root_dir.join("fftw-3.3.8");
    if !out_dir.join("lib/libfftw3.a").exists() {
        build_fftw(&[], &archive_dir, &out_dir);
    }
    if !out_dir.join("lib/libfftw3f.a").exists() {
        build_fftw(&["--enable-single"], &archive_dir, &out_dir);
    }
}

fn build_fftw(flags: &[&str], src_dir: &Path, out_dir: &Path) {
    run(
        Command::new(fs::canonicalize(src_dir.join("configure")).unwrap())
            .arg("--with-pic")
            .arg("--enable-static")
            .arg("--disable-doc")
            .arg(format!("--prefix={}", out_dir.display()))
            .args(flags)
            .current_dir(&src_dir),
    );
    run(Command::new("make")
        .arg(format!("-j{}", var("NUM_JOBS").unwrap()))
        .current_dir(&src_dir));
    run(Command::new("make").arg("install").current_dir(&src_dir));
}

fn run(command: &mut Command) {
    println!("Running: {:?}", command);
    match command.status() {
        Ok(status) => {
            if !status.success() {
                panic!("`{:?}` failed: {}", command, status);
            }
        }
        Err(error) => {
            panic!("failed to execute `{:?}`: {}", command, error);
        }
    }
}

fn main() -> Fallible<()> {
    let out_dir = PathBuf::from(var("OUT_DIR").unwrap());
    if cfg!(target_os = "windows") {
        download_archive_windows(&out_dir)?;
        println!("cargo:rustc-link-search={}", out_dir.display());
        println!("cargo:rustc-link-lib=libfftw3-3");
        println!("cargo:rustc-link-lib=libfftw3f-3");
    } else {
        build_unix(&out_dir);
        println!("cargo:rustc-link-search={}", out_dir.join("lib").display());
        println!("cargo:rustc-link-lib=static=fftw3");
        println!("cargo:rustc-link-lib=static=fftw3f");
    }
    Ok(())
}
<commit_msg>fftw-src: Don't return errors from main()<commit_after>use failure::*;
use std::env::var;
use std::fs;
use std::io::*;
use std::path::*;
use std::process::Command;
use zip::ZipArchive;

fn download_archive_windows(out_dir: &Path) -> Fallible<()> {
    if out_dir.join("libfftw3.dll").exists() && out_dir.join("libfftw3f.dll").exists() {
        return Ok(());
    }

    let archive = out_dir.join("fftw_windows.zip");
    if !archive.exists() {
        // Download
        let mut conn = ftp::FtpStream::connect("ftp.fftw.org:21")?;
        conn.login("anonymous", "anonymous")?;
        conn.cwd("pub/fftw")?;
        let buf = conn.simple_retr("fftw-3.3.5-dll64.zip")?.into_inner();
        // TODO calc checksum
        let mut f = fs::File::create(&archive)?;
        f.write(&buf)?;
    }
    let f = fs::File::open(&archive)?;
    let mut zip = ZipArchive::new(f)?;
    let target = var("TARGET").unwrap();
    for name in &["fftw3-3", "fftw3f-3"] {
        for ext in &["dll", "def"] {
            let filename = format!("lib{}.{}", name, ext);
            let mut zf = zip.by_name(&filename)?;
            let mut f = fs::File::create(out_dir.join(filename))?;
            copy(&mut zf, &mut f)?;
        }
        run(cc::windows_registry::find_tool(&target, "lib.exe")
            .unwrap()
            .to_command()
            .arg("/MACHINE:X64")
            .arg(format!("/DEF:lib{}.def", name))
            .arg(format!("/OUT:lib{}.lib", name))
            .current_dir(out_dir))
    }
    Ok(())
}

fn build_unix(out_dir: &Path) {
    let root_dir = PathBuf::from(var("CARGO_MANIFEST_DIR").unwrap());
    let archive_dir = root_dir.join("fftw-3.3.8");
    if !out_dir.join("lib/libfftw3.a").exists() {
        build_fftw(&[], &archive_dir, &out_dir);
    }
    if !out_dir.join("lib/libfftw3f.a").exists() {
        build_fftw(&["--enable-single"], &archive_dir, &out_dir);
    }
}

fn build_fftw(flags: &[&str], src_dir: &Path, out_dir: &Path) {
    run(
        Command::new(fs::canonicalize(src_dir.join("configure")).unwrap())
            .arg("--with-pic")
            .arg("--enable-static")
            .arg("--disable-doc")
            .arg(format!("--prefix={}", out_dir.display()))
            .args(flags)
            .current_dir(&src_dir),
    );
    run(Command::new("make")
        .arg(format!("-j{}", var("NUM_JOBS").unwrap()))
        .current_dir(&src_dir));
    run(Command::new("make").arg("install").current_dir(&src_dir));
}

fn run(command: &mut Command) {
    println!("Running: {:?}", command);
    match command.status() {
        Ok(status) => {
            if !status.success() {
                panic!("`{:?}` failed: {}", command, status);
            }
        }
        Err(error) => {
            panic!("failed to execute `{:?}`: {}", command, error);
        }
    }
}

fn main() {
    let out_dir = PathBuf::from(var("OUT_DIR").unwrap());
    if cfg!(target_os = "windows") {
        download_archive_windows(&out_dir).unwrap();
        println!("cargo:rustc-link-search={}", out_dir.display());
        println!("cargo:rustc-link-lib=libfftw3-3");
        println!("cargo:rustc-link-lib=libfftw3f-3");
    } else {
        build_unix(&out_dir);
        println!("cargo:rustc-link-search={}", out_dir.join("lib").display());
        println!("cargo:rustc-link-lib=static=fftw3");
        println!("cargo:rustc-link-lib=static=fftw3f");
    }
}
<|endoftext|>


<commit_before>#![cfg(unix)]

extern crate rexpect;

use rexpect::spawn;
use rexpect::errors::*;

static COMMAND: &str = "../target/debug/gluon -i";
static TIMEOUT: u64 = 10_000;
static PROMPT: &str = "> ";

macro_rules! test {
    ($b: block) => {
        if ::std::env::var("GLUON_PATH").is_err() {
            ::std::env::set_var("GLUON_PATH", "..");
        }

        || -> Result<()> {
            $b
            Ok(())
        }().unwrap_or_else(|err| panic!("{}", err));
    };
}

#[test]
fn prompt() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;
    });
}

#[test]
fn exit() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;

        repl.send_line(":q")?;
        repl.exp_eof()?;
    });
}

#[test]
fn hello_world() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;

        repl.send_line("let io = import! std.io")?;

        repl.exp_regex("\\{[^}]+\\}")?;

        repl.send_line("io.println \"Hello world\"")?;
        repl.exp_string("Hello world")?;
    });
}

#[test]
fn expression_types() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;

        repl.send_line(":t 5")?;
        repl.exp_string("Int")?;

        repl.send_line(":t 5 + 5")?;
        repl.exp_string("Int -> Int")?;

        repl.send_line(":t \"gluon\"")?;
        repl.exp_string("String")?;
    });
}

#[test]
fn names() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;

        repl.send_line(":i std.prelude.show")?;
        repl.exp_string("std.prelude.show: forall a . [std.prelude.Show a] -> a -> String")?;
    });
}

#[test]
fn comments() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;

        repl.send_line("1 + 2 // Calls the + function on 1 and 2")?;
        repl.exp_string("3")?;

        repl.send_line("1 + 2 /* Calls the + function on 1 and 2 */")?;
        repl.exp_string("3")?;
    });
}

#[test]
fn if_expressions() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;

        repl.send_line("if True then 1 else 0")?;
        repl.exp_string("1")?;

        repl.send_line("if False then 1 else 0")?;
        repl.exp_string("0")?;
    });
}

#[test]
fn records() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;

        repl.send_line("let record = { pi = 3.14, add1 = (+) 1.0 }")?;

        repl.send_line("record.pi")?;
        repl.exp_string("3.14")?;

        repl.send_line("let record_2 = {x = 1 .. record }")?;

        repl.send_line("record_2.x")?;
        repl.exp_string("1")?;

        repl.send_line("record_2.pi")?;
        repl.exp_string("3.14")?;
    });
}

#[test]
fn arrays() {
    test!({
        let mut repl = spawn(COMMAND, Some(TIMEOUT))?;
        repl.exp_string(PROMPT)?;

        repl.send_line("let array = import! std.array")?;

        repl.send_line("array.len [1, 2, 3]")?;
        repl.exp_string("3")?;
    });
}
<commit_msg>Wrap repl tests in interface.<commit_after>#![cfg(unix)]

extern crate rexpect;

use rexpect::spawn;
use rexpect::session::PtySession;
use rexpect::errors::*;

macro_rules! test {
    ($b: block) => {
        if ::std::env::var("GLUON_PATH").is_err() {
            ::std::env::set_var("GLUON_PATH", "..");
        }

        || -> Result<()> {
            $b
            Ok(())
        }().unwrap_or_else(|err| panic!("{}", err));
    };
}

struct REPL {
    session: PtySession,
    prompt: &'static str,
}

impl REPL {
    /// Defines the command, timeout, and prompt settings.
    /// Wraps a rexpect::session::PtySession. expecting the prompt after launch.
    fn new() -> Result<REPL> {
        let command = "../target/debug/gluon -i";
        let timeout: u64 = 10_000;
        let prompt: &'static str = "> ";

        let mut session = spawn(command, Some(timeout))?;
        session.exp_string(prompt)?;

        Ok(REPL { session, prompt })
    }

    /// Ensures certain lines are expected to reduce race conditions.
    /// If no ouput is expected or desired to be tested, pass it an Option::None,
    /// causing rexpect to wait for the next prompt.
    fn test(&mut self, send: &str, expect: Option<&str>) -> Result<()> {
        self.session.send_line(send)?;
        self.session.exp_string(send)?;

        if let Some(string) = expect {
            self.session.exp_string(string)?;
        }

        self.session.exp_string(self.prompt)?;
        Ok(())
    }

    fn quit(&mut self) -> Result<()> {
        let line: &'static str = ":q";
        self.session.send_line(line)?;
        self.session.exp_string(line)?;
        self.session.exp_eof()?;
        Ok(())
    }
}

#[test]
fn prompt() {
    test!({
        let mut repl = REPL::new()?;
        repl.test(repl.prompt, None)?;
    });
}

#[test]
fn exit() {
    test!({
        let mut repl = REPL::new()?;
        repl.quit()?;
    });
}

#[test]
fn hello_world() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let io = import! std.io", None)?;
        repl.test("io.println \"Hello world\"", Some("Hello world"))?;
    });
}

#[test]
fn expression_types() {
    test!({
        let mut repl = REPL::new()?;

        repl.test(":t 5", Some("Int"))?;
        // repl.test(":t 5 + 5", Some("Int -> Int"))?;
        repl.test(":t \"gluon\"", Some("String"))?;
    });
}

#[test]
fn names() {
    test!({
        let mut repl = REPL::new()?;

        repl.test(
            ":i std.prelude.show",
            Some("std.prelude.show: forall a . [std.prelude.Show a] -> a -> String"),
        )?;
    });
}

#[test]
fn comments() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("1 + 2 // Calls the + function on 1 and 2", Some("3"))?;
        repl.test("1 + 2 /* Calls the + function on 1 and 2 */", Some("3"))?;
    });
}

#[test]
fn if_expressions() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("if True then 1 else 0", Some("1"))?;
        repl.test("if False then 1 else 0", Some("0"))?;
    });
}

#[test]
fn records() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let record = { pi = 3.14, add1 = (+) 1.0 }", None)?;
        repl.test("record.pi", Some("3.14"))?;

        repl.test("let record_2 = {x = 1 .. record }", None)?;
        repl.test("record_2.x", Some("1"))?;
        repl.test("record_2.pi", Some("3.14"))?;
    });
}

#[test]
fn arrays() {
    test!({
        let mut repl = REPL::new()?;

        repl.test("let array = import! std.array", None)?;
        repl.test("array.len [1, 2, 3]", Some("3"))?;
    });
}
<|endoftext|>


<commit_before>//! Physical memory management

use alloc::boxed::Box;

use core::ops::{Index, IndexMut};

use super::super::interrupts::{on, off};
use super::super::process::CURRENT_PROCESS;
use super::super::static_linked_list::StaticLinkedList;
use super::regionmap::RegionMap;

/// Array of `FrameInfo`. This is a pointer to the region of memory used
/// to hold physical memory allocation metadata.
static mut FRAME_INFO: *mut FrameInfoSection = 0 as *mut FrameInfoSection;

/// The index of the first free frame in a LIFO list.
/// 0 => empty list
static mut FREE_FRAMES: usize = 0;

/// A physical memory frame
#[repr(C, packed)]
pub struct Frame {
    mem: [usize; 1024],
}

/// Should take up 4MiB on a 32-bit machine.
/// There is one frame info for each frame, associated by frame index
#[repr(C, packed)]
pub struct FrameInfoSection {
    arr: [FrameInfo; 1 << 20],
}

/// Frame info
/// ```
/// When free
/// 31                 20           0
/// [nnnnnnnnnnnnnnnnnnnn           1]
///  ^-- next free index            ^-- free bit
///
/// When allocated
/// 31                           30 0
/// [ssssssssssssssssssssssssssssss 0]
///  ^-- ptr to shared frame info  ^^-- free bit
///                                |
///                                +-- PD bit
/// ```
#[repr(C, packed)]
pub struct FrameInfo {
    info: usize,
}

/// A struct to keep track of information related to shared
/// physical frames.
#[allow(dead_code)]
pub struct SharedFrameInfo {
    /// needs to be at least 4B aligned
    pad: u32,

    /// list of sharers: (pid, vaddr)
    list: StaticLinkedList<(usize, usize)>,
}

impl Frame {
    /// Allocate a frame and return its physical address
    pub fn alloc() -> usize {
        let all_frames = unsafe { &mut *FRAME_INFO };

        off();

        // get a frame
        let free = unsafe { FREE_FRAMES };

        if free == 0 {
            // TODO: page out
            panic!("Out of physical memory");
        }

        all_frames[free].alloc();

        on();

        free << 12
    }

    /// Free the frame with the given index
    pub fn free(index: usize) {
        let all_frames = unsafe { &mut *FRAME_INFO };

        off();
        all_frames[index].free();
        on();
    }

    /// Add the given pid as a sharer of this frame.
    pub fn share(pid: usize, vaddr: usize, paddr: usize) {

        // TODO: deal with a frame being shared multiple times
        // by the same process

        let all_frames = unsafe { &mut *FRAME_INFO };
        let index = paddr >> 12;

        off();

        let frame = &mut all_frames[index];
        let sfi = if frame.has_shared_info() {
            frame.get_shared_info().expect("No shared frame info!")
        } else {
            let raw_sfi = Box::into_raw(box SharedFrameInfo::new());
            frame.set_shared_info(raw_sfi);
            unsafe { &mut *raw_sfi }
        };

        sfi.list.push_back((pid, vaddr));

        on();

        // printf!("Shared {:X} {:X}\n", vaddr, paddr);
    }
}

/// Make the words of a frame indexable
impl Index<usize> for Frame {
    type Output = usize;

    fn index<'a>(&'a self, index: usize) -> &'a usize {
        &self.mem[index]
    }
}

/// Make the words of a frame indexable
impl IndexMut<usize> for Frame {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut usize {
        &mut self.mem[index]
    }
}

/// Make the `FrameInfoSection` indexable
impl Index<usize> for FrameInfoSection {
    type Output = FrameInfo;

    fn index<'a>(&'a self, index: usize) -> &'a FrameInfo {
        &self.arr[index]
    }
}

/// Make the `FrameInfoSection` indexable
impl IndexMut<usize> for FrameInfoSection {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut FrameInfo {
        &mut self.arr[index]
    }
}

impl FrameInfo {
    /// Allocate the frame referred to by this `FrameInfo`.
    /// NOTE: this should only be called on the first frame in the free list
    pub fn alloc(&mut self) {
        if self.get_index() != unsafe { FREE_FRAMES } {
            panic!("Attempt to alloc middle free frame {}", self.get_index());
        }

        off();

        // Remove from list
        unsafe {
            FREE_FRAMES = self.get_next_free();
        }

        on();

        // mark not free
        self.clear_shared_info();
        self.set_free(false);
    }

    /// Free the frame referred to by this FrameInfo
    /// if this is the last sharere; otherwise, just remove this
    /// process's `SharedFrameInfo`.
    pub fn free(&mut self) {
        // remove shared page info for this process
        let pid = unsafe { (*CURRENT_PROCESS).get_pid() };
        let mut dealloced = false;
        if self.has_shared_info() {
            let sfi_list = &mut self.get_shared_info()
                .expect("No shared frame info to free")
                .list;
            let i = sfi_list.iter()
                .position(|&(req_pid, _)| req_pid == pid)
                .expect("Attempt to free shared page which this process is not sharing!");
            let _ = sfi_list.remove(i);

            // if no more sharers, drop the shared info
            if sfi_list.is_empty() {
                let addr = self.info & !3;
                let ptr = addr as *mut SharedFrameInfo;
                off();
                unsafe {
                    Box::from_raw(ptr);
                }
                dealloced = true;
            }
        }

        if dealloced {
            self.clear_shared_info();
            on();
        }

        // if there is only one "sharer" left, free the page
        if !self.has_shared_info() {
            // mark free
            self.set_free(true);

            // add to free list
            off();

            unsafe {
                self.set_next_free(FREE_FRAMES);
                FREE_FRAMES = self.get_index();
            }

            on();
        }
    }

    /// Get the index of the `Frame`
    pub fn get_index(&self) -> usize {
        let first = unsafe { FRAME_INFO as *const FrameInfoSection as usize };
        let addr = self as *const FrameInfo as usize;
        (addr - first) / 4
    }

    /// Set the free bit of this `FrameInfo` to 1 if `free` is true; else 0
    fn set_free(&mut self, free: bool) {
        let base = self.info & !1;
        self.info = base | if free { 1 } else { 0 }
    }

    /// Get the index of the next free frame
    fn get_next_free(&self) -> usize {
        self.info >> 12
    }

    /// Set the index of the next free frame
    fn set_next_free(&mut self, next: usize) {
        let base = self.info & 0xFFF;
        self.info = (next << 12) | base;
    }

    /// Returns true if this frame has shared frame info.
    ///
    /// NOTE: this does not mean the frame is shared yet.
    fn has_shared_info(&self) -> bool {
        self.get_shared_info().is_some()
    }

    /// Get the `SharedFrameInfo` of this frame
    fn get_shared_info(&self) -> Option<&mut SharedFrameInfo> {
        let addr = self.info & !3;
        let ptr = addr as *mut SharedFrameInfo;

        if ptr.is_null() {
            None
        } else {
            unsafe { Some(&mut *ptr) }
        }
    }

    /// Set the `SharedFrameInfo` of this frame
    fn set_shared_info(&mut self, sfi: *mut SharedFrameInfo) {
        if self.get_shared_info().is_some() {
            panic!("Attempt to overwrite shared frame info!");
        }

        let addr = (sfi as usize) & !3;
        let base = self.info & 3;

        self.info = addr | base;
    }

    /// Remove the `SharedFrameInfo` ptr of the frame
    fn clear_shared_info(&mut self) {
        self.info &= 3;
    }
}

impl SharedFrameInfo {
    fn new() -> SharedFrameInfo {
        SharedFrameInfo {
            pad: 0,
            list: StaticLinkedList::new(),
        }
    }
}

/// Initialize physical memory frames using the rest of physical memory.
/// This function detects all available physical memory.
pub fn init(start: usize) {
    if start % 0x400000 != 0 {
        panic!("phys mem start must be 4MiB aligned!");
    }

    unsafe {
        // round start up to nearest page boundary
        FRAME_INFO = if start % 0x1000 == 0 {
            start
        } else {
            start - (start % 0x1000) + 0x1000
        } as *mut FrameInfoSection;
    }

    let all_frames = unsafe { &mut *FRAME_INFO };

    // Detect available memory
    let mem = RegionMap::new((8 << 20) as *mut Frame);
    let mut num_frames = 0;

    // add all available frames to free list
    for (base, num) in mem {
        for i in base..(base + num) {
            all_frames[i].free();
        }
        num_frames += num;
    }

    bootlog!("phys mem inited - metadata @ 0x{:X}, {} frames\n",
             start,
             num_frames);
}
<commit_msg>minor changes<commit_after>//! Physical memory management

use alloc::boxed::Box;

use core::ops::{Index, IndexMut};

use super::super::interrupts::{on, off};
use super::super::process::CURRENT_PROCESS;
use super::super::static_linked_list::StaticLinkedList;
use super::regionmap::RegionMap;

/// Array of `FrameInfo`. This is a pointer to the region of memory used
/// to hold physical memory allocation metadata.
static mut FRAME_INFO: *mut FrameInfoSection = 0 as *mut FrameInfoSection;

/// The index of the first free frame in a LIFO list.
/// 0 => empty list
static mut FREE_FRAMES: usize = 0;

/// A physical memory frame
#[repr(C, packed)]
pub struct Frame([usize; 1024]);

/// Should take up 4MiB on a 32-bit machine.
/// There is one frame info for each frame, associated by frame index
#[repr(C, packed)]
pub struct FrameInfoSection([FrameInfo; 1 << 20]);

/// Frame info
/// ```
/// When free
/// 31                 20           0
/// [nnnnnnnnnnnnnnnnnnnn           1]
///  ^-- next free index            ^-- free bit
///
/// When allocated
/// 31                           30 0
/// [ssssssssssssssssssssssssssssss 0]
///  ^-- ptr to shared frame info  ^^-- free bit
///                                |
///                                +-- PD bit
/// ```
#[repr(C, packed)]
pub struct FrameInfo(usize);

/// A struct to keep track of information related to shared
/// physical frames.
#[allow(dead_code)]
pub struct SharedFrameInfo {
    /// needs to be at least 4B aligned
    pad: u32,

    /// list of sharers: (pid, vaddr)
    list: StaticLinkedList<(usize, usize)>,
}

impl Frame {
    /// Allocate a frame and return its physical address
    pub fn alloc() -> usize {
        let all_frames = unsafe { &mut *FRAME_INFO };

        off();

        // get a frame
        let free = unsafe { FREE_FRAMES };

        if free == 0 {
            // TODO: page out
            panic!("Out of physical memory");
        }

        all_frames[free].alloc();

        on();

        free << 12
    }

    /// Free the frame with the given index
    pub fn free(index: usize) {
        let all_frames = unsafe { &mut *FRAME_INFO };

        off();
        all_frames[index].free();
        on();
    }

    /// Add the given pid as a sharer of this frame.
    pub fn share(pid: usize, vaddr: usize, paddr: usize) {

        // TODO: deal with a frame being shared multiple times
        // by the same process

        let all_frames = unsafe { &mut *FRAME_INFO };
        let index = paddr >> 12;

        off();

        let frame = &mut all_frames[index];
        let sfi = if frame.has_shared_info() {
            frame.get_shared_info().expect("No shared frame info!")
        } else {
            let raw_sfi = Box::into_raw(box SharedFrameInfo::new());
            frame.set_shared_info(raw_sfi);
            unsafe { &mut *raw_sfi }
        };

        sfi.list.push_back((pid, vaddr));

        on();

        // printf!("Shared {:X} {:X}\n", vaddr, paddr);
    }
}

/// Make the words of a frame indexable
impl Index<usize> for Frame {
    type Output = usize;

    fn index<'a>(&'a self, index: usize) -> &'a usize {
        &self.0[index]
    }
}

/// Make the words of a frame indexable
impl IndexMut<usize> for Frame {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut usize {
        &mut self.0[index]
    }
}

/// Make the `FrameInfoSection` indexable
impl Index<usize> for FrameInfoSection {
    type Output = FrameInfo;

    fn index<'a>(&'a self, index: usize) -> &'a FrameInfo {
        &self.0[index]
    }
}

/// Make the `FrameInfoSection` indexable
impl IndexMut<usize> for FrameInfoSection {
    fn index_mut<'a>(&'a mut self, index: usize) -> &'a mut FrameInfo {
        &mut self.0[index]
    }
}

impl FrameInfo {
    /// Allocate the frame referred to by this `FrameInfo`.
    /// NOTE: this should only be called on the first frame in the free list
    pub fn alloc(&mut self) {
        if self.get_index() != unsafe { FREE_FRAMES } {
            panic!("Attempt to alloc middle free frame {}", self.get_index());
        }

        off();

        // Remove from list
        unsafe {
            FREE_FRAMES = self.get_next_free();
        }

        on();

        // mark not free
        self.clear_shared_info();
        self.set_free(false);
    }

    /// Free the frame referred to by this FrameInfo
    /// if this is the last sharere; otherwise, just remove this
    /// process's `SharedFrameInfo`.
    pub fn free(&mut self) {
        // remove shared page info for this process
        let pid = unsafe { (*CURRENT_PROCESS).get_pid() };
        let mut dealloced = false;
        if self.has_shared_info() {
            let sfi_list = &mut self.get_shared_info()
                .expect("No shared frame info to free")
                .list;
            let i = sfi_list.iter()
                .position(|&(req_pid, _)| req_pid == pid)
                .expect("Attempt to free shared page which this process is not sharing!");
            let _ = sfi_list.remove(i);

            // if no more sharers, drop the shared info
            if sfi_list.is_empty() {
                let addr = self.0 & !3;
                let ptr = addr as *mut SharedFrameInfo;
                off();
                unsafe {
                    Box::from_raw(ptr);
                }
                dealloced = true;
            }
        }

        if dealloced {
            self.clear_shared_info();
            on();
        }

        // if there is only one "sharer" left, free the page
        if !self.has_shared_info() {
            // mark free
            self.set_free(true);

            // add to free list
            off();

            unsafe {
                self.set_next_free(FREE_FRAMES);
                FREE_FRAMES = self.get_index();
            }

            on();
        }
    }

    /// Get the index of the `Frame`
    pub fn get_index(&self) -> usize {
        let first = unsafe { FRAME_INFO as *const FrameInfoSection as usize };
        let addr = self as *const FrameInfo as usize;
        (addr - first) / 4
    }

    /// Set the free bit of this `FrameInfo` to 1 if `free` is true; else 0
    fn set_free(&mut self, free: bool) {
        let base = self.0 & !1;
        self.0 = base | if free { 1 } else { 0 }
    }

    /// Get the index of the next free frame
    fn get_next_free(&self) -> usize {
        self.0 >> 12
    }

    /// Set the index of the next free frame
    fn set_next_free(&mut self, next: usize) {
        let base = self.0 & 0xFFF;
        self.0 = (next << 12) | base;
    }

    /// Returns true if this frame has shared frame info.
    ///
    /// NOTE: this does not mean the frame is shared yet.
    fn has_shared_info(&self) -> bool {
        self.get_shared_info().is_some()
    }

    /// Get the `SharedFrameInfo` of this frame
    fn get_shared_info(&self) -> Option<&mut SharedFrameInfo> {
        let addr = self.0 & !3;
        let ptr = addr as *mut SharedFrameInfo;

        if ptr.is_null() {
            None
        } else {
            unsafe { Some(&mut *ptr) }
        }
    }

    /// Set the `SharedFrameInfo` of this frame
    fn set_shared_info(&mut self, sfi: *mut SharedFrameInfo) {
        if self.get_shared_info().is_some() {
            panic!("Attempt to overwrite shared frame info!");
        }

        let addr = (sfi as usize) & !3;
        let base = self.0 & 3;

        self.0 = addr | base;
    }

    /// Remove the `SharedFrameInfo` ptr of the frame
    fn clear_shared_info(&mut self) {
        self.0 &= 3;
    }
}

impl SharedFrameInfo {
    fn new() -> SharedFrameInfo {
        SharedFrameInfo {
            pad: 0,
            list: StaticLinkedList::new(),
        }
    }
}

/// Initialize physical memory frames using the rest of physical memory.
/// This function detects all available physical memory.
pub fn init(start: usize) {
    if start % 0x400000 != 0 {
        panic!("phys mem start must be 4MiB aligned!");
    }

    unsafe {
        // round start up to nearest page boundary
        FRAME_INFO = if start % 0x1000 == 0 {
            start
        } else {
            start - (start % 0x1000) + 0x1000
        } as *mut FrameInfoSection;
    }

    let all_frames = unsafe { &mut *FRAME_INFO };

    // Detect available memory
    let mem = RegionMap::new((8 << 20) as *mut Frame);
    let mut num_frames = 0;

    // add all available frames to free list
    for (base, num) in mem {
        for i in base..(base + num) {
            all_frames[i].free();
        }
        num_frames += num;
    }

    bootlog!("phys mem inited - metadata @ 0x{:X}, {} frames\n",
             start,
             num_frames);
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Colin Finck, RWTH Aachen University
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use arch::x86_64::mm::paging::{BasePageSize, PageSize};
use collections::Node;
use mm;
use mm::freelist::{FreeList, FreeListEntry};
use mm::POOL;
use scheduler::DisabledPreemption;

static mut KERNEL_FREE_LIST: FreeList = FreeList::new();

/// End of the virtual memory address space reserved for kernel memory (4 GiB).
/// This also marks the start of the virtual memory address space reserved for the task heap.
const KERNEL_VIRTUAL_MEMORY_END: usize = 0x1_0000_0000;

/// End of the virtual memory address space reserved for kernel memory (128 TiB).
/// This is the maximum contiguous virtual memory area possible with current x86-64 CPUs, which only support 48-bit
/// linear addressing (in two 47-bit areas).
const TASK_VIRTUAL_MEMORY_END: usize = 0x8000_0000_0000;

pub fn init() {
	let entry = Node::new(
		FreeListEntry {
			start: mm::kernel_end_address(),
			end: KERNEL_VIRTUAL_MEMORY_END
		}
	);
	unsafe { KERNEL_FREE_LIST.list.push(entry); }
}

pub fn allocate(size: usize) -> usize {
	assert!(size > 0);
	assert!(size % BasePageSize::SIZE == 0, "Size {:#X} is not a multiple of {:#X}", size, BasePageSize::SIZE);

	let _preemption = DisabledPreemption::new();
	let result = unsafe { KERNEL_FREE_LIST.allocate(size) };
	assert!(result.is_ok(), "Could not allocate {:#X} bytes of virtual memory", size);
	result.unwrap()
}

pub fn deallocate(virtual_address: usize, size: usize) {
	assert!(virtual_address >= mm::kernel_end_address(), "Virtual address {:#X} is not >= KERNEL_END_ADDRESS", virtual_address);
	assert!(virtual_address < KERNEL_VIRTUAL_MEMORY_END, "Virtual address {:#X} is not < KERNEL_VIRTUAL_MEMORY_END", virtual_address);
	assert!(virtual_address % BasePageSize::SIZE == 0, "Virtual address {:#X} is not a multiple of {:#X}", virtual_address, BasePageSize::SIZE);
	assert!(size > 0);
	assert!(size % BasePageSize::SIZE == 0, "Size {:#X} is not a multiple of {:#X}", size, BasePageSize::SIZE);

	let _preemption = DisabledPreemption::new();
	unsafe {
		POOL.maintain();
		KERNEL_FREE_LIST.deallocate(virtual_address, size);
	}
}

pub fn reserve(virtual_address: usize, size: usize) {
	assert!(virtual_address >= mm::kernel_end_address(), "Virtual address {:#X} is not >= KERNEL_END_ADDRESS", virtual_address);
	assert!(virtual_address < KERNEL_VIRTUAL_MEMORY_END, "Virtual address {:#X} is not < KERNEL_VIRTUAL_MEMORY_END", virtual_address);
	assert!(virtual_address % BasePageSize::SIZE == 0, "Virtual address {:#X} is not a multiple of {:#X}", virtual_address, BasePageSize::SIZE);
	assert!(size > 0);
	assert!(size % BasePageSize::SIZE == 0, "Size {:#X} is not a multiple of {:#X}", size, BasePageSize::SIZE);

	let result = unsafe {
		POOL.maintain();
		KERNEL_FREE_LIST.reserve(virtual_address, size)
	};
	assert!(result.is_ok(), "Could not reserve {:#X} bytes of virtual memory at {:#X}", size, virtual_address);
}

pub fn task_heap_start() -> usize {
	KERNEL_VIRTUAL_MEMORY_END
}

pub fn task_heap_end() -> usize {
	TASK_VIRTUAL_MEMORY_END
}
<commit_msg>protect critical section in virtualmem::reserve<commit_after>// Copyright (c) 2017 Colin Finck, RWTH Aachen University
//
// MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use arch::x86_64::mm::paging::{BasePageSize, PageSize};
use collections::Node;
use mm;
use mm::freelist::{FreeList, FreeListEntry};
use mm::POOL;
use scheduler::DisabledPreemption;

static mut KERNEL_FREE_LIST: FreeList = FreeList::new();

/// End of the virtual memory address space reserved for kernel memory (4 GiB).
/// This also marks the start of the virtual memory address space reserved for the task heap.
const KERNEL_VIRTUAL_MEMORY_END: usize = 0x1_0000_0000;

/// End of the virtual memory address space reserved for kernel memory (128 TiB).
/// This is the maximum contiguous virtual memory area possible with current x86-64 CPUs, which only support 48-bit
/// linear addressing (in two 47-bit areas).
const TASK_VIRTUAL_MEMORY_END: usize = 0x8000_0000_0000;

pub fn init() {
	let entry = Node::new(
		FreeListEntry {
			start: mm::kernel_end_address(),
			end: KERNEL_VIRTUAL_MEMORY_END
		}
	);
	unsafe { KERNEL_FREE_LIST.list.push(entry); }
}

pub fn allocate(size: usize) -> usize {
	assert!(size > 0);
	assert!(size % BasePageSize::SIZE == 0, "Size {:#X} is not a multiple of {:#X}", size, BasePageSize::SIZE);

	let _preemption = DisabledPreemption::new();
	let result = unsafe { KERNEL_FREE_LIST.allocate(size) };
	assert!(result.is_ok(), "Could not allocate {:#X} bytes of virtual memory", size);
	result.unwrap()
}

pub fn deallocate(virtual_address: usize, size: usize) {
	assert!(virtual_address >= mm::kernel_end_address(), "Virtual address {:#X} is not >= KERNEL_END_ADDRESS", virtual_address);
	assert!(virtual_address < KERNEL_VIRTUAL_MEMORY_END, "Virtual address {:#X} is not < KERNEL_VIRTUAL_MEMORY_END", virtual_address);
	assert!(virtual_address % BasePageSize::SIZE == 0, "Virtual address {:#X} is not a multiple of {:#X}", virtual_address, BasePageSize::SIZE);
	assert!(size > 0);
	assert!(size % BasePageSize::SIZE == 0, "Size {:#X} is not a multiple of {:#X}", size, BasePageSize::SIZE);

	let _preemption = DisabledPreemption::new();
	unsafe {
		POOL.maintain();
		KERNEL_FREE_LIST.deallocate(virtual_address, size);
	}
}

pub fn reserve(virtual_address: usize, size: usize) {
	assert!(virtual_address >= mm::kernel_end_address(), "Virtual address {:#X} is not >= KERNEL_END_ADDRESS", virtual_address);
	assert!(virtual_address < KERNEL_VIRTUAL_MEMORY_END, "Virtual address {:#X} is not < KERNEL_VIRTUAL_MEMORY_END", virtual_address);
	assert!(virtual_address % BasePageSize::SIZE == 0, "Virtual address {:#X} is not a multiple of {:#X}", virtual_address, BasePageSize::SIZE);
	assert!(size > 0);
	assert!(size % BasePageSize::SIZE == 0, "Size {:#X} is not a multiple of {:#X}", size, BasePageSize::SIZE);

	let _preemption = DisabledPreemption::new();
	let result = unsafe {
		POOL.maintain();
		KERNEL_FREE_LIST.reserve(virtual_address, size)
	};
	assert!(result.is_ok(), "Could not reserve {:#X} bytes of virtual memory at {:#X}", size, virtual_address);
}

pub fn task_heap_start() -> usize {
	KERNEL_VIRTUAL_MEMORY_END
}

pub fn task_heap_end() -> usize {
	TASK_VIRTUAL_MEMORY_END
}
<|endoftext|>


<commit_before>use addressable::Addressable;
use addressable::AddressableUtil;
use ram::Ram;

static NMI_VECTOR: u16 = 0xfffa;
static RESET_VECTOR: u16 = 0xfffc;
static IRQ_VECTOR: u16 = 0xfffe;

struct Registers {
	pc: u16,				// program counter
	ac: u8,					// accumulator
	x: u8,					// x register
	y: u8,					// y register
	sr: u8,					// status register (NV-BDIZC: Negative, oVerflow, Break, Decimal, Interrupt, Zero, Carry)
	sp: u8,					// stack pointer
}

enum Operand {
	Implied,							// OPC				// operand implied
	Immediate(u8),						// OPC #$BB			// operand is byte (BB)
	Accumulator,						// OPC A			// operand is AC
	Relative(i8),						// OPC $BB			// branch target is PC + offset (BB), bit 7 signifies negative offset
	Absolute(u16),						// OPC $HHLL		// operand is address $HHLL
	AbsoluteIndexedWithX(u16),			// OPC $HHLL,X		// operand is address $HHLL incremented by X with carry
	AbsoluteIndexedWithY(u16),			// OPC $HHLL,Y		// operand is address $HHLL incremented by Y with carry
	Indirect(u16),						// OPC ($HHLL)		// operand is effective address; effective address is value of address
	ZeroPage(u8),						// OPC $LL			// operand is address $00LL
	ZeroPageIndexedWithX(u8),			// OPC $LL,X		// operand is address $00LL incremented by X, no page transition
	ZeroPageIndexedWithY(u8),			// OPC $LL,Y		// operand is address $00LL incremented by Y, no page transition
	ZeroPageIndexedWithXIndirect(u8),	// OPC ($LL,X)		// operand is effective address; effective address is $00LL incremented by X without carry
	ZeroPageIndirectIndexedWithY(u8),	// OPC ($LL),Y		// operand is effective address incremented by Y with carry; effective address is word at $00LL
}

impl Operand {
	fn addr (&self, cpu: &Mos6502) -> u16 {
		match * self {
			Implied								=> fail!("mos6510: Implied operand is never targetted to an address"),
			Immediate(_)						=> fail!("mos6510: Immediade operand is never targetted to an address"),
			Accumulator							=> fail!("mos6510: Accumulator operand is never targetted to an address"),
			Relative(offset)					=> cpu.reg.pc + offset as u16,
			Absolute(addr)						=> addr,
			AbsoluteIndexedWithX(addr)			=> addr + cpu.reg.x as u16,
			AbsoluteIndexedWithY(addr)			=> addr + cpu.reg.y as u16,
			Indirect(addr)						=> cpu.get_le(addr),
			ZeroPage(addr)						=> addr as u16,
			ZeroPageIndexedWithX(addr)			=> (addr + cpu.reg.x) as u16,				// no page transition
			ZeroPageIndexedWithY(addr)			=> (addr + cpu.reg.y) as u16,				// no page transition
			ZeroPageIndexedWithXIndirect(addr)	=> cpu.get_le((addr + cpu.reg.x) as u16),	// no page transition
			ZeroPageIndirectIndexedWithY(addr)	=> { let iaddr: u16 = cpu.get_le(addr as u16); iaddr + cpu.reg.y as u16 },
		}
	}

	fn get (&self, cpu: &Mos6502) -> u8 {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never has a value"),
			Immediate(val)						=> val,
			Accumulator							=> cpu.reg.ac,
			Relative(_target)					=> fail!("mos6510: Relative operand never has a value"),
			op									=> { let addr = op.addr(cpu); cpu.get(addr) },
		}
	}

	fn set (&self, cpu: &mut Mos6502, val: u8) {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never sets a value"),
			Immediate(_)						=> fail!("mos6510: Immediate operand never sets a value"),
			Accumulator							=> cpu.reg.ac = val,
			Relative(_target)					=> fail!("mos6510: Relative operand never sets a value"),
			op									=> { let addr = op.addr(cpu); cpu.set(addr, val); },
		}
	}
}

pub struct Mos6502 {
	priv reg: Registers,		// internal CPU registers
	priv mem: Ram<u16>,			// memory as accessible to the CPU
}

impl Mos6502 {
	pub fn new () -> Mos6502 {
		Mos6502 {
			reg: Registers { pc: 0, ac: 0, x: 0, y: 0, sr: 0, sp: 0 },
			mem: Ram::new()
		}
	}
}

impl Addressable<u16> for Mos6502 {
	pub fn get (&self, addr: u16) -> u8 {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		self.mem.get(addr)
	}

	pub fn set (&mut self, addr: u16, data: u8) {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		self.mem.set(addr, data);
	}
}

pub struct Mos6510 {
	priv cpu: Mos6502,			// Core CPU
	priv port_ddr: u8,			// CPU port data direction register
	priv port_dat: u8,			// CPU port data register
}

impl Mos6510 {
	pub fn new () -> Mos6510 {
		Mos6510 { cpu: Mos6502::new(), port_ddr: 0, port_dat: 0 }
	}
}
<commit_msg>Added lifetime specifiers to cpus<commit_after>use addressable::Addressable;
use addressable::AddressableUtil;
use ram::Ram;

static NMI_VECTOR: u16 = 0xfffa;
static RESET_VECTOR: u16 = 0xfffc;
static IRQ_VECTOR: u16 = 0xfffe;

struct Registers {
	pc: u16,				// program counter
	ac: u8,					// accumulator
	x: u8,					// x register
	y: u8,					// y register
	sr: u8,					// status register (NV-BDIZC: Negative, oVerflow, Break, Decimal, Interrupt, Zero, Carry)
	sp: u8,					// stack pointer
}

enum Operand {
	Implied,							// OPC				// operand implied
	Immediate(u8),						// OPC #$BB			// operand is byte (BB)
	Accumulator,						// OPC A			// operand is AC
	Relative(i8),						// OPC $BB			// branch target is PC + offset (BB), bit 7 signifies negative offset
	Absolute(u16),						// OPC $HHLL		// operand is address $HHLL
	AbsoluteIndexedWithX(u16),			// OPC $HHLL,X		// operand is address $HHLL incremented by X with carry
	AbsoluteIndexedWithY(u16),			// OPC $HHLL,Y		// operand is address $HHLL incremented by Y with carry
	Indirect(u16),						// OPC ($HHLL)		// operand is effective address; effective address is value of address
	ZeroPage(u8),						// OPC $LL			// operand is address $00LL
	ZeroPageIndexedWithX(u8),			// OPC $LL,X		// operand is address $00LL incremented by X, no page transition
	ZeroPageIndexedWithY(u8),			// OPC $LL,Y		// operand is address $00LL incremented by Y, no page transition
	ZeroPageIndexedWithXIndirect(u8),	// OPC ($LL,X)		// operand is effective address; effective address is $00LL incremented by X without carry
	ZeroPageIndirectIndexedWithY(u8),	// OPC ($LL),Y		// operand is effective address incremented by Y with carry; effective address is word at $00LL
}

impl Operand {
	fn addr (&self, cpu: &Mos6502) -> u16 {
		match * self {
			Implied								=> fail!("mos6510: Implied operand is never targetted to an address"),
			Immediate(_)						=> fail!("mos6510: Immediade operand is never targetted to an address"),
			Accumulator							=> fail!("mos6510: Accumulator operand is never targetted to an address"),
			Relative(offset)					=> cpu.reg.pc + offset as u16,
			Absolute(addr)						=> addr,
			AbsoluteIndexedWithX(addr)			=> addr + cpu.reg.x as u16,
			AbsoluteIndexedWithY(addr)			=> addr + cpu.reg.y as u16,
			Indirect(addr)						=> cpu.get_le(addr),
			ZeroPage(addr)						=> addr as u16,
			ZeroPageIndexedWithX(addr)			=> (addr + cpu.reg.x) as u16,				// no page transition
			ZeroPageIndexedWithY(addr)			=> (addr + cpu.reg.y) as u16,				// no page transition
			ZeroPageIndexedWithXIndirect(addr)	=> cpu.get_le((addr + cpu.reg.x) as u16),	// no page transition
			ZeroPageIndirectIndexedWithY(addr)	=> { let iaddr: u16 = cpu.get_le(addr as u16); iaddr + cpu.reg.y as u16 },
		}
	}

	fn get (&self, cpu: &Mos6502) -> u8 {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never has a value"),
			Immediate(val)						=> val,
			Accumulator							=> cpu.reg.ac,
			Relative(_target)					=> fail!("mos6510: Relative operand never has a value"),
			op									=> { let addr = op.addr(cpu); cpu.get(addr) },
		}
	}

	fn set (&self, cpu: &mut Mos6502, val: u8) {
		match *self {
			Implied								=> fail!("mos6510: Implied operand never sets a value"),
			Immediate(_)						=> fail!("mos6510: Immediate operand never sets a value"),
			Accumulator							=> cpu.reg.ac = val,
			Relative(_target)					=> fail!("mos6510: Relative operand never sets a value"),
			op									=> { let addr = op.addr(cpu); cpu.set(addr, val); },
		}
	}
}

pub struct Mos6502<'self> {
	priv reg: Registers,		// internal CPU registers
	priv mem: Ram<u16>,			// memory as accessible to the CPU
}

impl<'self> Mos6502<'self> {
	pub fn new () -> Mos6502 {
		Mos6502 {
			reg: Registers { pc: 0, ac: 0, x: 0, y: 0, sr: 0, sp: 0 },
			mem: Ram::new()
		}
	}
}

impl<'self> Addressable<u16> for Mos6502<'self> {
	pub fn get (&self, addr: u16) -> u8 {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		self.mem.get(addr)
	}

	pub fn set (&mut self, addr: u16, data: u8) {
		// TODO: addresses $0000 (data direction) and $0001 (data) are hardwired for the processor I/O port
		self.mem.set(addr, data);
	}
}

pub struct Mos6510<'self> {
	priv cpu: Mos6502<'self>,	// Core CPU
	priv port_ddr: u8,			// CPU port data direction register
	priv port_dat: u8,			// CPU port data register
}

impl<'self> Mos6510<'self> {
	pub fn new () -> Mos6510 {
		Mos6510 { cpu: Mos6502::new(), port_ddr: 0, port_dat: 0 }
	}
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests;

use crate::fmt;
use crate::sync::{Condvar, Mutex};

/// A barrier enables multiple threads to synchronize the beginning
/// of some computation.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Barrier};
/// use std::thread;
///
/// let mut handles = Vec::with_capacity(10);
/// let barrier = Arc::new(Barrier::new(10));
/// for _ in 0..10 {
///     let c = Arc::clone(&barrier);
///     // The same messages will be printed together.
///     // You will NOT see any interleaving.
///     handles.push(thread::spawn(move|| {
///         println!("before wait");
///         c.wait();
///         println!("after wait");
///     }));
/// }
/// // Wait for other threads to finish.
/// for handle in handles {
///     handle.join().unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Barrier {
    lock: Mutex<BarrierState>,
    cvar: Condvar,
    num_threads: usize,
}

// The inner state of a double barrier
struct BarrierState {
    count: usize,
    generation_id: usize,
}

/// A `BarrierWaitResult` is returned by [`Barrier::wait()`] when all threads
/// in the [`Barrier`] have rendezvoused.
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
///
/// let barrier = Barrier::new(1);
/// let barrier_wait_result = barrier.wait();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Barrier {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Barrier").finish_non_exhaustive()
    }
}

impl Barrier {
    /// Creates a new barrier that can block a given number of threads.
    ///
    /// A barrier will block `n`-1 threads which call [`wait()`] and then wake
    /// up all threads at once when the `n`th thread calls [`wait()`].
    ///
    /// [`wait()`]: Barrier::wait
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::Barrier;
    ///
    /// let barrier = Barrier::new(10);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new(n: usize) -> Barrier {
        Barrier {
            lock: Mutex::new(BarrierState { count: 0, generation_id: 0 }),
            cvar: Condvar::new(),
            num_threads: n,
        }
    }

    /// Blocks the current thread until all threads have rendezvoused here.
    ///
    /// Barriers are re-usable after all threads have rendezvoused once, and can
    /// be used continuously.
    ///
    /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
    /// returns `true` from [`BarrierWaitResult::is_leader()`] when returning
    /// from this function, and all other threads will receive a result that
    /// will return `false` from [`BarrierWaitResult::is_leader()`].
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::{Arc, Barrier};
    /// use std::thread;
    ///
    /// let mut handles = Vec::with_capacity(10);
    /// let barrier = Arc::new(Barrier::new(10));
    /// for _ in 0..10 {
    ///     let c = Arc::clone(&barrier);
    ///     // The same messages will be printed together.
    ///     // You will NOT see any interleaving.
    ///     handles.push(thread::spawn(move|| {
    ///         println!("before wait");
    ///         c.wait();
    ///         println!("after wait");
    ///     }));
    /// }
    /// // Wait for other threads to finish.
    /// for handle in handles {
    ///     handle.join().unwrap();
    /// }
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn wait(&self) -> BarrierWaitResult {
        let mut lock = self.lock.lock().unwrap();
        let local_gen = lock.generation_id;
        lock.count += 1;
        if lock.count < self.num_threads {
            // We need a while loop to guard against spurious wakeups.
            // https://en.wikipedia.org/wiki/Spurious_wakeup
            while local_gen == lock.generation_id && lock.count < self.num_threads {
                lock = self.cvar.wait(lock).unwrap();
            }
            BarrierWaitResult(false)
        } else {
            lock.count = 0;
            lock.generation_id = lock.generation_id.wrapping_add(1);
            self.cvar.notify_all();
            BarrierWaitResult(true)
        }
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for BarrierWaitResult {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BarrierWaitResult").field("is_leader", &self.is_leader()).finish()
    }
}

impl BarrierWaitResult {
    /// Returns `true` if this thread is the "leader thread" for the call to
    /// [`Barrier::wait()`].
    ///
    /// Only one thread will have `true` returned from their result, all other
    /// threads will have `false` returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::Barrier;
    ///
    /// let barrier = Barrier::new(1);
    /// let barrier_wait_result = barrier.wait();
    /// println!("{:?}", barrier_wait_result.is_leader());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn is_leader(&self) -> bool {
        self.0
    }
}
<commit_msg>Remove unnecessary condition in Barrier::wait()<commit_after>#[cfg(test)]
mod tests;

use crate::fmt;
use crate::sync::{Condvar, Mutex};

/// A barrier enables multiple threads to synchronize the beginning
/// of some computation.
///
/// # Examples
///
/// ```
/// use std::sync::{Arc, Barrier};
/// use std::thread;
///
/// let mut handles = Vec::with_capacity(10);
/// let barrier = Arc::new(Barrier::new(10));
/// for _ in 0..10 {
///     let c = Arc::clone(&barrier);
///     // The same messages will be printed together.
///     // You will NOT see any interleaving.
///     handles.push(thread::spawn(move|| {
///         println!("before wait");
///         c.wait();
///         println!("after wait");
///     }));
/// }
/// // Wait for other threads to finish.
/// for handle in handles {
///     handle.join().unwrap();
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Barrier {
    lock: Mutex<BarrierState>,
    cvar: Condvar,
    num_threads: usize,
}

// The inner state of a double barrier
struct BarrierState {
    count: usize,
    generation_id: usize,
}

/// A `BarrierWaitResult` is returned by [`Barrier::wait()`] when all threads
/// in the [`Barrier`] have rendezvoused.
///
/// # Examples
///
/// ```
/// use std::sync::Barrier;
///
/// let barrier = Barrier::new(1);
/// let barrier_wait_result = barrier.wait();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for Barrier {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Barrier").finish_non_exhaustive()
    }
}

impl Barrier {
    /// Creates a new barrier that can block a given number of threads.
    ///
    /// A barrier will block `n`-1 threads which call [`wait()`] and then wake
    /// up all threads at once when the `n`th thread calls [`wait()`].
    ///
    /// [`wait()`]: Barrier::wait
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::Barrier;
    ///
    /// let barrier = Barrier::new(10);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new(n: usize) -> Barrier {
        Barrier {
            lock: Mutex::new(BarrierState { count: 0, generation_id: 0 }),
            cvar: Condvar::new(),
            num_threads: n,
        }
    }

    /// Blocks the current thread until all threads have rendezvoused here.
    ///
    /// Barriers are re-usable after all threads have rendezvoused once, and can
    /// be used continuously.
    ///
    /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
    /// returns `true` from [`BarrierWaitResult::is_leader()`] when returning
    /// from this function, and all other threads will receive a result that
    /// will return `false` from [`BarrierWaitResult::is_leader()`].
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::{Arc, Barrier};
    /// use std::thread;
    ///
    /// let mut handles = Vec::with_capacity(10);
    /// let barrier = Arc::new(Barrier::new(10));
    /// for _ in 0..10 {
    ///     let c = Arc::clone(&barrier);
    ///     // The same messages will be printed together.
    ///     // You will NOT see any interleaving.
    ///     handles.push(thread::spawn(move|| {
    ///         println!("before wait");
    ///         c.wait();
    ///         println!("after wait");
    ///     }));
    /// }
    /// // Wait for other threads to finish.
    /// for handle in handles {
    ///     handle.join().unwrap();
    /// }
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn wait(&self) -> BarrierWaitResult {
        let mut lock = self.lock.lock().unwrap();
        let local_gen = lock.generation_id;
        lock.count += 1;
        if lock.count < self.num_threads {
            // We need a while loop to guard against spurious wakeups.
            // https://en.wikipedia.org/wiki/Spurious_wakeup
            while local_gen == lock.generation_id {
                lock = self.cvar.wait(lock).unwrap();
            }
            BarrierWaitResult(false)
        } else {
            lock.count = 0;
            lock.generation_id = lock.generation_id.wrapping_add(1);
            self.cvar.notify_all();
            BarrierWaitResult(true)
        }
    }
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for BarrierWaitResult {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("BarrierWaitResult").field("is_leader", &self.is_leader()).finish()
    }
}

impl BarrierWaitResult {
    /// Returns `true` if this thread is the "leader thread" for the call to
    /// [`Barrier::wait()`].
    ///
    /// Only one thread will have `true` returned from their result, all other
    /// threads will have `false` returned.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::sync::Barrier;
    ///
    /// let barrier = Barrier::new(1);
    /// let barrier_wait_result = barrier.wait();
    /// println!("{:?}", barrier_wait_result.is_leader());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn is_leader(&self) -> bool {
        self.0
    }
}
<|endoftext|>


<commit_before>extern crate calx;
extern crate rand;
extern crate serde_json;

use calx::WeightedChoice;
use rand::{Rng, XorShiftRng};
use std::collections::HashMap;

fn splits_into(space: usize, line: &str, parts: &[&str]) {
    use calx::split_line;

    split_line(line, |_| 1.0, space as f32)
        .zip(parts)
        .all(|(actual, &expected)| {
            assert_eq!(expected, actual);
            true
        });

    assert_eq!(parts.len(), split_line(line, |_| 1.0, space as f32).count());
}

#[test]
fn test_split_line() {
    splits_into(10, "", &[""]);
    splits_into(0, "", &[""]);
    splits_into(0, "abc", &["a", "b", "c"]);
    splits_into(10, "abc", &["abc"]);
    splits_into(6, "the cat", &["the", "cat"]);
    splits_into(7, "the cat", &["the cat"]);
    splits_into(10, "the   cat", &["the   cat"]);
    splits_into(5, "the     cat", &["the", "cat"]);
    splits_into(5, "the \t cat", &["the", "cat"]);
    splits_into(4, "deadbeef", &["dead", "beef"]);
    splits_into(5, "the \t cat", &["the", "cat"]);
}

#[test]
fn test_weighted_choice() {
    let mut histogram: HashMap<u32, f32> = HashMap::new();
    let mut rng: XorShiftRng = calx::seeded_rng(&"1234");
    let items = vec![1u32, 2, 3, 4];
    let n = 1000;

    for _ in 0..n {
        let choice = *items
            .iter()
            .weighted_choice(&mut rng, |&&x| x as f32)
            .unwrap();
        *histogram.entry(choice).or_insert(0.0) += 1.0;
    }

    let measurement = vec![
        histogram[&1] / n as f32,
        histogram[&2] / n as f32,
        histogram[&3] / n as f32,
        histogram[&4] / n as f32,
    ];

    // The weights match the values because 1+2+3+4 = 10.
    let ideal = vec![0.1, 0.2, 0.3, 0.4];

    let err = measurement
        .iter()
        .zip(ideal)
        .map(|(x, y)| (x - y) * (x - y))
        .sum::<f32>()
        / measurement.len() as f32;
    println!("Mean square error from expected: {}", err);
    assert!(err < 0.0001);
}

#[test]
fn test_random_permutation() {
    use calx::RandomPermutation;
    let perm: Vec<usize> = RandomPermutation::new(&mut rand::thread_rng(), 100).collect();
    let mut sorted = perm.clone();
    sorted.sort();
    assert_eq!(sorted, (0..100).collect::<Vec<usize>>());

    // XXX: It is technically possible to get the unpermutating permutation and fail here.
    // Not very likely though.
    assert_ne!(perm, sorted);
    sorted.reverse();
    assert_ne!(perm, sorted);
}

#[test]
fn test_bit_spread() {
    use calx::{compact_bits_by_2, spread_bits_by_2};
    use std::u16;

    for x in 0..(u16::MAX as u32 + 1) {
        if x > 1 {
            assert_ne!(x, spread_bits_by_2(x));
        }
        assert_eq!(compact_bits_by_2(spread_bits_by_2(x)), x);
    }
}

#[test]
fn test_retry_gen() {
    use calx::retry_gen;

    fn failing_gen<R: Rng>(rng: &mut R) -> Result<f32, ()> {
        let x: f32 = rng.gen();
        if x < 0.1 {
            Ok(x)
        } else {
            Err(())
        }
    }

    assert!(retry_gen(1000, &mut rand::thread_rng(), failing_gen).is_ok());
}
<commit_msg>Rng 0.6 fix<commit_after>extern crate calx;
extern crate rand;
extern crate serde_json;

use calx::WeightedChoice;
use rand::Rng;
use rand_xorshift::XorShiftRng;
use std::collections::HashMap;

fn splits_into(space: usize, line: &str, parts: &[&str]) {
    use calx::split_line;

    split_line(line, |_| 1.0, space as f32)
        .zip(parts)
        .all(|(actual, &expected)| {
            assert_eq!(expected, actual);
            true
        });

    assert_eq!(parts.len(), split_line(line, |_| 1.0, space as f32).count());
}

#[test]
fn test_split_line() {
    splits_into(10, "", &[""]);
    splits_into(0, "", &[""]);
    splits_into(0, "abc", &["a", "b", "c"]);
    splits_into(10, "abc", &["abc"]);
    splits_into(6, "the cat", &["the", "cat"]);
    splits_into(7, "the cat", &["the cat"]);
    splits_into(10, "the   cat", &["the   cat"]);
    splits_into(5, "the     cat", &["the", "cat"]);
    splits_into(5, "the \t cat", &["the", "cat"]);
    splits_into(4, "deadbeef", &["dead", "beef"]);
    splits_into(5, "the \t cat", &["the", "cat"]);
}

#[test]
fn test_weighted_choice() {
    let mut histogram: HashMap<u32, f32> = HashMap::new();
    let mut rng: XorShiftRng = calx::seeded_rng(&"1234");
    let items = vec![1u32, 2, 3, 4];
    let n = 1000;

    for _ in 0..n {
        let choice = *items
            .iter()
            .weighted_choice(&mut rng, |&&x| x as f32)
            .unwrap();
        *histogram.entry(choice).or_insert(0.0) += 1.0;
    }

    let measurement = vec![
        histogram[&1] / n as f32,
        histogram[&2] / n as f32,
        histogram[&3] / n as f32,
        histogram[&4] / n as f32,
    ];

    // The weights match the values because 1+2+3+4 = 10.
    let ideal = vec![0.1, 0.2, 0.3, 0.4];

    let err = measurement
        .iter()
        .zip(ideal)
        .map(|(x, y)| (x - y) * (x - y))
        .sum::<f32>()
        / measurement.len() as f32;
    println!("Mean square error from expected: {}", err);
    assert!(err < 0.0001);
}

#[test]
fn test_random_permutation() {
    use calx::RandomPermutation;
    let perm: Vec<usize> = RandomPermutation::new(&mut rand::thread_rng(), 100).collect();
    let mut sorted = perm.clone();
    sorted.sort();
    assert_eq!(sorted, (0..100).collect::<Vec<usize>>());

    // XXX: It is technically possible to get the unpermutating permutation and fail here.
    // Not very likely though.
    assert_ne!(perm, sorted);
    sorted.reverse();
    assert_ne!(perm, sorted);
}

#[test]
fn test_bit_spread() {
    use calx::{compact_bits_by_2, spread_bits_by_2};
    use std::u16;

    for x in 0..(u16::MAX as u32 + 1) {
        if x > 1 {
            assert_ne!(x, spread_bits_by_2(x));
        }
        assert_eq!(compact_bits_by_2(spread_bits_by_2(x)), x);
    }
}

#[test]
fn test_retry_gen() {
    use calx::retry_gen;

    fn failing_gen<R: Rng>(rng: &mut R) -> Result<f32, ()> {
        let x: f32 = rng.gen();
        if x < 0.1 {
            Ok(x)
        } else {
            Err(())
        }
    }

    assert!(retry_gen(1000, &mut rand::thread_rng(), failing_gen).is_ok());
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};

pub static HEADER: &str = include_str!("include/cxx.h");

pub fn get(guard: &str) -> &'static str {
    let ifndef = format!("#ifndef {}", guard);
    let endif = format!("#endif // {}", guard);
    let begin = find_line(&ifndef);
    let end = find_line(&endif);
    if let (Some(begin), Some(end)) = (begin, end) {
        &HEADER[begin..end + endif.len()]
    } else {
        panic!("not found in cxx.h header: {}", guard)
    }
}

fn find_line(line: &str) -> Option<usize> {
    let mut offset = 0;
    loop {
        offset += HEADER[offset..].find(line)?;
        let rest = &HEADER[offset + line.len()..];
        if rest.starts_with('\n') || rest.starts_with('\r') {
            return Some(offset);
        }
        offset += line.len();
    }
}

#[derive(Default, PartialEq)]
pub struct Includes {
    custom: Vec<String>,
    pub array: bool,
    pub cstddef: bool,
    pub cstdint: bool,
    pub cstring: bool,
    pub exception: bool,
    pub memory: bool,
    pub string: bool,
    pub vector: bool,
    pub type_traits: bool,
    pub utility: bool,
    pub base_tsd: bool,
}

impl Includes {
    pub fn new() -> Self {
        Includes::default()
    }

    pub fn insert(&mut self, include: String) {
        self.custom.push(include);
    }
}

impl Extend<String> for Includes {
    fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
        self.custom.extend(iter);
    }
}

impl Display for Includes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for include in &self.custom {
            writeln!(f, "#include \"{}\"", include.escape_default())?;
        }
        if self.array {
            writeln!(f, "#include <array>")?;
        }
        if self.cstddef {
            writeln!(f, "#include <cstddef>")?;
        }
        if self.cstdint {
            writeln!(f, "#include <cstdint>")?;
        }
        if self.cstring {
            writeln!(f, "#include <cstring>")?;
        }
        if self.exception {
            writeln!(f, "#include <exception>")?;
        }
        if self.memory {
            writeln!(f, "#include <memory>")?;
        }
        if self.string {
            writeln!(f, "#include <string>")?;
        }
        if self.type_traits {
            writeln!(f, "#include <type_traits>")?;
        }
        if self.utility {
            writeln!(f, "#include <utility>")?;
        }
        if self.base_tsd {
            writeln!(f, "#if defined(_WIN32)")?;
            writeln!(f, "#include <BaseTsd.h>")?;
            writeln!(f, "#endif")?;
        }
        if *self != Self::default() {
            writeln!(f)?;
        }
        Ok(())
    }
}
<commit_msg>Place vector include in sorted order<commit_after>use std::fmt::{self, Display};

pub static HEADER: &str = include_str!("include/cxx.h");

pub fn get(guard: &str) -> &'static str {
    let ifndef = format!("#ifndef {}", guard);
    let endif = format!("#endif // {}", guard);
    let begin = find_line(&ifndef);
    let end = find_line(&endif);
    if let (Some(begin), Some(end)) = (begin, end) {
        &HEADER[begin..end + endif.len()]
    } else {
        panic!("not found in cxx.h header: {}", guard)
    }
}

fn find_line(line: &str) -> Option<usize> {
    let mut offset = 0;
    loop {
        offset += HEADER[offset..].find(line)?;
        let rest = &HEADER[offset + line.len()..];
        if rest.starts_with('\n') || rest.starts_with('\r') {
            return Some(offset);
        }
        offset += line.len();
    }
}

#[derive(Default, PartialEq)]
pub struct Includes {
    custom: Vec<String>,
    pub array: bool,
    pub cstddef: bool,
    pub cstdint: bool,
    pub cstring: bool,
    pub exception: bool,
    pub memory: bool,
    pub string: bool,
    pub type_traits: bool,
    pub utility: bool,
    pub vector: bool,
    pub base_tsd: bool,
}

impl Includes {
    pub fn new() -> Self {
        Includes::default()
    }

    pub fn insert(&mut self, include: String) {
        self.custom.push(include);
    }
}

impl Extend<String> for Includes {
    fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
        self.custom.extend(iter);
    }
}

impl Display for Includes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for include in &self.custom {
            writeln!(f, "#include \"{}\"", include.escape_default())?;
        }
        if self.array {
            writeln!(f, "#include <array>")?;
        }
        if self.cstddef {
            writeln!(f, "#include <cstddef>")?;
        }
        if self.cstdint {
            writeln!(f, "#include <cstdint>")?;
        }
        if self.cstring {
            writeln!(f, "#include <cstring>")?;
        }
        if self.exception {
            writeln!(f, "#include <exception>")?;
        }
        if self.memory {
            writeln!(f, "#include <memory>")?;
        }
        if self.string {
            writeln!(f, "#include <string>")?;
        }
        if self.type_traits {
            writeln!(f, "#include <type_traits>")?;
        }
        if self.utility {
            writeln!(f, "#include <utility>")?;
        }
        if self.base_tsd {
            writeln!(f, "#if defined(_WIN32)")?;
            writeln!(f, "#include <BaseTsd.h>")?;
            writeln!(f, "#endif")?;
        }
        if *self != Self::default() {
            writeln!(f)?;
        }
        Ok(())
    }
}
<|endoftext|>