<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod std;
extern mod extra;

use extra::test::{TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use extra::getopts::{getopts, reqopt};
use std::{os, run, io, str};
use std::cell::Cell;
use std::os::list_dir_path;

#[deriving(Clone)]
struct Config {
    source_dir: ~str,
    filter: Option<~str>
}

fn main() {
    let args = os::args();
    let config = parse_config(args);
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    run_tests_console(&opts, tests);
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt("source-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail!(f.to_err_msg())
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some((*matches.free.head()).clone())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        ratchet_metrics: None,
        ratchet_noise_percent: None,
        save_metrics: None,
        test_shard: None,
        logfile: None
    }
}

fn find_tests(config: Config) -> ~[TestDescAndFn] {
    let mut files = list_dir_path(&Path::new(config.source_dir));
    // FIXME (#1094): not the right way to transform a path
    files.retain( |file| file.display().to_str().ends_with(".html") );
    return files.map(|file| make_test(file.display().to_str()) );
}

fn make_test(file: ~str) -> TestDescAndFn {
    let f = Cell::new(file.clone());
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file),
            ignore: false,
            should_fail: false
        },
        testfn: DynTestFn(|| { run_test(f.take()) })
    }
}

fn run_test(file: ~str) {
    let path = os::make_absolute(&Path::new(file));
    // FIXME (#1094): not the right way to transform a path
    let infile = ~"file://" + path.display().to_str();
    let res = run::process_output("./servo", [infile]);
    let out = str::from_utf8(res.output);
    io::print(out);
    let lines: ~[&str] = out.split_iter('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            fail!(line);
        }
    }
}
<commit_msg>Use headless mode for content tests<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern mod std;
extern mod extra;

use extra::test::{TestOpts, run_tests_console, TestDesc, TestDescAndFn, DynTestFn, DynTestName};
use extra::getopts::{getopts, reqopt};
use std::{os, run, io, str};
use std::cell::Cell;
use std::os::list_dir_path;

#[deriving(Clone)]
struct Config {
    source_dir: ~str,
    filter: Option<~str>
}

fn main() {
    let args = os::args();
    let config = parse_config(args);
    let opts = test_options(config.clone());
    let tests = find_tests(config);
    run_tests_console(&opts, tests);
}

fn parse_config(args: ~[~str]) -> Config {
    let args = args.tail();
    let opts = ~[reqopt("source-dir")];
    let matches = match getopts(args, opts) {
      Ok(m) => m,
      Err(f) => fail!(f.to_err_msg())
    };

    Config {
        source_dir: matches.opt_str("source-dir").unwrap(),
        filter: if matches.free.is_empty() {
            None
        } else {
            Some((*matches.free.head()).clone())
        }
    }
}

fn test_options(config: Config) -> TestOpts {
    TestOpts {
        filter: config.filter,
        run_ignored: false,
        run_tests: true,
        run_benchmarks: false,
        ratchet_metrics: None,
        ratchet_noise_percent: None,
        save_metrics: None,
        test_shard: None,
        logfile: None
    }
}

fn find_tests(config: Config) -> ~[TestDescAndFn] {
    let mut files = list_dir_path(&Path::new(config.source_dir));
    // FIXME (#1094): not the right way to transform a path
    files.retain( |file| file.display().to_str().ends_with(".html") );
    return files.map(|file| make_test(file.display().to_str()) );
}

fn make_test(file: ~str) -> TestDescAndFn {
    let f = Cell::new(file.clone());
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(file),
            ignore: false,
            should_fail: false
        },
        testfn: DynTestFn(|| { run_test(f.take()) })
    }
}

fn run_test(file: ~str) {
    let path = os::make_absolute(&Path::new(file));
    // FIXME (#1094): not the right way to transform a path
    let infile = ~"file://" + path.display().to_str();
    let res = run::process_output("./servo", [~"-z", infile]);
    let out = str::from_utf8(res.output);
    io::print(out);
    let lines: ~[&str] = out.split_iter('\n').collect();
    for &line in lines.iter() {
        if line.contains("TEST-UNEXPECTED-FAIL") {
            fail!(line);
        }
    }
}
<|endoftext|>


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

use std::thread;
use std::thread::JoinHandle;
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
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 epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use ipc::*;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT);

pub fn begin<T: ToSocketAddrs + Send + 'static>(address: T, handler: Box<EventHandler>) {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let epfd = create_epoll_instance();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sckts1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(&handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sckts1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                trace!("New connection received");
                // Create new socket
                match NbetStream::new(stream) {
                    Ok(nb_stream) => {
                        let socket = Socket::new(nb_stream);
                        let socket_ptr;
                        // Add to master list
                        { // Begin Mutex lock
                            let mut guard = match socket.lock() {
                                Ok(guard) => guard,
                                Err(poisoned) => {
                                    warn!("SocketList Mutex failed, using anyway...");
                                    poisoned.into_inner()
                                }
                            };
                            let socket_list = guard.deref_mut();
                            socket_list.push_back(socket.clone());
                            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
                        } // End Mutex lock

                        // Add to epoll
                        let sfd = socket.raw_fd();
                        let mut event = EpollEvent {
                            data: socket_ptr,
                            events: EVENTS
                        };
                        match epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event) {
                            Ok(()) => trace!("New socket added to epoll list"),
                            Err(e) => warn!("Epoll CtrlError during add: {}", e)
                        };
                    }
                    Err(e) => warn!("Error creating nbstream: {}", e)
                }
            }
            Err(e) => warn!("Error encountered during TCP connection: {}", e)
        }
    }
    drop(listener);
}

fn create_epoll_instance() -> RawFd {
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    result.unwrap();
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // 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 {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
    info!("epoll_wait thread finished");
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Pull out the socket
        let socket;
        { // Begin Mutex lock
            let mut guard = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            let socket_ptr = event.data as *mut Socket;
            unsafe { socket = *socket_ptr.clone(); }
        } // End Mutex lock

        if event.events & DROP_EVENT {
            let t_epfd = epfd.clone();
            let socketfd = socket.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socket, socket_list);
            });
        } else if event.events & READ_EVENT {
            let t_epfd = epfd.clone();
            let socketfd = socket.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            pool.run(move || {
                match socket.read() {
                    Ok(_) => {
                        for msg in socket.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("SocketList Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(socket, socket_list, msg.clone());
                            } // Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(socket, socket_list);
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(socket.id());
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("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 mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds 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(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket: Socket, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

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

    if !s_found { 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);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<commit_msg>TODO note added<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/.

use std::thread;
use std::thread::JoinHandle;
use std::net::{TcpListener, TcpStream, ToSocketAddrs};
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 epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use ipc::*;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT);

pub fn begin<T: ToSocketAddrs + Send + 'static>(address: T, handler: Box<EventHandler>) {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let epfd = create_epoll_instance();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sckts1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(&handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sckts1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                trace!("New connection received");
                // Create new socket
                match NbetStream::new(stream) {
                    Ok(nb_stream) => {
                        let socket = Socket::new(nb_stream);
                        let socket_ptr;
                        // Add to master list
                        { // Begin Mutex lock
                            let mut guard = match socket.lock() {
                                Ok(guard) => guard,
                                Err(poisoned) => {
                                    warn!("SocketList Mutex failed, using anyway...");
                                    poisoned.into_inner()
                                }
                            };
                            let socket_list = guard.deref_mut();
                            socket_list.push_back(socket.clone());
                            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
                        } // End Mutex lock

                        // Add to epoll
                        let sfd = socket.raw_fd();
                        let mut event = EpollEvent {
                            data: socket_ptr,
                            events: EVENTS
                        };
                        match epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event) {
                            Ok(()) => trace!("New socket added to epoll list"),
                            Err(e) => warn!("Epoll CtrlError during add: {}", e)
                        };
                    }
                    Err(e) => warn!("Error creating nbstream: {}", e)
                }
            }
            Err(e) => warn!("Error encountered during TCP connection: {}", e)
        }
    }
    drop(listener);
}

fn create_epoll_instance() -> RawFd {
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    result.unwrap();
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // 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 {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
    info!("epoll_wait thread finished");
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Pull out the socket
        let socket;
        { // Begin Mutex lock
            let mut guard = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            let socket_ptr = event.data as *mut Socket;
            unsafe { socket = *socket_ptr.clone(); }
        } // End Mutex lock

        if event.events & DROP_EVENT {
            let t_epfd = epfd.clone();
            let socketfd = socket.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socket, socket_list);
            });
        } else if event.events & READ_EVENT {
            let t_epfd = epfd.clone();
            let socketfd = socket.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            pool.run(move || {
                match socket.read() {
                    Ok(_) => {
                        for msg in socket.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("SocketList Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(socket, socket_list, msg.clone());
                            } // Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // TODO - Add socket fd back to epoll
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(socket, socket_list);
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(socket.id());
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("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 mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds 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(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket: Socket, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

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

    if !s_found { 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);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Fibonacci_sequence
#[cfg(not(test))]
fn main() {
    let fns=vec![
        (fib_recursive, "recursive implementation"),
        (fib_tail_recursive, "tail recursive implementation"),
        (fib_iterative, "iterative implementation")];

    for (f, desc) in fns.move_iter() {
        let r: Vec<u64> = range(0u64, 10).map(|i| f(i)).collect();
        println!("{}:\n {}\n", desc, r);
    }
}

// Fibonacci "classic" recursive version
// not tail recursive (it's going to blow the stack
// for n too high
fn fib_recursive(n: u64) -> u64 {
    match n {
        n if n<2 => n,
        m => fib_recursive(m - 1) + fib_recursive(m-2)
    }
}

// tail recursive version
fn fib_tail_recursive(n: u64) -> u64 {
        fn in_fib(n : u64, current : u64, next : u64) -> u64 {
            match n {
                0 => current,
                _ => in_fib(n - 1, next, current + next)
            }
        }
        in_fib(n, 0, 1)
}

// iterative version
fn fib_iterative(n: u64) -> u64 {
    let (mut fib1, mut fib2) = (0u64, 1u64);
    let mut fib = n;

    for _ in range(1u64,n) {
        fib = fib1 + fib2;
        fib1 = fib2;
        fib2 = fib;
    }
    fib
}

#[cfg(test)]
fn tester(f: fn(u64)->u64) -> bool {
    let exp = [0u64,1,1,2,3,5,8,13,21,34];
    for i in range(0u, 10) {
        let ret=f(i as u64);
        assert_eq!(ret, exp[i]);
    }
    true
}

#[test]
fn fib_values() {
    let fns=vec![fib_recursive, fib_tail_recursive, fib_iterative];
    fns.move_iter()
        .advance(|f| tester(f));
}<commit_msg>refactoring per suggestions<commit_after>// Implements http://rosettacode.org/wiki/Fibonacci_sequence
#[cfg(not(test))]
fn main() {
    let fns=vec![
        (fib_recursive, "recursive implementation"),
        (fib_tail_recursive, "tail recursive implementation"),
        (fib_iterative, "iterative implementation")];

    for &(f, desc) in fns.iter() {
        let r: Vec<u64> = range(0u64, 10).map(|i| f(i)).collect();
        println!("{}:\n {}\n", desc, r);
    }
}

// Fibonacci "classic" recursive version
// not tail recursive (it's going to blow the stack
// for n too high)
fn fib_recursive(n: u64) -> u64 {
    match n {
        n if n<2 => n,
        m => fib_recursive(m - 1) + fib_recursive(m-2)
    }
}

// tail recursive version
fn fib_tail_recursive(n: u64) -> u64 {
        fn in_fib(n : u64, current : u64, next : u64) -> u64 {
            match n {
                0 => current,
                _ => in_fib(n - 1, next, current + next)
            }
        }
        in_fib(n, 0, 1)
}

// iterative version
fn fib_iterative(n: u64) -> u64 {
    let (mut fib1, mut fib2) = (0u64, 1u64);
    let mut fib = n;

    for _ in range(1u64,n) {
        fib = fib1 + fib2;
        fib1 = fib2;
        fib2 = fib;
    }
    fib
}

// helper function to test that all versions of the fib function
// return the expected values.
#[cfg(test)]
fn tester(f: fn(u64)->u64) {
    let exp = [0u64,1,1,2,3,5,8,13,21,34];
    for i in range(0u64, 10) {
        let ret=f(i);
        assert_eq!(ret, exp[i as uint]);
    }
}

#[test]
fn fib_values() {
    let fns=vec![fib_recursive, fib_tail_recursive, fib_iterative];
    fns.iter()
        .advance(|&f| {tester(f); true});
}<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Generators.
//!
//! Generators allow repeatedly suspending the execution of a function,
//! returning a value to the caller, and resuming the suspended function
//! afterwards.

use core::marker::PhantomData;
use core::{ptr, mem};

use stack;
use context::Context;

#[derive(Debug, Clone, Copy)]
pub enum State {
  /// Generator can be resumed. This is the initial state.
  Runnable,
  /// Generator cannot be resumed. This is the state of the generator after
  /// the generator function has returned or panicked.
  Unavailable
}

/// Generator wraps a function and allows suspending its execution more than once, returning
/// a value each time.
///
/// The first time `resume(input0)` is called, the function is called as `f(yielder, input0)`.
/// It runs until it suspends its execution through `yielder.suspend(output0)`, after which
/// `resume(input0)` returns `output0`. The function can be resumed again using `resume(input1)`,
/// after which `yielder.suspend(output0)` returns `input1`, and so on. Once the function returns,
/// the `resume()` call will return `None`, and it will return `None` every time it is called
/// after that.
///
/// If the generator function panics, the panic is propagated through the `resume()` call as usual.
///
/// After the generator function returns or panics, it is safe to reclaim the generator stack
/// using `unwrap()`.
///
/// `state()` can be used to determine whether the generator function has returned;
/// the state is `State::Runnable` after creation and suspension, and `State::Unavailable`
/// once the generator function returns or panics.
///
/// When the input type is `()`, a generator implements the Iterator trait.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut add_one = Generator::new(stack, move |yielder, mut input| {
///   loop {
///     if input == 0 { break }
///     input = yielder.suspend(input + 1)
///   }
/// });
/// println!("{:?}", add_one.resume(2)); // prints Some(3)
/// println!("{:?}", add_one.resume(3)); // prints Some(4)
/// println!("{:?}", add_one.resume(0)); // prints None
/// ```
///
/// # Iterator example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut nat = Generator::new(stack, move |yielder, ()| {
///   for i in 1.. { yielder.suspend(i) }
/// });
/// println!("{:?}", nat.next()); // prints Some(0)
/// println!("{:?}", nat.next()); // prints Some(1)
/// println!("{:?}", nat.next()); // prints Some(2)
/// ```
#[derive(Debug)]
pub struct Generator<Input: Send, Output: Send, Stack: stack::Stack> {
  state:   State,
  context: Context<Stack>,
  phantom: (PhantomData<*const Input>, PhantomData<*const Output>)
}

impl<Input, Output, Stack> Generator<Input, Output, Stack>
    where Input: Send, Output: Send, Stack: stack::Stack {
  /// Creates a new generator.
  ///
  /// See also the [contract](../trait.GuardedStack.html) that needs to be fulfilled by `stack`.
  pub fn new<F>(stack: Stack, f: F) -> Generator<Input, Output, Stack>
      where Stack: stack::GuardedStack,
            F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) + Send {
    unsafe { Generator::unsafe_new(stack, f) }
  }

  /// Same as `new`, but does not require `stack` to have a guard page.
  ///
  /// This function is unsafe because the generator function can easily violate
  /// memory safety by overflowing the stack. It is useful in environments where
  /// guarded stacks do not exist, e.g. in absence of an MMU.
  ///
  /// See also the [contract](../trait.Stack.html) that needs to be fulfilled by `stack`.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Input, Output, Stack>
      where F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) + Send {
    unsafe extern "C" fn generator_wrapper<Input, Output, Stack, F>(env: usize) -> !
        where Input: Send, Output: Send, Stack: stack::Stack,
              F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) {
      // Retrieve our environment from the callee and return control to it.
      let (mut yielder, f) = ptr::read(env as *mut (Yielder<Input, Output, Stack>, F));
      let data = Context::swap(yielder.context, yielder.context, 0);
      // See the second half of Yielder::suspend_bare.
      let (new_context, input) = ptr::read(data as *mut (*mut Context<Stack>, Input));
      yielder.context = new_context as *mut Context<Stack>;
      // Run the body of the generator.
      f(&mut yielder, input);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.suspend_bare(None); }
    }

    let mut generator = Generator {
      state:   State::Runnable,
      context: Context::new(stack, generator_wrapper::<Input, Output, Stack, F>),
      phantom: (PhantomData, PhantomData)
    };

    // Transfer environment to the callee.
    let mut env = (Yielder::new(&mut generator.context), f);
    Context::swap(&mut generator.context, &generator.context,
                  &mut env as *mut (Yielder<Input, Output, Stack>, F) as usize);
    mem::forget(env);

    generator
  }

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  pub fn resume(&mut self, input: Input) -> Option<Output> {
    match self.state {
      State::Runnable => {
        // Set the state to Unavailable. Since we have exclusive access to the generator,
        // the only case where this matters is the generator function panics, after which
        // it must not be invocable again.
        self.state = State::Unavailable;

        // Switch to the generator function, and retrieve the yielded value.
        let val = unsafe {
          let mut data_in = (&mut self.context as *mut Context<Stack>, input);
          let data_out =
            ptr::read(Context::swap(&mut self.context, &self.context,
                                    &mut data_in as *mut (*mut Context<Stack>, Input)  as usize)
                      as *mut Option<Output>);
          mem::forget(data_in);
          data_out
        };

        // Unless the generator function has returned, it can be switched to again, so
        // set the state to Runnable.
        if val.is_some() { self.state = State::Runnable }

        val
      }
      State::Unavailable => None
    }
  }

  /// Returns the state of the generator.
  #[inline]
  pub fn state(&self) -> State { self.state }

  /// Extracts the stack from a generator when the generator function has returned.
  /// If the generator function has not returned
  /// (i.e. `self.state() == State::Runnable`), panics.
  pub fn unwrap(self) -> Stack {
    match self.state {
      State::Runnable    => panic!("Argh! Bastard! Don't touch that!"),
      State::Unavailable => unsafe { self.context.unwrap() }
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Input: Send, Output: Send, Stack: stack::Stack> {
  context: *mut Context<Stack>,
  phantom: (PhantomData<*const Input>, PhantomData<*const Output>)
}

impl<Input, Output, Stack> Yielder<Input, Output, Stack>
    where Input: Send, Output: Send, Stack: stack::Stack {
  fn new(context: *mut Context<Stack>) -> Yielder<Input, Output, Stack> {
    Yielder {
      context: context,
      phantom: (PhantomData, PhantomData)
    }
  }

  #[inline(always)]
  fn suspend_bare(&mut self, mut val: Option<Output>) -> Input {
    unsafe {
      let data = Context::swap(self.context, self.context,
                               &mut val as *mut Option<Output> as usize);
      mem::forget(val);
      let (new_context, input) = ptr::read(data as *mut (*mut Context<Stack>, Input));
      // The generator can be moved (and with it, the context).
      // This changes the address of the context.
      // Thus, we update it after each swap.
      self.context = new_context;
      // However, between this point and the next time we enter suspend_bare
      // the generator cannot be moved, as a &mut Generator is necessary
      // to resume the generator function.
      input
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `resume()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn suspend(&mut self, item: Output) -> Input {
    self.suspend_bare(Some(item))
  }
}

impl<Output, Stack> Iterator for Generator<(), Output, Stack>
    where Output: Send, Stack: stack::Stack {
  type Item = Output;

  fn next(&mut self) -> Option<Self::Item> { self.resume(()) }
}
<commit_msg>Yielder: use Cell internally to allow suspending via multiple borrows.<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) whitequark <whitequark@whitequark.org>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! Generators.
//!
//! Generators allow repeatedly suspending the execution of a function,
//! returning a value to the caller, and resuming the suspended function
//! afterwards.

use core::marker::PhantomData;
use core::{ptr, mem};
use core::cell::Cell;

use stack;
use context::Context;

#[derive(Debug, Clone, Copy)]
pub enum State {
  /// Generator can be resumed. This is the initial state.
  Runnable,
  /// Generator cannot be resumed. This is the state of the generator after
  /// the generator function has returned or panicked.
  Unavailable
}

/// Generator wraps a function and allows suspending its execution more than once, returning
/// a value each time.
///
/// The first time `resume(input0)` is called, the function is called as `f(yielder, input0)`.
/// It runs until it suspends its execution through `yielder.suspend(output0)`, after which
/// `resume(input0)` returns `output0`. The function can be resumed again using `resume(input1)`,
/// after which `yielder.suspend(output0)` returns `input1`, and so on. Once the function returns,
/// the `resume()` call will return `None`, and it will return `None` every time it is called
/// after that.
///
/// If the generator function panics, the panic is propagated through the `resume()` call as usual.
///
/// After the generator function returns or panics, it is safe to reclaim the generator stack
/// using `unwrap()`.
///
/// `state()` can be used to determine whether the generator function has returned;
/// the state is `State::Runnable` after creation and suspension, and `State::Unavailable`
/// once the generator function returns or panics.
///
/// When the input type is `()`, a generator implements the Iterator trait.
///
/// # Example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut add_one = Generator::new(stack, move |yielder, mut input| {
///   loop {
///     if input == 0 { break }
///     input = yielder.suspend(input + 1)
///   }
/// });
/// println!("{:?}", add_one.resume(2)); // prints Some(3)
/// println!("{:?}", add_one.resume(3)); // prints Some(4)
/// println!("{:?}", add_one.resume(0)); // prints None
/// ```
///
/// # Iterator example
///
/// ```
/// use fringe::{OsStack, Generator};
///
/// let stack = OsStack::new(0).unwrap();
/// let mut nat = Generator::new(stack, move |yielder, ()| {
///   for i in 1.. { yielder.suspend(i) }
/// });
/// println!("{:?}", nat.next()); // prints Some(0)
/// println!("{:?}", nat.next()); // prints Some(1)
/// println!("{:?}", nat.next()); // prints Some(2)
/// ```
#[derive(Debug)]
pub struct Generator<Input: Send, Output: Send, Stack: stack::Stack> {
  state:   State,
  context: Context<Stack>,
  phantom: (PhantomData<*const Input>, PhantomData<*const Output>)
}

impl<Input, Output, Stack> Generator<Input, Output, Stack>
    where Input: Send, Output: Send, Stack: stack::Stack {
  /// Creates a new generator.
  ///
  /// See also the [contract](../trait.GuardedStack.html) that needs to be fulfilled by `stack`.
  pub fn new<F>(stack: Stack, f: F) -> Generator<Input, Output, Stack>
      where Stack: stack::GuardedStack,
            F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) + Send {
    unsafe { Generator::unsafe_new(stack, f) }
  }

  /// Same as `new`, but does not require `stack` to have a guard page.
  ///
  /// This function is unsafe because the generator function can easily violate
  /// memory safety by overflowing the stack. It is useful in environments where
  /// guarded stacks do not exist, e.g. in absence of an MMU.
  ///
  /// See also the [contract](../trait.Stack.html) that needs to be fulfilled by `stack`.
  pub unsafe fn unsafe_new<F>(stack: Stack, f: F) -> Generator<Input, Output, Stack>
      where F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) + Send {
    unsafe extern "C" fn generator_wrapper<Input, Output, Stack, F>(env: usize) -> !
        where Input: Send, Output: Send, Stack: stack::Stack,
              F: FnOnce(&mut Yielder<Input, Output, Stack>, Input) {
      // Retrieve our environment from the callee and return control to it.
      let (mut yielder, f) = ptr::read(env as *mut (Yielder<Input, Output, Stack>, F));
      let data = Context::swap(yielder.context.get(), yielder.context.get(), 0);
      // See the second half of Yielder::suspend_bare.
      let (new_context, input) = ptr::read(data as *mut (*mut Context<Stack>, Input));
      yielder.context.set(new_context as *mut Context<Stack>);
      // Run the body of the generator.
      f(&mut yielder, input);
      // Past this point, the generator has dropped everything it has held.
      loop { yielder.suspend_bare(None); }
    }

    let mut generator = Generator {
      state:   State::Runnable,
      context: Context::new(stack, generator_wrapper::<Input, Output, Stack, F>),
      phantom: (PhantomData, PhantomData)
    };

    // Transfer environment to the callee.
    let mut env = (Yielder::new(&mut generator.context), f);
    Context::swap(&mut generator.context, &generator.context,
                  &mut env as *mut (Yielder<Input, Output, Stack>, F) as usize);
    mem::forget(env);

    generator
  }

  /// Resumes the generator and return the next value it yields.
  /// If the generator function has returned, returns `None`.
  #[inline]
  pub fn resume(&mut self, input: Input) -> Option<Output> {
    match self.state {
      State::Runnable => {
        // Set the state to Unavailable. Since we have exclusive access to the generator,
        // the only case where this matters is the generator function panics, after which
        // it must not be invocable again.
        self.state = State::Unavailable;

        // Switch to the generator function, and retrieve the yielded value.
        let val = unsafe {
          let mut data_in = (&mut self.context as *mut Context<Stack>, input);
          let data_out =
            ptr::read(Context::swap(&mut self.context, &self.context,
                                    &mut data_in as *mut (*mut Context<Stack>, Input)  as usize)
                      as *mut Option<Output>);
          mem::forget(data_in);
          data_out
        };

        // Unless the generator function has returned, it can be switched to again, so
        // set the state to Runnable.
        if val.is_some() { self.state = State::Runnable }

        val
      }
      State::Unavailable => None
    }
  }

  /// Returns the state of the generator.
  #[inline]
  pub fn state(&self) -> State { self.state }

  /// Extracts the stack from a generator when the generator function has returned.
  /// If the generator function has not returned
  /// (i.e. `self.state() == State::Runnable`), panics.
  pub fn unwrap(self) -> Stack {
    match self.state {
      State::Runnable    => panic!("Argh! Bastard! Don't touch that!"),
      State::Unavailable => unsafe { self.context.unwrap() }
    }
  }
}

/// Yielder is an interface provided to every generator through which it
/// returns a value.
#[derive(Debug)]
pub struct Yielder<Input: Send, Output: Send, Stack: stack::Stack> {
  context: Cell<*mut Context<Stack>>,
  phantom: (PhantomData<*const Input>, PhantomData<*const Output>)
}

impl<Input, Output, Stack> Yielder<Input, Output, Stack>
    where Input: Send, Output: Send, Stack: stack::Stack {
  fn new(context: *mut Context<Stack>) -> Yielder<Input, Output, Stack> {
    Yielder {
      context: Cell::new(context),
      phantom: (PhantomData, PhantomData)
    }
  }

  #[inline(always)]
  fn suspend_bare(&self, mut val: Option<Output>) -> Input {
    unsafe {
      let data = Context::swap(self.context.get(), self.context.get(),
                               &mut val as *mut Option<Output> as usize);
      mem::forget(val);
      let (new_context, input) = ptr::read(data as *mut (*mut Context<Stack>, Input));
      // The generator can be moved (and with it, the context).
      // This changes the address of the context.
      // Thus, we update it after each swap.
      self.context.set(new_context);
      // However, between this point and the next time we enter suspend_bare
      // the generator cannot be moved, as a &mut Generator is necessary
      // to resume the generator function.
      input
    }
  }

  /// Suspends the generator and returns `Some(item)` from the `resume()`
  /// invocation that resumed the generator.
  #[inline(always)]
  pub fn suspend(&self, item: Output) -> Input {
    self.suspend_bare(Some(item))
  }
}

impl<Output, Stack> Iterator for Generator<(), Output, Stack>
    where Output: Send, Stack: stack::Stack {
  type Item = Output;

  fn next(&mut self) -> Option<Self::Item> { self.resume(()) }
}
<|endoftext|>


<commit_before>use libc::{uint64_t, c_double, c_int};
use std::mem;

/// Typedef for the window completion callback function.
pub type HeartbeatWindowCompleteFn = extern fn(*const Heartbeat, *const HeartbeatRecord, uint64_t);

#[link(name = "hbs-pow")]
extern {
    /// Initialize a Heartbeat.
    fn heartbeat_init(hb: *mut Heartbeat,
                      window_size: uint64_t,
                      window_buffer: *mut HeartbeatRecord,
                      hwc_callback: Option<HeartbeatWindowCompleteFn>) -> c_int;

    /// Issue a heartbeat.
    fn heartbeat(hb: *mut Heartbeat,
                 user_tag: uint64_t,
                 work: uint64_t,
                 start_time: uint64_t,
                 end_time: uint64_t);

    /// Issue a heartbeat with energy data.
    fn heartbeat_pow(hb: *mut Heartbeat,
                     user_tag: uint64_t,
                     work: uint64_t,
                     start_time: uint64_t,
                     end_time: uint64_t,
                     start_energy: uint64_t,
                     end_energy: uint64_t);

    /// Writes the window buffer to the log specified by the file descriptor.
    pub fn heartbeat_log_window_buffer(hb: *const Heartbeat,
                                       fd: c_int,
                                       print_header: c_int) -> c_int;

    /// Utility function to get the most recent user-specified tag
    fn hb_get_user_tag(hb: *const Heartbeat) -> uint64_t;

    /// Utility function to get the current window performance.
    fn hb_get_window_rate(hb: *const Heartbeat) -> c_double;

    /// Utility function to get the current window power.
    fn hb_get_window_power(hb: *const Heartbeat) -> c_double;
}

/// Time data.
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatTimeData {
    total_time: uint64_t,
    window_time: uint64_t,
}

/// Work data.
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatWorkData {
    total_work: uint64_t,
    window_work: uint64_t,
}

/// Energy data
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatEnergyData {
    total_energy: uint64_t,
    window_energy: uint64_t,
}

/// A Heartbeat record with current rates (performance and power).
#[derive(Clone, Copy)]
#[repr(C)]
pub struct HeartbeatRecord {
    pub id: uint64_t,
    pub user_tag: uint64_t,

    pub work: uint64_t,
    pub start_time: uint64_t,
    pub end_time: uint64_t,
    pub global_perf: c_double,
    pub window_perf: c_double,
    pub instant_perf: c_double,

    pub start_energy: uint64_t,
    pub end_energy: uint64_t,
    pub global_pwr: c_double,
    pub window_pwr: c_double,
    pub instant_pwr: c_double,
}

/// A `Heartbeat` is used for tracking performance/power of recurring jobs.
/// This represents a C struct.
#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
#[repr(C)]
pub struct Heartbeat {
    counter: uint64_t,
    buffer_index: uint64_t,
    read_index: uint64_t,
    window_size: uint64_t,
    window_buffer: *mut HeartbeatRecord,
    hwc_callback: HeartbeatWindowCompleteFn,

    td: HeartbeatTimeData,
    wd: HeartbeatWorkData,
    ed: HeartbeatEnergyData,
}

/// Heartbeat wrapper. Contains the window data buffer.
pub struct HeartbeatSimple {
    pub hb: Heartbeat,
    pub hbr: Vec<HeartbeatRecord>,
}

impl HeartbeatSimple {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<HeartbeatWindowCompleteFn>) -> Result<HeartbeatSimple, &'static str> {
        unsafe {
            let mut hb = HeartbeatSimple {
                hb: mem::uninitialized(),
                hbr: Vec::with_capacity(window_size)
            };
            match heartbeat_init(&mut hb.hb, window_size as u64, hb.hbr.as_mut_ptr(), hwc_callback) {
                0 => Ok(hb),
                _ => Err("Failed to initialize heartbeat")
            }
        }
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64) {
        unsafe {
            heartbeat(&mut self.hb, tag, work, start_time, end_time)
        }
    }

    /// Issue a heartbeat with energy data.
    pub fn heartbeat_pow(&mut self,
                         tag: u64,
                         work: u64,
                         start_time: u64,
                         end_time: u64,
                         start_energy: u64,
                         end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&self) -> u64 {
        unsafe {
            hb_get_user_tag(&self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&self) -> f64 {
        unsafe {
            hb_get_window_rate(&self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&self) -> f64 {
        unsafe {
            hb_get_window_power(&self.hb)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::uint64_t;

    extern fn heartbeat_window_complete_callback(hb: *const Heartbeat,
                                                 _hbr: *const HeartbeatRecord,
                                                 _size: uint64_t) {
    const STDOUT: i32 = 1;
    unsafe {
        heartbeat_log_window_buffer(hb, STDOUT, 0);
    }
}

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatSimple::new(5, Some(heartbeat_window_complete_callback)).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        let mut tag: u64 = 0;
        for _ in 0..10 {
            hb.heartbeat_pow(tag, 1, start_time, end_time, start_energy, end_energy);
            assert!(hb.get_tag() == tag);
            assert!(hb.get_window_perf() == 1.0);
            assert!(hb.get_window_pwr() == 1.0);
            tag += 1;
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }
}
<commit_msg>Add pub fn to impl and make ffi function private so as not to expose Heartbeat<commit_after>use libc::{uint64_t, c_double, c_int};
use std::mem;

/// Typedef for the window completion callback function.
pub type HeartbeatWindowCompleteFn = extern fn(*const Heartbeat, *const HeartbeatRecord, uint64_t);

#[link(name = "hbs-pow")]
extern {
    /// Initialize a Heartbeat.
    fn heartbeat_init(hb: *mut Heartbeat,
                      window_size: uint64_t,
                      window_buffer: *mut HeartbeatRecord,
                      hwc_callback: Option<HeartbeatWindowCompleteFn>) -> c_int;

    /// Issue a heartbeat.
    fn heartbeat(hb: *mut Heartbeat,
                 user_tag: uint64_t,
                 work: uint64_t,
                 start_time: uint64_t,
                 end_time: uint64_t);

    /// Issue a heartbeat with energy data.
    fn heartbeat_pow(hb: *mut Heartbeat,
                     user_tag: uint64_t,
                     work: uint64_t,
                     start_time: uint64_t,
                     end_time: uint64_t,
                     start_energy: uint64_t,
                     end_energy: uint64_t);

    /// Writes the window buffer to the log specified by the file descriptor.
    fn heartbeat_log_window_buffer(hb: *const Heartbeat,
                                   fd: c_int,
                                   print_header: c_int) -> c_int;

    /// Utility function to get the most recent user-specified tag
    fn hb_get_user_tag(hb: *const Heartbeat) -> uint64_t;

    /// Utility function to get the current window performance.
    fn hb_get_window_rate(hb: *const Heartbeat) -> c_double;

    /// Utility function to get the current window power.
    fn hb_get_window_power(hb: *const Heartbeat) -> c_double;
}

/// Time data.
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatTimeData {
    total_time: uint64_t,
    window_time: uint64_t,
}

/// Work data.
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatWorkData {
    total_work: uint64_t,
    window_work: uint64_t,
}

/// Energy data
#[derive(Clone, Copy)]
#[repr(C)]
struct HeartbeatEnergyData {
    total_energy: uint64_t,
    window_energy: uint64_t,
}

/// A Heartbeat record with current rates (performance and power).
#[derive(Clone, Copy)]
#[repr(C)]
pub struct HeartbeatRecord {
    pub id: uint64_t,
    pub user_tag: uint64_t,

    pub work: uint64_t,
    pub start_time: uint64_t,
    pub end_time: uint64_t,
    pub global_perf: c_double,
    pub window_perf: c_double,
    pub instant_perf: c_double,

    pub start_energy: uint64_t,
    pub end_energy: uint64_t,
    pub global_pwr: c_double,
    pub window_pwr: c_double,
    pub instant_pwr: c_double,
}

/// A `Heartbeat` is used for tracking performance/power of recurring jobs.
/// This represents a C struct.
#[allow(raw_pointer_derive)]
#[derive(Clone, Copy)]
#[repr(C)]
pub struct Heartbeat {
    counter: uint64_t,
    buffer_index: uint64_t,
    read_index: uint64_t,
    window_size: uint64_t,
    window_buffer: *mut HeartbeatRecord,
    hwc_callback: HeartbeatWindowCompleteFn,

    td: HeartbeatTimeData,
    wd: HeartbeatWorkData,
    ed: HeartbeatEnergyData,
}

/// Heartbeat wrapper. Contains the window data buffer.
pub struct HeartbeatSimple {
    pub hb: Heartbeat,
    pub hbr: Vec<HeartbeatRecord>,
}

impl HeartbeatSimple {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<HeartbeatWindowCompleteFn>) -> Result<HeartbeatSimple, &'static str> {
        unsafe {
            let mut hb = HeartbeatSimple {
                hb: mem::uninitialized(),
                hbr: Vec::with_capacity(window_size)
            };
            match heartbeat_init(&mut hb.hb, window_size as u64, hb.hbr.as_mut_ptr(), hwc_callback) {
                0 => Ok(hb),
                _ => Err("Failed to initialize heartbeat")
            }
        }
    }

    /// Issue a heartbeat.
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64) {
        unsafe {
            heartbeat(&mut self.hb, tag, work, start_time, end_time)
        }
    }

    /// Issue a heartbeat with energy data.
    pub fn heartbeat_pow(&mut self,
                         tag: u64,
                         work: u64,
                         start_time: u64,
                         end_time: u64,
                         start_energy: u64,
                         end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    pub fn log_window_buffer(&self, fd: i32, print_header: bool) -> Result<(), &'static str> {
        let ph: c_int = match print_header {
            true => 1,
            false => 0,
        };
        unsafe {
            match heartbeat_log_window_buffer(&self.hb, fd, ph) {
                0 => Ok(()),
                _ => Err("Error logging window buffer"),
            }
        }
    }

    /// Utility function to get the most recent user-specified tag
    pub fn get_tag(&self) -> u64 {
        unsafe {
            hb_get_user_tag(&self.hb)
        }
    }

    /// Utility function to get the current window performance.
    pub fn get_window_perf(&self) -> f64 {
        unsafe {
            hb_get_window_rate(&self.hb)
        }
    }

    /// Utility function to get the current window power.
    pub fn get_window_pwr(&self) -> f64 {
        unsafe {
            hb_get_window_power(&self.hb)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use libc::uint64_t;

    extern fn heartbeat_window_complete_callback(hb: *const Heartbeat,
                                                 _hbr: *const HeartbeatRecord,
                                                 _size: uint64_t) {
    const STDOUT: i32 = 1;
    unsafe {
        heartbeat_log_window_buffer(hb, STDOUT, 0);
    }
}

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatSimple::new(5, Some(heartbeat_window_complete_callback)).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        let mut tag: u64 = 0;
        for _ in 0..10 {
            hb.heartbeat_pow(tag, 1, start_time, end_time, start_energy, end_energy);
            assert!(hb.get_tag() == tag);
            assert!(hb.get_window_perf() == 1.0);
            assert!(hb.get_window_pwr() == 1.0);
            tag += 1;
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/writer.rs                                           *
 *                                                        *
 * hprose writer for Rust.                                *
 *                                                        *
 * LastModified: Sep 12, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

extern crate test;
extern crate dtoa;

use std::i32;
use std::io::Write;
use std::ptr;
use std::string::String;

use super::tags::*;
use super::util::*;
use super::encoder::*;
use super::writer_refer::WriterRefer;

pub struct Writer {
    buf: Vec<u8>,
    refer: Option<WriterRefer>
}

impl Writer {
    pub fn serialize<T: Encodable + ?Sized>(&mut self, v: &T) -> &mut Writer {
        self.write_value(v);
        self
    }

    #[inline]
    pub fn write_value<T: Encodable + ?Sized>(&mut self, v: &T) {
        v.encode(self);
    }

    pub fn clear(&mut self) {
        self.buf.clear();
    }

    pub fn bytes(&mut self) -> Vec<u8> {
        self.buf.clone()
    }

    pub fn string(&mut self) -> String {
        String::from_utf8(self.buf.clone()).unwrap()
    }

    #[inline]
    pub fn new(simple: bool) -> Writer {
        Writer {
            buf: Vec::with_capacity(1024),
            refer: if simple { None } else { Some(WriterRefer::new()) }
        }
    }

    // private functions

    fn write_string(&mut self, s: &str, length: i64) {
        self.buf.push(TAG_STRING);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, length));
        self.buf.push(TAG_QUOTE);
        self.buf.extend_from_slice(s.as_bytes());
        self.buf.push(TAG_QUOTE);
    }

    fn write_list_header(&mut self, len: usize) {
        self.buf.push(TAG_LIST);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_uint_bytes(&mut buf, len as u64));
        self.buf.push(TAG_OPENBRACE);
    }

    #[inline]
    fn write_list_footer(&mut self) {
        self.buf.push(TAG_CLOSEBRACE);
    }

    #[inline]
    fn write_empty_list(&mut self) {
        self.buf.push(TAG_LIST);
        self.buf.push(TAG_OPENBRACE);
        self.buf.push(TAG_CLOSEBRACE);
    }
}

impl Encoder for Writer {
    fn write_nil(&mut self) {
        self.buf.push(TAG_NULL);
    }

    fn write_bool(&mut self, b: bool) {
        self.buf.push(if b { TAG_TRUE } else { TAG_FALSE });
    }

    fn write_int(&mut self, i: i64) {
        if i >= 0 && i <= 9 {
            self.buf.push(b'0' + i as u8);
            return
        }
        if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
            self.buf.push(TAG_INTEGER);
        } else {
            self.buf.push(TAG_LONG);
        }
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, i));
        self.buf.push(TAG_SEMICOLON);
    }

    fn write_uint(&mut self, i: u64) {
        if i <= 9 {
            self.buf.push(b'0' + i as u8);
            return
        }
        if i <= i32::MAX as u64 {
            self.buf.push(TAG_INTEGER);
        } else {
            self.buf.push(TAG_LONG);
        }
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_uint_bytes(&mut buf, i));
        self.buf.push(TAG_SEMICOLON);
    }

    fn write_f32(&mut self, f: f32) {
        if f.is_nan() {
            self.buf.push(TAG_NAN);
            return
        }
        if f.is_infinite() {
            self.buf.push(TAG_INFINITY);
            self.buf.push(if f.is_sign_negative() { TAG_NEG } else { TAG_POS });
            return
        }
        self.buf.push(TAG_DOUBLE);
        dtoa::write(&mut self.buf, f).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    fn write_f64(&mut self, f: f64) {
        if f.is_nan() {
            self.buf.push(TAG_NAN);
            return
        }
        if f.is_infinite() {
            self.buf.push(TAG_INFINITY);
            self.buf.push(if f.is_sign_negative() { TAG_NEG } else { TAG_POS });
            return
        }
        self.buf.push(TAG_DOUBLE);
        dtoa::write(&mut self.buf, f).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    fn write_char(&mut self, c: char) {}

    fn write_str(&mut self, s: &str) {
        let length = utf16_length(s);
        match length {
            0 => self.buf.push(TAG_EMPTY),
            -1 => self.write_bytes(s.as_bytes()),
            1 => {
                self.buf.push(TAG_UTF8_CHAR);
                self.buf.extend_from_slice(s.as_bytes());
            },
            _ => {
                self.set_ref(ptr::null::<&str>());
                self.write_string(s, length)
            }
        }
    }

    fn write_bytes(&mut self, bytes: &[u8]) {
        let count = bytes.len();
        if count == 0 {
            self.buf.push(TAG_BYTES);
            self.buf.push(TAG_QUOTE);
            self.buf.push(TAG_QUOTE);
            return
        }
        self.buf.push(TAG_BYTES);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, count as i64));
        self.buf.push(TAG_QUOTE);
        self.buf.extend_from_slice(bytes);
        self.buf.push(TAG_QUOTE);
    }

    fn write_seq<F>(&mut self, len: usize, f: F) where F: FnOnce(&mut Writer) {
        if len == 0 {
            self.write_empty_list();
            return
        }
        self.write_list_header(len);
        f(self);
        self.write_list_footer();
    }

    #[inline]
    fn write_ref<T>(&mut self, p: *const T) -> bool {
        let buf = &mut self.buf;
        self.refer.as_mut().map_or(true, |r| r.write(buf, p))
    }

    #[inline]
    fn set_ref<T>(&mut self, p: *const T) {
        self.refer.as_mut().map(|r| r.set(p));
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::test::Bencher;

    use std::{f32, f64};

    #[test]
    fn test_serialize_bool() {
        let mut w = Writer::new(true);
        w.serialize(&true);
        assert_eq!(w.string(), "t");
        w.clear();
        w.serialize(&false);
        assert_eq!(w.string(), "f");
    }

    #[bench]
    fn benchmark_serialize_bool(b: &mut Bencher) {
        let mut w = Writer::new(true);
        b.bytes = 1;
        b.iter(|| {
            w.serialize(&true);
        });
    }

    #[test]
    fn test_serialize_int() {
        let mut w = Writer::new(true);
        w.serialize(&8);
        assert_eq!(w.string(), "8");
        w.clear();
        w.serialize(&88);
        assert_eq!(w.string(), "i88;");
    }

    #[bench]
    fn benchmark_serialize_int(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: i64 = 1;
        b.iter(|| {
            w.serialize(&i);
            i += 1;
        });
    }

    #[test]
    fn test_serialize_float32() {
        let test_cases = [
            (f32::NAN, "N"),
            (f32::INFINITY, "I+"),
            (f32::NEG_INFINITY, "I-"),
            (f32::consts::PI, "d3.1415927;")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(&test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_float32(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: f32 = 1.0;
        b.iter(|| {
            w.serialize(&i);
            i += 1.0;
        });
    }

    #[test]
    fn test_serialize_float64() {
        let test_cases = [
            (f64::NAN, "N"),
            (f64::INFINITY, "I+"),
            (f64::NEG_INFINITY, "I-"),
            (f64::consts::PI, "d3.141592653589793;")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(&test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_float64(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: f64 = 1.0;
        b.iter(|| {
            w.serialize(&i);
            i += 1.0;
        });
    }

    #[test]
    fn test_serialize_string() {
        let test_cases = [
            ("", "e"),
            ("π", "uπ"),
            ("你", "u你"),
            ("你好", "s2\"你好\""),
            ("你好啊,hello!", "s10\"你好啊,hello!\""),
            ("🇨🇳", "s4\"🇨🇳\"")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_string(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let s = "你好,hello!";
        b.bytes = s.len() as u64;
        b.iter(|| {
            w.serialize(s);
        });
    }

    #[test]
    fn test_serialize_bytes() {
        let test_cases = [
            ("hello".as_bytes(), "b5\"hello\""),
            ("".as_bytes(), "b\"\"")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_int_slice(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let array = [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 1, 2, 3, 4, 0, 1, 2, 3, 4];
        let slice = &array[..];
        b.iter(|| {
            w.serialize(slice);
        });
    }
}
<commit_msg>Added bytes benchmark.<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/writer.rs                                           *
 *                                                        *
 * hprose writer for Rust.                                *
 *                                                        *
 * LastModified: Sep 12, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

extern crate test;
extern crate dtoa;

use std::i32;
use std::io::Write;
use std::ptr;
use std::string::String;

use super::tags::*;
use super::util::*;
use super::encoder::*;
use super::writer_refer::WriterRefer;

pub struct Writer {
    buf: Vec<u8>,
    refer: Option<WriterRefer>
}

impl Writer {
    #[inline]
    pub fn serialize<T: Encodable + ?Sized>(&mut self, v: &T) -> &mut Writer {
        self.write_value(v);
        self
    }

    #[inline]
    pub fn write_value<T: Encodable + ?Sized>(&mut self, v: &T) {
        v.encode(self);
    }

    pub fn clear(&mut self) {
        self.buf.clear();
    }

    pub fn bytes(&mut self) -> Vec<u8> {
        self.buf.clone()
    }

    pub fn string(&mut self) -> String {
        String::from_utf8(self.buf.clone()).unwrap()
    }

    #[inline]
    pub fn new(simple: bool) -> Writer {
        Writer {
            buf: Vec::with_capacity(1024),
            refer: if simple { None } else { Some(WriterRefer::new()) }
        }
    }

    // private functions

    fn write_string(&mut self, s: &str, length: i64) {
        self.buf.push(TAG_STRING);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, length));
        self.buf.push(TAG_QUOTE);
        self.buf.extend_from_slice(s.as_bytes());
        self.buf.push(TAG_QUOTE);
    }

    fn write_list_header(&mut self, len: usize) {
        self.buf.push(TAG_LIST);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_uint_bytes(&mut buf, len as u64));
        self.buf.push(TAG_OPENBRACE);
    }

    #[inline]
    fn write_list_footer(&mut self) {
        self.buf.push(TAG_CLOSEBRACE);
    }

    #[inline]
    fn write_empty_list(&mut self) {
        self.buf.push(TAG_LIST);
        self.buf.push(TAG_OPENBRACE);
        self.buf.push(TAG_CLOSEBRACE);
    }
}

impl Encoder for Writer {
    #[inline]
    fn write_nil(&mut self) {
        self.buf.push(TAG_NULL);
    }

    #[inline]
    fn write_bool(&mut self, b: bool) {
        self.buf.push(if b { TAG_TRUE } else { TAG_FALSE });
    }

    fn write_int(&mut self, i: i64) {
        if i >= 0 && i <= 9 {
            self.buf.push(b'0' + i as u8);
            return
        }
        if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
            self.buf.push(TAG_INTEGER);
        } else {
            self.buf.push(TAG_LONG);
        }
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, i));
        self.buf.push(TAG_SEMICOLON);
    }

    fn write_uint(&mut self, i: u64) {
        if i <= 9 {
            self.buf.push(b'0' + i as u8);
            return
        }
        if i <= i32::MAX as u64 {
            self.buf.push(TAG_INTEGER);
        } else {
            self.buf.push(TAG_LONG);
        }
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_uint_bytes(&mut buf, i));
        self.buf.push(TAG_SEMICOLON);
    }

    fn write_f32(&mut self, f: f32) {
        if f.is_nan() {
            self.buf.push(TAG_NAN);
            return
        }
        if f.is_infinite() {
            self.buf.push(TAG_INFINITY);
            self.buf.push(if f.is_sign_negative() { TAG_NEG } else { TAG_POS });
            return
        }
        self.buf.push(TAG_DOUBLE);
        dtoa::write(&mut self.buf, f).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    fn write_f64(&mut self, f: f64) {
        if f.is_nan() {
            self.buf.push(TAG_NAN);
            return
        }
        if f.is_infinite() {
            self.buf.push(TAG_INFINITY);
            self.buf.push(if f.is_sign_negative() { TAG_NEG } else { TAG_POS });
            return
        }
        self.buf.push(TAG_DOUBLE);
        dtoa::write(&mut self.buf, f).unwrap();
        self.buf.push(TAG_SEMICOLON);
    }

    fn write_char(&mut self, c: char) {}

    fn write_str(&mut self, s: &str) {
        let length = utf16_length(s);
        match length {
            0 => self.buf.push(TAG_EMPTY),
            - 1 => self.write_bytes(s.as_bytes()),
            1 => {
                self.buf.push(TAG_UTF8_CHAR);
                self.buf.extend_from_slice(s.as_bytes());
            },
            _ => {
                self.set_ref(ptr::null::<&str>());
                self.write_string(s, length)
            }
        }
    }

    fn write_bytes(&mut self, bytes: &[u8]) {
        let count = bytes.len();
        if count == 0 {
            self.buf.push(TAG_BYTES);
            self.buf.push(TAG_QUOTE);
            self.buf.push(TAG_QUOTE);
            return
        }
        self.buf.push(TAG_BYTES);
        let mut buf: [u8; 20] = [0; 20];
        self.buf.extend_from_slice(get_int_bytes(&mut buf, count as i64));
        self.buf.push(TAG_QUOTE);
        self.buf.extend_from_slice(bytes);
        self.buf.push(TAG_QUOTE);
    }

    fn write_seq<F>(&mut self, len: usize, f: F) where F: FnOnce(&mut Writer) {
        if len == 0 {
            self.write_empty_list();
            return
        }
        self.write_list_header(len);
        f(self);
        self.write_list_footer();
    }

    #[inline]
    fn write_ref<T>(&mut self, p: *const T) -> bool {
        let buf = &mut self.buf;
        self.refer.as_mut().map_or(true, |r| r.write(buf, p))
    }

    #[inline]
    fn set_ref<T>(&mut self, p: *const T) {
        self.refer.as_mut().map(|r| r.set(p));
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use super::test::Bencher;

    use std::{f32, f64};

    #[test]
    fn test_serialize_bool() {
        let mut w = Writer::new(true);
        w.serialize(&true);
        assert_eq!(w.string(), "t");
        w.clear();
        w.serialize(&false);
        assert_eq!(w.string(), "f");
    }

    #[bench]
    fn benchmark_serialize_bool(b: &mut Bencher) {
        let mut w = Writer::new(true);
        b.bytes = 1;
        b.iter(|| {
            w.serialize(&true);
        });
    }

    #[test]
    fn test_serialize_int() {
        let mut w = Writer::new(true);
        w.serialize(&8);
        assert_eq!(w.string(), "8");
        w.clear();
        w.serialize(&88);
        assert_eq!(w.string(), "i88;");
    }

    #[bench]
    fn benchmark_serialize_int(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: i64 = 1;
        b.iter(|| {
            w.serialize(&i);
            i += 1;
        });
    }

    #[test]
    fn test_serialize_f32() {
        let test_cases = [
            (f32::NAN, "N"),
            (f32::INFINITY, "I+"),
            (f32::NEG_INFINITY, "I-"),
            (f32::consts::PI, "d3.1415927;")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(&test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_f32(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: f32 = 1.0;
        b.iter(|| {
            w.serialize(&i);
            i += 1.0;
        });
    }

    #[test]
    fn test_serialize_f64() {
        let test_cases = [
            (f64::NAN, "N"),
            (f64::INFINITY, "I+"),
            (f64::NEG_INFINITY, "I-"),
            (f64::consts::PI, "d3.141592653589793;")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(&test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_f64(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let mut i: f64 = 1.0;
        b.iter(|| {
            w.serialize(&i);
            i += 1.0;
        });
    }

    #[test]
    fn test_serialize_str() {
        let test_cases = [
            ("", "e"),
            ("π", "uπ"),
            ("你", "u你"),
            ("你好", "s2\"你好\""),
            ("你好啊,hello!", "s10\"你好啊,hello!\""),
            ("🇨🇳", "s4\"🇨🇳\"")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_str(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let s = "你好,hello!";
        b.bytes = s.len() as u64;
        b.iter(|| {
            w.serialize(s);
        });
    }

    #[test]
    fn test_serialize_bytes() {
        let test_cases = [
            ("hello".as_bytes(), "b5\"hello\""),
            ("".as_bytes(), "b\"\"")
        ];
        let mut w = Writer::new(true);
        for test_case in &test_cases {
            w.serialize(test_case.0);
            assert_eq!(w.string(), test_case.1);
            w.clear();
        }
    }

    #[bench]
    fn benchmark_serialize_bytes(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let bytes = "你好,hello!".as_bytes();
        b.bytes = bytes.len() as u64;
        b.iter(|| {
            w.serialize(bytes);
        });
    }

    #[bench]
    fn benchmark_serialize_int_slice(b: &mut Bencher) {
        let mut w = Writer::new(true);
        let array = [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 1, 2, 3, 4, 0, 1, 2, 3, 4];
        let slice = &array[..];
        b.iter(|| {
            w.serialize(slice);
        });
    }
}
<|endoftext|>


<commit_before>use rustc_middle::mir;
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;

use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: Symbol,
        abi: Abi,
        args: &[OpTy<'tcx, Tag>],
        dest: &PlaceTy<'tcx, Tag>,
        _ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
        let this = self.eval_context_mut();

        match link_name.as_str() {
            // errno
            "__error" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let errno_place = this.last_error_place()?;
                this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?;
            }

            // File related shims
            "close" | "close$NOCANCEL" => {
                let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.close(result)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "stat" | "stat$INODE64" => {
                let [path, buf] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.macos_stat(path, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "lstat" | "lstat$INODE64" => {
                let [path, buf] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.macos_lstat(path, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "fstat" | "fstat$INODE64" => {
                let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.macos_fstat(fd, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "opendir" | "opendir$INODE64" => {
                let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.opendir(name)?;
                this.write_scalar(result, dest)?;
            }
            "readdir_r" | "readdir_r$INODE64" => {
                let [dirp, entry, result] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.macos_readdir_r(dirp, entry, result)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "ftruncate" => {
                let [fd, length] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.ftruncate64(fd, length)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }

            // Environment related shims
            "_NSGetEnviron" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.write_pointer(
                    this.machine.env_vars.environ.expect("machine must be initialized").ptr,
                    dest,
                )?;
            }

            // Time related shims
            "mach_absolute_time" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.mach_absolute_time()?;
                this.write_scalar(Scalar::from_u64(result), dest)?;
            }

            "mach_timebase_info" => {
                let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.mach_timebase_info(info)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }

            // Access to command-line arguments
            "_NSGetArgc" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.write_pointer(
                    this.machine.argc.expect("machine must be initialized").ptr,
                    dest,
                )?;
            }
            "_NSGetArgv" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.write_pointer(
                    this.machine.argv.expect("machine must be initialized").ptr,
                    dest,
                )?;
            }

            // Thread-local storage
            "_tlv_atexit" => {
                let [dtor, data] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let dtor = this.read_pointer(dtor)?;
                let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
                let data = this.read_scalar(data)?.check_init()?;
                let active_thread = this.get_active_thread();
                this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
            }

            // Querying system information
            "pthread_get_stackaddr_np" => {
                let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.read_scalar(thread)?.to_machine_usize(this)?;
                let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size());
                this.write_scalar(stack_addr, dest)?;
            }
            "pthread_get_stacksize_np" => {
                let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.read_scalar(thread)?.to_machine_usize(this)?;
                let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size());
                this.write_scalar(stack_size, dest)?;
            }

            // Threading
            "pthread_setname_np" => {
                let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let name = this.read_pointer(name)?;
                this.pthread_setname_np(name)?;
            }

            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
            // These shims are enabled only when the caller is in the standard library.
            "mmap" if this.frame_in_std() => {
                // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
                let [addr, _, _, _, _, _] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let addr = this.read_scalar(addr)?.check_init()?;
                this.write_scalar(addr, dest)?;
            }

            _ => return Ok(EmulateByNameResult::NotSupported),
        };

        Ok(EmulateByNameResult::NeedsJumping)
    }
}
<commit_msg>Support (stat/fstat/lstat)64 on macos<commit_after>use rustc_middle::mir;
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;

use crate::*;
use shims::foreign_items::EmulateByNameResult;
use shims::unix::fs::EvalContextExt as _;
use shims::unix::thread::EvalContextExt as _;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: Symbol,
        abi: Abi,
        args: &[OpTy<'tcx, Tag>],
        dest: &PlaceTy<'tcx, Tag>,
        _ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> {
        let this = self.eval_context_mut();

        match link_name.as_str() {
            // errno
            "__error" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let errno_place = this.last_error_place()?;
                this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?;
            }

            // File related shims
            "close" | "close$NOCANCEL" => {
                let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.close(result)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "stat" | "stat64" | "stat$INODE64" => {
                let [path, buf] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.macos_stat(path, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "lstat" | "lstat64" | "lstat$INODE64" => {
                let [path, buf] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.macos_lstat(path, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "fstat" | "fstat64" | "fstat$INODE64" => {
                let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.macos_fstat(fd, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "opendir" | "opendir$INODE64" => {
                let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.opendir(name)?;
                this.write_scalar(result, dest)?;
            }
            "readdir_r" | "readdir_r$INODE64" => {
                let [dirp, entry, result] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.macos_readdir_r(dirp, entry, result)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "ftruncate" => {
                let [fd, length] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.ftruncate64(fd, length)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }

            // Environment related shims
            "_NSGetEnviron" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.write_pointer(
                    this.machine.env_vars.environ.expect("machine must be initialized").ptr,
                    dest,
                )?;
            }

            // Time related shims
            "mach_absolute_time" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.mach_absolute_time()?;
                this.write_scalar(Scalar::from_u64(result), dest)?;
            }

            "mach_timebase_info" => {
                let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let result = this.mach_timebase_info(info)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }

            // Access to command-line arguments
            "_NSGetArgc" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.write_pointer(
                    this.machine.argc.expect("machine must be initialized").ptr,
                    dest,
                )?;
            }
            "_NSGetArgv" => {
                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.write_pointer(
                    this.machine.argv.expect("machine must be initialized").ptr,
                    dest,
                )?;
            }

            // Thread-local storage
            "_tlv_atexit" => {
                let [dtor, data] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let dtor = this.read_pointer(dtor)?;
                let dtor = this.get_ptr_fn(dtor)?.as_instance()?;
                let data = this.read_scalar(data)?.check_init()?;
                let active_thread = this.get_active_thread();
                this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
            }

            // Querying system information
            "pthread_get_stackaddr_np" => {
                let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.read_scalar(thread)?.to_machine_usize(this)?;
                let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size());
                this.write_scalar(stack_addr, dest)?;
            }
            "pthread_get_stacksize_np" => {
                let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                this.read_scalar(thread)?.to_machine_usize(this)?;
                let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size());
                this.write_scalar(stack_size, dest)?;
            }

            // Threading
            "pthread_setname_np" => {
                let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let name = this.read_pointer(name)?;
                this.pthread_setname_np(name)?;
            }

            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
            // These shims are enabled only when the caller is in the standard library.
            "mmap" if this.frame_in_std() => {
                // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
                let [addr, _, _, _, _, _] =
                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                let addr = this.read_scalar(addr)?.check_init()?;
                this.write_scalar(addr, dest)?;
            }

            _ => return Ok(EmulateByNameResult::NotSupported),
        };

        Ok(EmulateByNameResult::NeedsJumping)
    }
}
<|endoftext|>


<commit_before>//! A standalone binary for `proc-macro-srv`.

use proc_macro_srv::cli;

fn main() {
    cli::run().unwrap();
}
<commit_msg>Return result directly<commit_after>//! A standalone binary for `proc-macro-srv`.

use proc_macro_srv::cli;

fn main() -> std::io::Result<()> {
    cli::run()
}
<|endoftext|>


<commit_before>#![macro_escape]
macro_rules! hash_module (($hash_name:ident, $hashbytes:expr, $blockbytes:expr) => (

#[link(name = "sodium")]
extern {
    fn $hash_name(h: *mut u8,
                  m: *u8,
                  mlen: c_ulonglong) -> c_int;
}

pub static HASHBYTES: uint = $hashbytes;
pub static BLOCKBYTES: uint = $blockbytes;

/**
 * Digest-structure
 */
pub struct Digest(pub [u8, ..HASHBYTES]);

/**
 * `hash` hashes a message `m`. It returns a hash `h`.
 */
pub fn hash(m: &[u8]) -> Digest {
    unsafe {
        let mut h = [0, ..HASHBYTES];
        $hash_name(h.as_mut_ptr(), m.as_ptr(), m.len() as c_ulonglong);
        Digest(h)
    }
}

))
<commit_msg>Revert "The Digest buffer should public (fields are private by default now)"<commit_after>#![macro_escape]
macro_rules! hash_module (($hash_name:ident, $hashbytes:expr, $blockbytes:expr) => (

#[link(name = "sodium")]
extern {
    fn $hash_name(h: *mut u8,
                  m: *u8,
                  mlen: c_ulonglong) -> c_int;
}

pub static HASHBYTES: uint = $hashbytes;
pub static BLOCKBYTES: uint = $blockbytes;

/**
 * Digest-structure
 */
pub struct Digest([u8, ..HASHBYTES]);

/**
 * `hash` hashes a message `m`. It returns a hash `h`.
 */
pub fn hash(m: &[u8]) -> Digest {
    unsafe {
        let mut h = [0, ..HASHBYTES];
        $hash_name(h.as_mut_ptr(), m.as_ptr(), m.len() as c_ulonglong);
        Digest(h)
    }
}

))
<|endoftext|>