<commit_before>//
// gash.rs
//
// Reference solution for PS2
// Running on Rust 0.8
//
// Special thanks to Kiet Tran for porting code from Rust 0.7 to Rust 0.8.
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu, Purnam Jantrania, David Evans
// Version 0.2
//

use std::{io, run, os, path, libc};
use std::task;

fn get_fd(fpath: &str, mode: &str) -> libc::c_int {
    #[fixed_stack_segment]; #[inline(never)];

    unsafe {
        let fpathbuf = fpath.to_c_str().unwrap();
        let modebuf = mode.to_c_str().unwrap();
        return libc::fileno(libc::fopen(fpathbuf, modebuf));
    }
}

fn exit(status: libc::c_int) {
    #[fixed_stack_segment]; #[inline(never)];
    unsafe { libc::exit(status); }
}

fn handle_cmd(cmd_line: &str, pipe_in: libc::c_int, pipe_out: libc::c_int, pipe_err: libc::c_int) {
    let mut out_fd = pipe_out;
    let mut in_fd = pipe_in;
    let err_fd = pipe_err;

    let mut argv: ~[~str] =
        cmd_line.split_iter(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
    let mut i = 0;
    // found problem on redirection
    // `ping google.com | grep 1 > ping.txt &` didn't work
    // because grep won't flush the buffer until terminated (only) by SIGINT.
    while (i < argv.len()) {
        if (argv[i] == ~">") {
            argv.remove(i);
            out_fd = get_fd(argv.remove(i), "w");
        } else if (argv[i] == ~"<") {
            argv.remove(i);
            in_fd = get_fd(argv.remove(i), "r");
        }
        i += 1;
    }

    if argv.len() > 0 {
        let program = argv.remove(0);
        match program {
            ~"help" => {println("This is a new shell implemented in Rust!")}
            ~"cd" => {if argv.len()>0 {os::change_dir(&path::PosixPath(argv[0]));}}
            //global variable?
            //~"history" => {for i in range(0, history.len()) {println(fmt!("%5u %s", i+1, history[i]));}}
            ~"exit" => {exit(0);}
            _ => {let mut prog = run::Process::new(program, argv, run::ProcessOptions {
                                                                                env: None,
                                                                                dir: None,
                                                                                in_fd: Some(in_fd),
                                                                                out_fd: Some(out_fd),
                                                                                err_fd: Some(err_fd)
                                                                                });
                             prog.finish();
                             // close the pipes after process terminates.
                             if in_fd != 0 {os::close(in_fd);}
                             if out_fd != 1 {os::close(out_fd);}
                             if err_fd != 2 {os::close(err_fd);}
                            }
        }//match
    }//if
}

fn handle_cmdline(cmd_line:&str, bg_flag:bool)
{
    // handle pipes
    let progs: ~[~str] =
        cmd_line.split_iter('|').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();

    let mut pipes: ~[os::Pipe] = ~[];

    // create pipes
    if (progs.len() > 1) {
        for _ in range(0, progs.len()-1) {
            pipes.push(os::pipe());
        }
    }

    if progs.len() == 1 {
        if bg_flag == false { handle_cmd(progs[0], 0, 1, 2); }
        else {task::spawn_sched(task::SingleThreaded, ||{handle_cmd(progs[0], 0, 1, 2)});}
    } else {
        for i in range(0, progs.len()) {
            let prog = progs[i].to_owned();

            if i == 0 {
                let pipe_i = pipes[i];
                task::spawn_sched(task::SingleThreaded, ||{handle_cmd(prog, 0, pipe_i.out, 2)});
            } else if i == progs.len() - 1 {
                let pipe_i_1 = pipes[i-1];
                if bg_flag == true {
                    task::spawn_sched(task::SingleThreaded, ||{handle_cmd(prog, pipe_i_1.input, 1, 2)});
                } else {
                    handle_cmd(prog, pipe_i_1.input, 1, 2);
                }
            } else {
                let pipe_i = pipes[i];
                let pipe_i_1 = pipes[i-1];
                task::spawn_sched(task::SingleThreaded, ||{handle_cmd(prog, pipe_i_1.input, pipe_i.out, 2)});
            }
        }
    }
}

fn main() {
    static CMD_PROMPT: &'static str = "gash > ";
    let mut history: ~[~str] = ~[];

    loop {
        print(CMD_PROMPT);

        let mut cmd_line = io::stdin().read_line();
        cmd_line = cmd_line.trim().to_owned();
        if cmd_line.len() > 0 {
            history.push(cmd_line.to_owned());
        }
        let mut bg_flag = false;
        if cmd_line.ends_with("&") {
            cmd_line = cmd_line.trim_right_chars(&'&').to_owned();
            bg_flag = true;
        }

        if cmd_line == ~"exit" {
            break;
        } else if cmd_line == ~"history" {
            for i in range(0, history.len()) {
                println(fmt!("%5u %s", i+1, history[i]));
            }
        } else {
            handle_cmdline(cmd_line, bg_flag);
        }
    }
}
<commit_msg>removed unnecessary gash.rs<commit_after><|endoftext|>


<commit_before>//! This module handles incoming network messages.
//!
//! It routes the messages to appropriate services.
//! It handles requests at the application layer in its associated processor and directs
//! syncing-related responses to the Sync manager.
#![allow(clippy::unit_arg)]

pub mod processor;

use crate::error;
use crate::service::NetworkMessage;
use beacon_chain::{BeaconChain, BeaconChainTypes};
use eth2_libp2p::{
    rpc::RequestId, MessageId, NetworkGlobals, PeerId, PeerRequestId, PubsubMessage, Request,
    Response,
};
use futures::prelude::*;
use processor::Processor;
use slog::{debug, o, trace};
use std::sync::Arc;
use tokio::sync::mpsc;
use types::EthSpec;

/// Handles messages received from the network and client and organises syncing. This
/// functionality of this struct is to validate an decode messages from the network before
/// passing them to the internal message processor. The message processor spawns a syncing thread
/// which manages which blocks need to be requested and processed.
pub struct Router<T: BeaconChainTypes> {
    /// Processes validated and decoded messages from the network. Has direct access to the
    /// sync manager.
    processor: Processor<T>,
    /// The `Router` logger.
    log: slog::Logger,
}

/// Types of messages the handler can receive.
#[derive(Debug)]
pub enum RouterMessage<T: EthSpec> {
    /// We have initiated a connection to a new peer.
    PeerDialed(PeerId),
    /// Peer has disconnected,
    PeerDisconnected(PeerId),
    /// An RPC request has been received.
    RPCRequestReceived {
        peer_id: PeerId,
        id: PeerRequestId,
        request: Request,
    },
    /// An RPC response has been received.
    RPCResponseReceived {
        peer_id: PeerId,
        request_id: RequestId,
        response: Response<T>,
    },
    /// An RPC request failed
    RPCFailed {
        peer_id: PeerId,
        request_id: RequestId,
    },
    /// A gossip message has been received. The fields are: message id, the peer that sent us this
    /// message, the message itself and a bool which indicates if the message should be processed
    /// by the beacon chain after successful verification.
    PubsubMessage(MessageId, PeerId, PubsubMessage<T>, bool),
    /// The peer manager has requested we re-status a peer.
    StatusPeer(PeerId),
}

impl<T: BeaconChainTypes> Router<T> {
    /// Initializes and runs the Router.
    pub fn spawn(
        beacon_chain: Arc<BeaconChain<T>>,
        network_globals: Arc<NetworkGlobals<T::EthSpec>>,
        network_send: mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>,
        executor: task_executor::TaskExecutor,
        log: slog::Logger,
    ) -> error::Result<mpsc::UnboundedSender<RouterMessage<T::EthSpec>>> {
        let message_handler_log = log.new(o!("service"=> "router"));
        trace!(message_handler_log, "Service starting");

        let (handler_send, handler_recv) = mpsc::unbounded_channel();

        // Initialise a message instance, which itself spawns the syncing thread.
        let processor = Processor::new(
            executor.clone(),
            beacon_chain,
            network_globals,
            network_send,
            &log,
        );

        // generate the Message handler
        let mut handler = Router {
            processor,
            log: message_handler_log,
        };

        // spawn handler task and move the message handler instance into the spawned thread
        executor.spawn(
            async move {
                debug!(log, "Network message router started");
                handler_recv
                    .for_each(move |msg| future::ready(handler.handle_message(msg)))
                    .await;
            },
            "router",
        );

        Ok(handler_send)
    }

    /// Handle all messages incoming from the network service.
    fn handle_message(&mut self, message: RouterMessage<T::EthSpec>) {
        match message {
            // we have initiated a connection to a peer or the peer manager has requested a
            // re-status
            RouterMessage::PeerDialed(peer_id) | RouterMessage::StatusPeer(peer_id) => {
                self.processor.send_status(peer_id);
            }
            // A peer has disconnected
            RouterMessage::PeerDisconnected(peer_id) => {
                self.processor.on_disconnect(peer_id);
            }
            RouterMessage::RPCRequestReceived {
                peer_id,
                id,
                request,
            } => {
                self.handle_rpc_request(peer_id, id, request);
            }
            RouterMessage::RPCResponseReceived {
                peer_id,
                request_id,
                response,
            } => {
                self.handle_rpc_response(peer_id, request_id, response);
            }
            RouterMessage::RPCFailed {
                peer_id,
                request_id,
            } => {
                self.processor.on_rpc_error(peer_id, request_id);
            }
            RouterMessage::PubsubMessage(id, peer_id, gossip, should_process) => {
                self.handle_gossip(id, peer_id, gossip, should_process);
            }
        }
    }

    /* RPC - Related functionality */

    /// A new RPC request has been received from the network.
    fn handle_rpc_request(&mut self, peer_id: PeerId, id: PeerRequestId, request: Request) {
        match request {
            Request::Status(status_message) => {
                self.processor
                    .on_status_request(peer_id, id, status_message)
            }
            Request::BlocksByRange(request) => self
                .processor
                .on_blocks_by_range_request(peer_id, id, request),
            Request::BlocksByRoot(request) => self
                .processor
                .on_blocks_by_root_request(peer_id, id, request),
        }
    }

    /// An RPC response has been received from the network.
    // we match on id and ignore responses past the timeout.
    fn handle_rpc_response(
        &mut self,
        peer_id: PeerId,
        request_id: RequestId,
        response: Response<T::EthSpec>,
    ) {
        // an error could have occurred.
        match response {
            Response::Status(status_message) => {
                self.processor.on_status_response(peer_id, status_message);
            }
            Response::BlocksByRange(beacon_block) => {
                self.processor
                    .on_blocks_by_range_response(peer_id, request_id, beacon_block);
            }
            Response::BlocksByRoot(beacon_block) => {
                self.processor
                    .on_blocks_by_root_response(peer_id, request_id, beacon_block);
            }
        }
    }

    /// Handle RPC messages.
    /// Note: `should_process` is currently only useful for the `Attestation` variant.
    /// if `should_process` is `false`, we only propagate the message on successful verification,
    /// else, we propagate **and** import into the beacon chain.
    fn handle_gossip(
        &mut self,
        id: MessageId,
        peer_id: PeerId,
        gossip_message: PubsubMessage<T::EthSpec>,
        should_process: bool,
    ) {
        match gossip_message {
            // Attestations should never reach the router.
            PubsubMessage::AggregateAndProofAttestation(aggregate_and_proof) => {
                self.processor
                    .on_aggregated_attestation_gossip(id, peer_id, *aggregate_and_proof);
            }
            PubsubMessage::Attestation(subnet_attestation) => {
                self.processor.on_unaggregated_attestation_gossip(
                    id,
                    peer_id,
                    subnet_attestation.1.clone(),
                    subnet_attestation.0,
                    should_process,
                );
            }
            PubsubMessage::BeaconBlock(block) => {
                self.processor.on_block_gossip(id, peer_id, block);
            }
            PubsubMessage::VoluntaryExit(exit) => {
                debug!(self.log, "Received a voluntary exit"; "peer_id" => format!("{}", peer_id));
                self.processor.on_voluntary_exit_gossip(id, peer_id, exit);
            }
            PubsubMessage::ProposerSlashing(proposer_slashing) => {
                debug!(
                    self.log,
                    "Received a proposer slashing";
                    "peer_id" => format!("{}", peer_id)
                );
                self.processor
                    .on_proposer_slashing_gossip(id, peer_id, proposer_slashing);
            }
            PubsubMessage::AttesterSlashing(attester_slashing) => {
                debug!(
                    self.log,
                    "Received a attester slashing";
                    "peer_id" => format!("{}", peer_id)
                );
                self.processor
                    .on_attester_slashing_gossip(id, peer_id, attester_slashing);
            }
        }
    }
}
<commit_msg>router: drop requests from peers that have dc'd (#1919)<commit_after>//! This module handles incoming network messages.
//!
//! It routes the messages to appropriate services.
//! It handles requests at the application layer in its associated processor and directs
//! syncing-related responses to the Sync manager.
#![allow(clippy::unit_arg)]

pub mod processor;

use crate::error;
use crate::service::NetworkMessage;
use beacon_chain::{BeaconChain, BeaconChainTypes};
use eth2_libp2p::{
    rpc::RequestId, MessageId, NetworkGlobals, PeerId, PeerRequestId, PubsubMessage, Request,
    Response,
};
use futures::prelude::*;
use processor::Processor;
use slog::{debug, o, trace};
use std::sync::Arc;
use tokio::sync::mpsc;
use types::EthSpec;

/// Handles messages received from the network and client and organises syncing. This
/// functionality of this struct is to validate an decode messages from the network before
/// passing them to the internal message processor. The message processor spawns a syncing thread
/// which manages which blocks need to be requested and processed.
pub struct Router<T: BeaconChainTypes> {
    /// Access to the peer db.
    network_globals: Arc<NetworkGlobals<T::EthSpec>>,
    /// Processes validated and decoded messages from the network. Has direct access to the
    /// sync manager.
    processor: Processor<T>,
    /// The `Router` logger.
    log: slog::Logger,
}

/// Types of messages the handler can receive.
#[derive(Debug)]
pub enum RouterMessage<T: EthSpec> {
    /// We have initiated a connection to a new peer.
    PeerDialed(PeerId),
    /// Peer has disconnected,
    PeerDisconnected(PeerId),
    /// An RPC request has been received.
    RPCRequestReceived {
        peer_id: PeerId,
        id: PeerRequestId,
        request: Request,
    },
    /// An RPC response has been received.
    RPCResponseReceived {
        peer_id: PeerId,
        request_id: RequestId,
        response: Response<T>,
    },
    /// An RPC request failed
    RPCFailed {
        peer_id: PeerId,
        request_id: RequestId,
    },
    /// A gossip message has been received. The fields are: message id, the peer that sent us this
    /// message, the message itself and a bool which indicates if the message should be processed
    /// by the beacon chain after successful verification.
    PubsubMessage(MessageId, PeerId, PubsubMessage<T>, bool),
    /// The peer manager has requested we re-status a peer.
    StatusPeer(PeerId),
}

impl<T: BeaconChainTypes> Router<T> {
    /// Initializes and runs the Router.
    pub fn spawn(
        beacon_chain: Arc<BeaconChain<T>>,
        network_globals: Arc<NetworkGlobals<T::EthSpec>>,
        network_send: mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>,
        executor: task_executor::TaskExecutor,
        log: slog::Logger,
    ) -> error::Result<mpsc::UnboundedSender<RouterMessage<T::EthSpec>>> {
        let message_handler_log = log.new(o!("service"=> "router"));
        trace!(message_handler_log, "Service starting");

        let (handler_send, handler_recv) = mpsc::unbounded_channel();

        // Initialise a message instance, which itself spawns the syncing thread.
        let processor = Processor::new(
            executor.clone(),
            beacon_chain,
            network_globals.clone(),
            network_send,
            &log,
        );

        // generate the Message handler
        let mut handler = Router {
            network_globals,
            processor,
            log: message_handler_log,
        };

        // spawn handler task and move the message handler instance into the spawned thread
        executor.spawn(
            async move {
                debug!(log, "Network message router started");
                handler_recv
                    .for_each(move |msg| future::ready(handler.handle_message(msg)))
                    .await;
            },
            "router",
        );

        Ok(handler_send)
    }

    /// Handle all messages incoming from the network service.
    fn handle_message(&mut self, message: RouterMessage<T::EthSpec>) {
        match message {
            // we have initiated a connection to a peer or the peer manager has requested a
            // re-status
            RouterMessage::PeerDialed(peer_id) | RouterMessage::StatusPeer(peer_id) => {
                self.processor.send_status(peer_id);
            }
            // A peer has disconnected
            RouterMessage::PeerDisconnected(peer_id) => {
                self.processor.on_disconnect(peer_id);
            }
            RouterMessage::RPCRequestReceived {
                peer_id,
                id,
                request,
            } => {
                self.handle_rpc_request(peer_id, id, request);
            }
            RouterMessage::RPCResponseReceived {
                peer_id,
                request_id,
                response,
            } => {
                self.handle_rpc_response(peer_id, request_id, response);
            }
            RouterMessage::RPCFailed {
                peer_id,
                request_id,
            } => {
                self.processor.on_rpc_error(peer_id, request_id);
            }
            RouterMessage::PubsubMessage(id, peer_id, gossip, should_process) => {
                self.handle_gossip(id, peer_id, gossip, should_process);
            }
        }
    }

    /* RPC - Related functionality */

    /// A new RPC request has been received from the network.
    fn handle_rpc_request(&mut self, peer_id: PeerId, id: PeerRequestId, request: Request) {
        if !self.network_globals.peers.read().is_connected(&peer_id) {
            debug!(self.log, "Dropping request of disconnected peer"; "peer_id" => %peer_id, "request" => ?request);
            return;
        }
        match request {
            Request::Status(status_message) => {
                self.processor
                    .on_status_request(peer_id, id, status_message)
            }
            Request::BlocksByRange(request) => self
                .processor
                .on_blocks_by_range_request(peer_id, id, request),
            Request::BlocksByRoot(request) => self
                .processor
                .on_blocks_by_root_request(peer_id, id, request),
        }
    }

    /// An RPC response has been received from the network.
    // we match on id and ignore responses past the timeout.
    fn handle_rpc_response(
        &mut self,
        peer_id: PeerId,
        request_id: RequestId,
        response: Response<T::EthSpec>,
    ) {
        // an error could have occurred.
        match response {
            Response::Status(status_message) => {
                self.processor.on_status_response(peer_id, status_message);
            }
            Response::BlocksByRange(beacon_block) => {
                self.processor
                    .on_blocks_by_range_response(peer_id, request_id, beacon_block);
            }
            Response::BlocksByRoot(beacon_block) => {
                self.processor
                    .on_blocks_by_root_response(peer_id, request_id, beacon_block);
            }
        }
    }

    /// Handle RPC messages.
    /// Note: `should_process` is currently only useful for the `Attestation` variant.
    /// if `should_process` is `false`, we only propagate the message on successful verification,
    /// else, we propagate **and** import into the beacon chain.
    fn handle_gossip(
        &mut self,
        id: MessageId,
        peer_id: PeerId,
        gossip_message: PubsubMessage<T::EthSpec>,
        should_process: bool,
    ) {
        match gossip_message {
            // Attestations should never reach the router.
            PubsubMessage::AggregateAndProofAttestation(aggregate_and_proof) => {
                self.processor
                    .on_aggregated_attestation_gossip(id, peer_id, *aggregate_and_proof);
            }
            PubsubMessage::Attestation(subnet_attestation) => {
                self.processor.on_unaggregated_attestation_gossip(
                    id,
                    peer_id,
                    subnet_attestation.1.clone(),
                    subnet_attestation.0,
                    should_process,
                );
            }
            PubsubMessage::BeaconBlock(block) => {
                self.processor.on_block_gossip(id, peer_id, block);
            }
            PubsubMessage::VoluntaryExit(exit) => {
                debug!(self.log, "Received a voluntary exit"; "peer_id" => format!("{}", peer_id));
                self.processor.on_voluntary_exit_gossip(id, peer_id, exit);
            }
            PubsubMessage::ProposerSlashing(proposer_slashing) => {
                debug!(
                    self.log,
                    "Received a proposer slashing";
                    "peer_id" => format!("{}", peer_id)
                );
                self.processor
                    .on_proposer_slashing_gossip(id, peer_id, proposer_slashing);
            }
            PubsubMessage::AttesterSlashing(attester_slashing) => {
                debug!(
                    self.log,
                    "Received a attester slashing";
                    "peer_id" => format!("{}", peer_id)
                );
                self.processor
                    .on_attester_slashing_gossip(id, peer_id, attester_slashing);
            }
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    // Take the mod of some large number to a large power
    let value = mod_of_power(324322, 87234632, 3724);
    println!("{} {}", "324322^(87234632) mod 645:", value);
}

/// Get the modulus of an integer raised to a power.
/// **Calculates the modulus using modular exponentiation.**
fn mod_of_power(value: i32, power: i32, modulus: i32) -> i32 {
    let mut x: i32 = 1;
    for i in 0..power {
        x = (x * value) % modulus;
    }
    x
}
<commit_msg>Fixed error in output number<commit_after>fn main() {
    // Take the mod of some large number to a large power
    let value = mod_of_power(324322, 87234632, 3724);
    println!("{} {}", "324322^(87234632) mod 3724:", value);
}

/// Get the modulus of an integer raised to a power.
/// **Calculates the modulus using modular exponentiation.**
fn mod_of_power(value: i32, power: i32, modulus: i32) -> i32 {
    let mut x: i32 = 1;
    for i in 0..power {
        x = (x * value) % modulus;
    }
    x
}
<|endoftext|>


<commit_before>use smallvec::smallvec;

use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::outlives::Component;
use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
use rustc_span::symbol::Ident;

pub fn anonymize_predicate<'tcx>(
    tcx: TyCtxt<'tcx>,
    pred: ty::Predicate<'tcx>,
) -> ty::Predicate<'tcx> {
    match *pred.kind() {
        ty::PredicateKind::ForAll(binder) => {
            let new = ty::PredicateKind::ForAll(tcx.anonymize_late_bound_regions(binder));
            tcx.reuse_or_mk_predicate(pred, new)
        }
        ty::PredicateKind::Atom(_) => pred,
    }
}

struct PredicateSet<'tcx> {
    tcx: TyCtxt<'tcx>,
    set: FxHashSet<ty::Predicate<'tcx>>,
}

impl PredicateSet<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> Self {
        Self { tcx, set: Default::default() }
    }

    fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
        // We have to be careful here because we want
        //
        //    for<'a> Foo<&'a i32>
        //
        // and
        //
        //    for<'b> Foo<&'b i32>
        //
        // to be considered equivalent. So normalize all late-bound
        // regions before we throw things into the underlying set.
        self.set.insert(anonymize_predicate(self.tcx, pred))
    }
}

impl Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
    fn extend<I: IntoIterator<Item = ty::Predicate<'tcx>>>(&mut self, iter: I) {
        for pred in iter {
            self.insert(pred);
        }
    }

    fn extend_one(&mut self, pred: ty::Predicate<'tcx>) {
        self.insert(pred);
    }

    fn extend_reserve(&mut self, additional: usize) {
        Extend::<ty::Predicate<'tcx>>::extend_reserve(&mut self.set, additional);
    }
}

///////////////////////////////////////////////////////////////////////////
// `Elaboration` iterator
///////////////////////////////////////////////////////////////////////////

/// "Elaboration" is the process of identifying all the predicates that
/// are implied by a source predicate. Currently, this basically means
/// walking the "supertraits" and other similar assumptions. For example,
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
/// `T: Foo`, then we know that `T: 'static`.
pub struct Elaborator<'tcx> {
    stack: Vec<PredicateObligation<'tcx>>,
    visited: PredicateSet<'tcx>,
}

pub fn elaborate_trait_ref<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_ref: ty::PolyTraitRef<'tcx>,
) -> Elaborator<'tcx> {
    elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx)))
}

pub fn elaborate_trait_refs<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
) -> Elaborator<'tcx> {
    let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate(tcx));
    elaborate_predicates(tcx, predicates)
}

pub fn elaborate_trait_refs_that_define_assoc_type<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
    assoc_name: Ident,
) -> FxHashSet<ty::PolyTraitRef<'tcx>> {
    let mut stack: Vec<_> = trait_refs.collect();
    let mut trait_refs = FxHashSet::default();

    while let Some(trait_ref) = stack.pop() {
        if trait_refs.insert(trait_ref) {
            let super_predicates =
                tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), Some(assoc_name)));
            for (super_predicate, _) in super_predicates.predicates {
                let bound_predicate = super_predicate.bound_atom();
                let subst_predicate = super_predicate
                    .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder()));
                if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
                    stack.push(binder.value);
                }
            }
        }
    }

    trait_refs
}

pub fn elaborate_predicates<'tcx>(
    tcx: TyCtxt<'tcx>,
    predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
) -> Elaborator<'tcx> {
    let obligations = predicates
        .map(|predicate| {
            predicate_obligation(predicate, ty::ParamEnv::empty(), ObligationCause::dummy())
        })
        .collect();
    elaborate_obligations(tcx, obligations)
}

pub fn elaborate_obligations<'tcx>(
    tcx: TyCtxt<'tcx>,
    mut obligations: Vec<PredicateObligation<'tcx>>,
) -> Elaborator<'tcx> {
    let mut visited = PredicateSet::new(tcx);
    obligations.retain(|obligation| visited.insert(obligation.predicate));
    Elaborator { stack: obligations, visited }
}

fn predicate_obligation<'tcx>(
    predicate: ty::Predicate<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    cause: ObligationCause<'tcx>,
) -> PredicateObligation<'tcx> {
    Obligation { cause, param_env, recursion_depth: 0, predicate }
}

impl Elaborator<'tcx> {
    pub fn filter_to_traits(self) -> FilterToTraits<Self> {
        FilterToTraits::new(self)
    }

    fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
        let tcx = self.visited.tcx;

        let bound_predicate = obligation.predicate.bound_atom();
        match bound_predicate.skip_binder() {
            ty::PredicateAtom::Trait(data, _) => {
                // Get predicates declared on the trait.
                let predicates = tcx.super_predicates_of(data.def_id());

                let obligations = predicates.predicates.iter().map(|&(pred, _)| {
                    predicate_obligation(
                        pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
                        obligation.param_env,
                        obligation.cause.clone(),
                    )
                });
                debug!("super_predicates: data={:?}", data);

                // Only keep those bounds that we haven't already seen.
                // This is necessary to prevent infinite recursion in some
                // cases. One common case is when people define
                // `trait Sized: Sized { }` rather than `trait Sized { }`.
                let visited = &mut self.visited;
                let obligations = obligations.filter(|o| visited.insert(o.predicate));

                self.stack.extend(obligations);
            }
            ty::PredicateAtom::WellFormed(..) => {
                // Currently, we do not elaborate WF predicates,
                // although we easily could.
            }
            ty::PredicateAtom::ObjectSafe(..) => {
                // Currently, we do not elaborate object-safe
                // predicates.
            }
            ty::PredicateAtom::Subtype(..) => {
                // Currently, we do not "elaborate" predicates like `X <: Y`,
                // though conceivably we might.
            }
            ty::PredicateAtom::Projection(..) => {
                // Nothing to elaborate in a projection predicate.
            }
            ty::PredicateAtom::ClosureKind(..) => {
                // Nothing to elaborate when waiting for a closure's kind to be inferred.
            }
            ty::PredicateAtom::ConstEvaluatable(..) => {
                // Currently, we do not elaborate const-evaluatable
                // predicates.
            }
            ty::PredicateAtom::ConstEquate(..) => {
                // Currently, we do not elaborate const-equate
                // predicates.
            }
            ty::PredicateAtom::RegionOutlives(..) => {
                // Nothing to elaborate from `'a: 'b`.
            }
            ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
                // We know that `T: 'a` for some type `T`. We can
                // often elaborate this. For example, if we know that
                // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
                // we know `&'a U: 'b`, then we know that `'a: 'b` and
                // `U: 'b`.
                //
                // We can basically ignore bound regions here. So for
                // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
                // `'a: 'b`.

                // Ignore `for<'a> T: 'a` -- we might in the future
                // consider this as evidence that `T: 'static`, but
                // I'm a bit wary of such constructions and so for now
                // I want to be conservative. --nmatsakis
                if r_min.is_late_bound() {
                    return;
                }

                let visited = &mut self.visited;
                let mut components = smallvec![];
                tcx.push_outlives_components(ty_max, &mut components);
                self.stack.extend(
                    components
                        .into_iter()
                        .filter_map(|component| match component {
                            Component::Region(r) => {
                                if r.is_late_bound() {
                                    None
                                } else {
                                    Some(ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(
                                        r, r_min,
                                    )))
                                }
                            }

                            Component::Param(p) => {
                                let ty = tcx.mk_ty_param(p.index, p.name);
                                Some(ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(
                                    ty, r_min,
                                )))
                            }

                            Component::UnresolvedInferenceVariable(_) => None,

                            Component::Projection(_) | Component::EscapingProjection(_) => {
                                // We can probably do more here. This
                                // corresponds to a case like `<T as
                                // Foo<'a>>::U: 'b`.
                                None
                            }
                        })
                        .map(|predicate_kind| predicate_kind.to_predicate(tcx))
                        .filter(|&predicate| visited.insert(predicate))
                        .map(|predicate| {
                            predicate_obligation(
                                predicate,
                                obligation.param_env,
                                obligation.cause.clone(),
                            )
                        }),
                );
            }
            ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
                // Nothing to elaborate
            }
        }
    }
}

impl Iterator for Elaborator<'tcx> {
    type Item = PredicateObligation<'tcx>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.stack.len(), None)
    }

    fn next(&mut self) -> Option<Self::Item> {
        // Extract next item from top-most stack frame, if any.
        if let Some(obligation) = self.stack.pop() {
            self.elaborate(&obligation);
            Some(obligation)
        } else {
            None
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// Supertrait iterator
///////////////////////////////////////////////////////////////////////////

pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>;

pub fn supertraits<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_ref: ty::PolyTraitRef<'tcx>,
) -> Supertraits<'tcx> {
    elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
}

pub fn transitive_bounds<'tcx>(
    tcx: TyCtxt<'tcx>,
    bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
) -> Supertraits<'tcx> {
    elaborate_trait_refs(tcx, bounds).filter_to_traits()
}

pub fn transitive_bounds_that_define_assoc_type<'tcx>(
    tcx: TyCtxt<'tcx>,
    bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
    assoc_name: Ident,
) -> FxHashSet<ty::PolyTraitRef<'tcx>> {
    elaborate_trait_refs_that_define_assoc_type(tcx, bounds, assoc_name)
}

///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////

/// A filter around an iterator of predicates that makes it yield up
/// just trait references.
pub struct FilterToTraits<I> {
    base_iterator: I,
}

impl<I> FilterToTraits<I> {
    fn new(base: I) -> FilterToTraits<I> {
        FilterToTraits { base_iterator: base }
    }
}

impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<I> {
    type Item = ty::PolyTraitRef<'tcx>;

    fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
        while let Some(obligation) = self.base_iterator.next() {
            if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() {
                return Some(data.value);
            }
        }
        None
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.base_iterator.size_hint();
        (0, upper)
    }
}
<commit_msg>Document elaborate_trait_refs_that_define_assoc_type<commit_after>use smallvec::smallvec;

use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::outlives::Component;
use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
use rustc_span::symbol::Ident;

pub fn anonymize_predicate<'tcx>(
    tcx: TyCtxt<'tcx>,
    pred: ty::Predicate<'tcx>,
) -> ty::Predicate<'tcx> {
    match *pred.kind() {
        ty::PredicateKind::ForAll(binder) => {
            let new = ty::PredicateKind::ForAll(tcx.anonymize_late_bound_regions(binder));
            tcx.reuse_or_mk_predicate(pred, new)
        }
        ty::PredicateKind::Atom(_) => pred,
    }
}

struct PredicateSet<'tcx> {
    tcx: TyCtxt<'tcx>,
    set: FxHashSet<ty::Predicate<'tcx>>,
}

impl PredicateSet<'tcx> {
    fn new(tcx: TyCtxt<'tcx>) -> Self {
        Self { tcx, set: Default::default() }
    }

    fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
        // We have to be careful here because we want
        //
        //    for<'a> Foo<&'a i32>
        //
        // and
        //
        //    for<'b> Foo<&'b i32>
        //
        // to be considered equivalent. So normalize all late-bound
        // regions before we throw things into the underlying set.
        self.set.insert(anonymize_predicate(self.tcx, pred))
    }
}

impl Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
    fn extend<I: IntoIterator<Item = ty::Predicate<'tcx>>>(&mut self, iter: I) {
        for pred in iter {
            self.insert(pred);
        }
    }

    fn extend_one(&mut self, pred: ty::Predicate<'tcx>) {
        self.insert(pred);
    }

    fn extend_reserve(&mut self, additional: usize) {
        Extend::<ty::Predicate<'tcx>>::extend_reserve(&mut self.set, additional);
    }
}

///////////////////////////////////////////////////////////////////////////
// `Elaboration` iterator
///////////////////////////////////////////////////////////////////////////

/// "Elaboration" is the process of identifying all the predicates that
/// are implied by a source predicate. Currently, this basically means
/// walking the "supertraits" and other similar assumptions. For example,
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
/// `T: Foo`, then we know that `T: 'static`.
pub struct Elaborator<'tcx> {
    stack: Vec<PredicateObligation<'tcx>>,
    visited: PredicateSet<'tcx>,
}

pub fn elaborate_trait_ref<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_ref: ty::PolyTraitRef<'tcx>,
) -> Elaborator<'tcx> {
    elaborate_predicates(tcx, std::iter::once(trait_ref.without_const().to_predicate(tcx)))
}

pub fn elaborate_trait_refs<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
) -> Elaborator<'tcx> {
    let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate(tcx));
    elaborate_predicates(tcx, predicates)
}

/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may
/// define the given associated type `assoc_name`. It uses the
/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that
/// aren't related to `assoc_item`.  This is used when resolving types like `Self::Item` or
/// `T::Item` and helps to avoid cycle errors (see e.g. #35237).
pub fn elaborate_trait_refs_that_define_assoc_type<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
    assoc_name: Ident,
) -> FxHashSet<ty::PolyTraitRef<'tcx>> {
    let mut stack: Vec<_> = trait_refs.collect();
    let mut trait_refs = FxHashSet::default();

    while let Some(trait_ref) = stack.pop() {
        if trait_refs.insert(trait_ref) {
            let super_predicates =
                tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), Some(assoc_name)));
            for (super_predicate, _) in super_predicates.predicates {
                let bound_predicate = super_predicate.bound_atom();
                let subst_predicate = super_predicate
                    .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder()));
                if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
                    stack.push(binder.value);
                }
            }
        }
    }

    trait_refs
}

pub fn elaborate_predicates<'tcx>(
    tcx: TyCtxt<'tcx>,
    predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
) -> Elaborator<'tcx> {
    let obligations = predicates
        .map(|predicate| {
            predicate_obligation(predicate, ty::ParamEnv::empty(), ObligationCause::dummy())
        })
        .collect();
    elaborate_obligations(tcx, obligations)
}

pub fn elaborate_obligations<'tcx>(
    tcx: TyCtxt<'tcx>,
    mut obligations: Vec<PredicateObligation<'tcx>>,
) -> Elaborator<'tcx> {
    let mut visited = PredicateSet::new(tcx);
    obligations.retain(|obligation| visited.insert(obligation.predicate));
    Elaborator { stack: obligations, visited }
}

fn predicate_obligation<'tcx>(
    predicate: ty::Predicate<'tcx>,
    param_env: ty::ParamEnv<'tcx>,
    cause: ObligationCause<'tcx>,
) -> PredicateObligation<'tcx> {
    Obligation { cause, param_env, recursion_depth: 0, predicate }
}

impl Elaborator<'tcx> {
    pub fn filter_to_traits(self) -> FilterToTraits<Self> {
        FilterToTraits::new(self)
    }

    fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
        let tcx = self.visited.tcx;

        let bound_predicate = obligation.predicate.bound_atom();
        match bound_predicate.skip_binder() {
            ty::PredicateAtom::Trait(data, _) => {
                // Get predicates declared on the trait.
                let predicates = tcx.super_predicates_of(data.def_id());

                let obligations = predicates.predicates.iter().map(|&(pred, _)| {
                    predicate_obligation(
                        pred.subst_supertrait(tcx, &bound_predicate.rebind(data.trait_ref)),
                        obligation.param_env,
                        obligation.cause.clone(),
                    )
                });
                debug!("super_predicates: data={:?}", data);

                // Only keep those bounds that we haven't already seen.
                // This is necessary to prevent infinite recursion in some
                // cases. One common case is when people define
                // `trait Sized: Sized { }` rather than `trait Sized { }`.
                let visited = &mut self.visited;
                let obligations = obligations.filter(|o| visited.insert(o.predicate));

                self.stack.extend(obligations);
            }
            ty::PredicateAtom::WellFormed(..) => {
                // Currently, we do not elaborate WF predicates,
                // although we easily could.
            }
            ty::PredicateAtom::ObjectSafe(..) => {
                // Currently, we do not elaborate object-safe
                // predicates.
            }
            ty::PredicateAtom::Subtype(..) => {
                // Currently, we do not "elaborate" predicates like `X <: Y`,
                // though conceivably we might.
            }
            ty::PredicateAtom::Projection(..) => {
                // Nothing to elaborate in a projection predicate.
            }
            ty::PredicateAtom::ClosureKind(..) => {
                // Nothing to elaborate when waiting for a closure's kind to be inferred.
            }
            ty::PredicateAtom::ConstEvaluatable(..) => {
                // Currently, we do not elaborate const-evaluatable
                // predicates.
            }
            ty::PredicateAtom::ConstEquate(..) => {
                // Currently, we do not elaborate const-equate
                // predicates.
            }
            ty::PredicateAtom::RegionOutlives(..) => {
                // Nothing to elaborate from `'a: 'b`.
            }
            ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty_max, r_min)) => {
                // We know that `T: 'a` for some type `T`. We can
                // often elaborate this. For example, if we know that
                // `[U]: 'a`, that implies that `U: 'a`. Similarly, if
                // we know `&'a U: 'b`, then we know that `'a: 'b` and
                // `U: 'b`.
                //
                // We can basically ignore bound regions here. So for
                // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to
                // `'a: 'b`.

                // Ignore `for<'a> T: 'a` -- we might in the future
                // consider this as evidence that `T: 'static`, but
                // I'm a bit wary of such constructions and so for now
                // I want to be conservative. --nmatsakis
                if r_min.is_late_bound() {
                    return;
                }

                let visited = &mut self.visited;
                let mut components = smallvec![];
                tcx.push_outlives_components(ty_max, &mut components);
                self.stack.extend(
                    components
                        .into_iter()
                        .filter_map(|component| match component {
                            Component::Region(r) => {
                                if r.is_late_bound() {
                                    None
                                } else {
                                    Some(ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(
                                        r, r_min,
                                    )))
                                }
                            }

                            Component::Param(p) => {
                                let ty = tcx.mk_ty_param(p.index, p.name);
                                Some(ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(
                                    ty, r_min,
                                )))
                            }

                            Component::UnresolvedInferenceVariable(_) => None,

                            Component::Projection(_) | Component::EscapingProjection(_) => {
                                // We can probably do more here. This
                                // corresponds to a case like `<T as
                                // Foo<'a>>::U: 'b`.
                                None
                            }
                        })
                        .map(|predicate_kind| predicate_kind.to_predicate(tcx))
                        .filter(|&predicate| visited.insert(predicate))
                        .map(|predicate| {
                            predicate_obligation(
                                predicate,
                                obligation.param_env,
                                obligation.cause.clone(),
                            )
                        }),
                );
            }
            ty::PredicateAtom::TypeWellFormedFromEnv(..) => {
                // Nothing to elaborate
            }
        }
    }
}

impl Iterator for Elaborator<'tcx> {
    type Item = PredicateObligation<'tcx>;

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.stack.len(), None)
    }

    fn next(&mut self) -> Option<Self::Item> {
        // Extract next item from top-most stack frame, if any.
        if let Some(obligation) = self.stack.pop() {
            self.elaborate(&obligation);
            Some(obligation)
        } else {
            None
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// Supertrait iterator
///////////////////////////////////////////////////////////////////////////

pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>;

pub fn supertraits<'tcx>(
    tcx: TyCtxt<'tcx>,
    trait_ref: ty::PolyTraitRef<'tcx>,
) -> Supertraits<'tcx> {
    elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
}

pub fn transitive_bounds<'tcx>(
    tcx: TyCtxt<'tcx>,
    bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
) -> Supertraits<'tcx> {
    elaborate_trait_refs(tcx, bounds).filter_to_traits()
}

pub fn transitive_bounds_that_define_assoc_type<'tcx>(
    tcx: TyCtxt<'tcx>,
    bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
    assoc_name: Ident,
) -> FxHashSet<ty::PolyTraitRef<'tcx>> {
    elaborate_trait_refs_that_define_assoc_type(tcx, bounds, assoc_name)
}

///////////////////////////////////////////////////////////////////////////
// Other
///////////////////////////////////////////////////////////////////////////

/// A filter around an iterator of predicates that makes it yield up
/// just trait references.
pub struct FilterToTraits<I> {
    base_iterator: I,
}

impl<I> FilterToTraits<I> {
    fn new(base: I) -> FilterToTraits<I> {
        FilterToTraits { base_iterator: base }
    }
}

impl<'tcx, I: Iterator<Item = PredicateObligation<'tcx>>> Iterator for FilterToTraits<I> {
    type Item = ty::PolyTraitRef<'tcx>;

    fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
        while let Some(obligation) = self.base_iterator.next() {
            if let Some(data) = obligation.predicate.to_opt_poly_trait_ref() {
                return Some(data.value);
            }
        }
        None
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (_, upper) = self.base_iterator.size_hint();
        (0, upper)
    }
}
<|endoftext|>


<commit_before>//! The push thread.
//!
//! This is the thread for distributing rumors to members. It distributes to `FANOUT` members, no
//! more often than `Timing::GOSSIP_PERIOD_DEFAULT_MS`.

use crate::{member::{Member,
                     Membership},
            rumor::{RumorEnvelope,
                    RumorKey,
                    RumorKind,
                    RumorType},
            server::{timing::Timing,
                     Server},
            ZMQ_CONTEXT};
use habitat_common::liveliness_checker;
use habitat_core::util::ToI64;
use prometheus::{IntCounterVec,
                 IntGaugeVec};
use std::{thread,
          time::{Duration,
                 Instant}};
use zmq;

const FANOUT: usize = 5;

lazy_static! {
    static ref GOSSIP_MESSAGES_SENT: IntCounterVec =
        register_int_counter_vec!("hab_butterfly_gossip_messages_sent_total",
                                  "Total number of gossip messages sent",
                                  &["type", "mode"]).unwrap();
    static ref GOSSIP_BYTES_SENT: IntGaugeVec =
        register_int_gauge_vec!("hab_butterfly_gossip_sent_bytes",
                                "Gossip message size sent in bytes",
                                &["type", "mode"]).unwrap();
}

pub fn spawn_thread(name: String, server: Server, timing: Timing) -> std::io::Result<()> {
    thread::Builder::new().name(name)
                          .spawn(move || -> ! { run_loop(&server, &timing) })
                          .map(|_| ())
}

/// Executes the Push thread. Gets a list of members to talk to that are not Confirmed; then
/// proceeds to process the list in `FANOUT` sized chunks. If we finish sending the messages to
/// all FANOUT targets faster than `Timing::gossip_period`, we will block until we
/// exceed that time.
fn run_loop(server: &Server, timing: &Timing) -> ! {
    let gossip_period = timing.gossip_period();

    loop {
        liveliness_checker::mark_thread_alive().and_divergent();

        if server.paused() {
            thread::sleep(Duration::from_millis(100));
            continue;
        }

        server.update_gossip_round();

        let mut check_list = server.member_list.check_list_mlr(server.member_id());
        let fanout_loop_start_time = Instant::now();

        'fanout: loop {
            let mut thread_list = Vec::with_capacity(FANOUT);
            if check_list.is_empty() {
                break 'fanout;
            }
            let drain_length = check_list.len().min(FANOUT);
            let gossip_start_time = Instant::now();
            for member in check_list.drain(0..drain_length) {
                if server.is_member_blocked_sblr(&member.id) {
                    debug!("Not sending rumors to {} - it is blocked", member.id);

                    continue;
                }
                // Unlike the SWIM mechanism, we don't actually want to send gossip traffic to
                // persistent members that are confirmed dead. When the failure detector thread
                // finds them alive again, we'll go ahead and get back to the business at hand.
                if server.member_list.pingable_mlr(&member)
                   && !server.member_list.persistent_and_confirmed_mlr(&member)
                {
                    let rumors = server.rumor_heat
                                       .lock_rhr()
                                       .currently_hot_rumors(&member.id);
                    if !rumors.is_empty() {
                        let sc = server.clone();
                        let guard = match thread::Builder::new().name(String::from("push-worker"))
                                                                .spawn(move || {
                                                                    send_rumors_rsr_mlr_rhw(&sc,
                                                                                &member,
                                                                                &rumors)
                                                                }) {
                            Ok(guard) => guard,
                            Err(e) => {
                                error!("Could not spawn thread: {}", e);
                                continue;
                            }
                        };
                        thread_list.push(guard);
                    }
                }
            }
            let num_threads = thread_list.len();
            for guard in thread_list.drain(0..num_threads) {
                let _ = guard.join()
                             .map_err(|e| error!("Push worker died: {:?}", e));
            }
            // If we've still got any time left in the gossip period, sleep
            // for that long.
            if let Some(wait_time) = gossip_period.checked_sub(gossip_start_time.elapsed()) {
                thread::sleep(wait_time);
            }
        }

        // If we've still got any time left in the gossip period, sleep
        // for that long.
        if let Some(wait_time) = gossip_period.checked_sub(fanout_loop_start_time.elapsed()) {
            thread::sleep(wait_time);
        }
    }
}

/// Send the list of rumors to a given member. This method creates an outbound socket and then
/// closes the connection as soon as we are done sending rumors. ZeroMQ may choose to keep the
/// connection and socket open for 1 second longer - so it is possible, but unlikely, that this
/// method can lose messages.
///
/// # Locking (see locking.md)
/// * `RumorStore::list` (read)
/// * `MemberList::entries` (read)
/// * `RumorHeat::inner` (write)
// If we ever need to modify this function, it would be an excellent opportunity to
// simplify the redundant aspects and remove this allow(clippy::cognitive_complexity),
// but changing it in the absence of other necessity seems like too much risk for the
// expected reward.
#[allow(clippy::cognitive_complexity)]
fn send_rumors_rsr_mlr_rhw(server: &Server, member: &Member, rumors: &[RumorKey]) {
    let socket = (**ZMQ_CONTEXT).as_mut()
                                .socket(zmq::PUSH)
                                .expect("Failure to create the ZMQ push socket");
    socket.set_linger(1000)
          .expect("Failure to set the ZMQ push socket to not linger");
    socket.set_tcp_keepalive(0)
          .expect("Failure to set the ZMQ push socket to not use keepalive");
    socket.set_immediate(true)
          .expect("Failure to set the ZMQ push socket to immediate");
    socket.set_sndhwm(1000)
          .expect("Failure to set the ZMQ push socket hwm");
    socket.set_sndtimeo(500)
          .expect("Failure to set the ZMQ send timeout");
    let to_addr = format!("{}:{}", member.address, member.gossip_port);
    match socket.connect(&format!("tcp://{}", to_addr)) {
        Ok(()) => debug!("Connected push socket to {:?}", member),
        Err(e) => {
            error!("Cannot connect push socket to {:?}: {:?}", member, e);
            let label_values = &["socket_connect", "failure"];
            GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
            GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
            return;
        }
    }
    'rumorlist: for rumor_key in rumors.iter() {
        let rumor_as_bytes = match rumor_key.kind {
            RumorType::Member => {
                let send_rumor = match create_member_rumor_mlr(&server, &rumor_key) {
                    Some(rumor) => rumor,
                    None => continue 'rumorlist,
                };
                match send_rumor.encode() {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["member_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::Service => {
                match server.service_store.lock_rsr().encode_rumor_for(&rumor_key) {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["service_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::ServiceConfig => {
                match server.service_config_store
                            .lock_rsr()
                            .encode_rumor_for(&rumor_key)
                {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["service_config_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::ServiceFile => {
                match server.service_file_store
                            .lock_rsr()
                            .encode_rumor_for(&rumor_key)
                {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["service_file_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::Departure => {
                match server.departure_store
                            .lock_rsr()
                            .encode_rumor_for(&rumor_key)
                {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["departure_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::Election => {
                match server.election_store
                            .lock_rsr()
                            .encode_rumor_for(&rumor_key)
                {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["election_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::ElectionUpdate => {
                match server.update_store.lock_rsr().encode_rumor_for(&rumor_key) {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["election_update_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::Fake | RumorType::Fake2 => {
                debug!("You have fake rumors; how odd!");
                continue 'rumorlist;
            }
        };
        let rumor_len = rumor_as_bytes.len().to_i64();
        let payload = match server.generate_wire(rumor_as_bytes) {
            Ok(payload) => payload,
            Err(e) => {
                error!("Generating protobuf failed: {}", e);
                let label_values = &["generate_wire", "failure"];
                GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                GOSSIP_BYTES_SENT.with_label_values(label_values)
                                 .set(rumor_len);
                continue 'rumorlist;
            }
        };
        match socket.send(&payload, 0) {
            Ok(()) => {
                GOSSIP_MESSAGES_SENT.with_label_values(&[&rumor_key.kind.to_string(), "success"])
                                    .inc();
                GOSSIP_BYTES_SENT.with_label_values(&[&rumor_key.kind.to_string(), "success"])
                                 .set(payload.len().to_i64());
                debug!("Sent rumor {:?} to {:?}", rumor_key, member);
            }
            Err(e) => {
                warn!("Could not send rumor to {:?} @ {:?}; ZMQ said: {:?}",
                      member.id, to_addr, e)
            }
        }
    }

    server.rumor_heat
          .lock_rhw()
          .cool_rumors(&member.id, &rumors);
}

/// Given a rumorkey, creates a protobuf rumor for sharing.
///
/// # Locking (see locking.md)
/// * `MemberList::entries` (read)
fn create_member_rumor_mlr(server: &Server, rumor_key: &RumorKey) -> Option<RumorEnvelope> {
    let member = server.member_list.get_cloned_mlr(&rumor_key.to_string())?;
    let payload = Membership { member,
                               health: server.member_list
                                             .health_of_by_id_mlr(&rumor_key.to_string())
                                             .unwrap() };
    let rumor = RumorEnvelope { r#type:  RumorType::Member,
                                from_id: server.member_id().to_string(),
                                kind:    RumorKind::Membership(payload), };
    Some(rumor)
}
<commit_msg>Avoid a meaningless let<commit_after>//! The push thread.
//!
//! This is the thread for distributing rumors to members. It distributes to `FANOUT` members, no
//! more often than `Timing::GOSSIP_PERIOD_DEFAULT_MS`.

use crate::{member::{Member,
                     Membership},
            rumor::{RumorEnvelope,
                    RumorKey,
                    RumorKind,
                    RumorType},
            server::{timing::Timing,
                     Server},
            ZMQ_CONTEXT};
use habitat_common::liveliness_checker;
use habitat_core::util::ToI64;
use prometheus::{IntCounterVec,
                 IntGaugeVec};
use std::{thread,
          time::{Duration,
                 Instant}};
use zmq;

const FANOUT: usize = 5;

lazy_static! {
    static ref GOSSIP_MESSAGES_SENT: IntCounterVec =
        register_int_counter_vec!("hab_butterfly_gossip_messages_sent_total",
                                  "Total number of gossip messages sent",
                                  &["type", "mode"]).unwrap();
    static ref GOSSIP_BYTES_SENT: IntGaugeVec =
        register_int_gauge_vec!("hab_butterfly_gossip_sent_bytes",
                                "Gossip message size sent in bytes",
                                &["type", "mode"]).unwrap();
}

pub fn spawn_thread(name: String, server: Server, timing: Timing) -> std::io::Result<()> {
    thread::Builder::new().name(name)
                          .spawn(move || -> ! { run_loop(&server, &timing) })
                          .map(|_| ())
}

/// Executes the Push thread. Gets a list of members to talk to that are not Confirmed; then
/// proceeds to process the list in `FANOUT` sized chunks. If we finish sending the messages to
/// all FANOUT targets faster than `Timing::gossip_period`, we will block until we
/// exceed that time.
fn run_loop(server: &Server, timing: &Timing) -> ! {
    let gossip_period = timing.gossip_period();

    loop {
        liveliness_checker::mark_thread_alive().and_divergent();

        if server.paused() {
            thread::sleep(Duration::from_millis(100));
            continue;
        }

        server.update_gossip_round();

        let mut check_list = server.member_list.check_list_mlr(server.member_id());
        let fanout_loop_start_time = Instant::now();

        'fanout: loop {
            let mut thread_list = Vec::with_capacity(FANOUT);
            if check_list.is_empty() {
                break 'fanout;
            }
            let drain_length = check_list.len().min(FANOUT);
            let gossip_start_time = Instant::now();
            for member in check_list.drain(0..drain_length) {
                if server.is_member_blocked_sblr(&member.id) {
                    debug!("Not sending rumors to {} - it is blocked", member.id);

                    continue;
                }
                // Unlike the SWIM mechanism, we don't actually want to send gossip traffic to
                // persistent members that are confirmed dead. When the failure detector thread
                // finds them alive again, we'll go ahead and get back to the business at hand.
                if server.member_list.pingable_mlr(&member)
                   && !server.member_list.persistent_and_confirmed_mlr(&member)
                {
                    let rumors = server.rumor_heat
                                       .lock_rhr()
                                       .currently_hot_rumors(&member.id);
                    if !rumors.is_empty() {
                        let sc = server.clone();
                        let guard = match thread::Builder::new().name(String::from("push-worker"))
                                                                .spawn(move || {
                                                                    send_rumors_rsr_mlr_rhw(&sc,
                                                                                &member,
                                                                                &rumors)
                                                                }) {
                            Ok(guard) => guard,
                            Err(e) => {
                                error!("Could not spawn thread: {}", e);
                                continue;
                            }
                        };
                        thread_list.push(guard);
                    }
                }
            }
            let num_threads = thread_list.len();
            for guard in thread_list.drain(0..num_threads) {
                if let Err(e) = guard.join() {
                    error!("Push worker died: {:?}", e);
                }
            }
            // If we've still got any time left in the gossip period, sleep
            // for that long.
            if let Some(wait_time) = gossip_period.checked_sub(gossip_start_time.elapsed()) {
                thread::sleep(wait_time);
            }
        }

        // If we've still got any time left in the gossip period, sleep
        // for that long.
        if let Some(wait_time) = gossip_period.checked_sub(fanout_loop_start_time.elapsed()) {
            thread::sleep(wait_time);
        }
    }
}

/// Send the list of rumors to a given member. This method creates an outbound socket and then
/// closes the connection as soon as we are done sending rumors. ZeroMQ may choose to keep the
/// connection and socket open for 1 second longer - so it is possible, but unlikely, that this
/// method can lose messages.
///
/// # Locking (see locking.md)
/// * `RumorStore::list` (read)
/// * `MemberList::entries` (read)
/// * `RumorHeat::inner` (write)
// If we ever need to modify this function, it would be an excellent opportunity to
// simplify the redundant aspects and remove this allow(clippy::cognitive_complexity),
// but changing it in the absence of other necessity seems like too much risk for the
// expected reward.
#[allow(clippy::cognitive_complexity)]
fn send_rumors_rsr_mlr_rhw(server: &Server, member: &Member, rumors: &[RumorKey]) {
    let socket = (**ZMQ_CONTEXT).as_mut()
                                .socket(zmq::PUSH)
                                .expect("Failure to create the ZMQ push socket");
    socket.set_linger(1000)
          .expect("Failure to set the ZMQ push socket to not linger");
    socket.set_tcp_keepalive(0)
          .expect("Failure to set the ZMQ push socket to not use keepalive");
    socket.set_immediate(true)
          .expect("Failure to set the ZMQ push socket to immediate");
    socket.set_sndhwm(1000)
          .expect("Failure to set the ZMQ push socket hwm");
    socket.set_sndtimeo(500)
          .expect("Failure to set the ZMQ send timeout");
    let to_addr = format!("{}:{}", member.address, member.gossip_port);
    match socket.connect(&format!("tcp://{}", to_addr)) {
        Ok(()) => debug!("Connected push socket to {:?}", member),
        Err(e) => {
            error!("Cannot connect push socket to {:?}: {:?}", member, e);
            let label_values = &["socket_connect", "failure"];
            GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
            GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
            return;
        }
    }
    'rumorlist: for rumor_key in rumors.iter() {
        let rumor_as_bytes = match rumor_key.kind {
            RumorType::Member => {
                let send_rumor = match create_member_rumor_mlr(&server, &rumor_key) {
                    Some(rumor) => rumor,
                    None => continue 'rumorlist,
                };
                match send_rumor.encode() {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["member_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::Service => {
                match server.service_store.lock_rsr().encode_rumor_for(&rumor_key) {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["service_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::ServiceConfig => {
                match server.service_config_store
                            .lock_rsr()
                            .encode_rumor_for(&rumor_key)
                {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["service_config_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::ServiceFile => {
                match server.service_file_store
                            .lock_rsr()
                            .encode_rumor_for(&rumor_key)
                {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["service_file_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::Departure => {
                match server.departure_store
                            .lock_rsr()
                            .encode_rumor_for(&rumor_key)
                {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["departure_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::Election => {
                match server.election_store
                            .lock_rsr()
                            .encode_rumor_for(&rumor_key)
                {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["election_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::ElectionUpdate => {
                match server.update_store.lock_rsr().encode_rumor_for(&rumor_key) {
                    Ok(bytes) => bytes,
                    Err(e) => {
                        error!("Could not write our own rumor to bytes; abandoning sending \
                                rumor: {:?}",
                               e);
                        let label_values = &["election_update_rumor_encode", "failure"];
                        GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                        GOSSIP_BYTES_SENT.with_label_values(label_values).set(0);
                        continue 'rumorlist;
                    }
                }
            }
            RumorType::Fake | RumorType::Fake2 => {
                debug!("You have fake rumors; how odd!");
                continue 'rumorlist;
            }
        };
        let rumor_len = rumor_as_bytes.len().to_i64();
        let payload = match server.generate_wire(rumor_as_bytes) {
            Ok(payload) => payload,
            Err(e) => {
                error!("Generating protobuf failed: {}", e);
                let label_values = &["generate_wire", "failure"];
                GOSSIP_MESSAGES_SENT.with_label_values(label_values).inc();
                GOSSIP_BYTES_SENT.with_label_values(label_values)
                                 .set(rumor_len);
                continue 'rumorlist;
            }
        };
        match socket.send(&payload, 0) {
            Ok(()) => {
                GOSSIP_MESSAGES_SENT.with_label_values(&[&rumor_key.kind.to_string(), "success"])
                                    .inc();
                GOSSIP_BYTES_SENT.with_label_values(&[&rumor_key.kind.to_string(), "success"])
                                 .set(payload.len().to_i64());
                debug!("Sent rumor {:?} to {:?}", rumor_key, member);
            }
            Err(e) => {
                warn!("Could not send rumor to {:?} @ {:?}; ZMQ said: {:?}",
                      member.id, to_addr, e)
            }
        }
    }

    server.rumor_heat
          .lock_rhw()
          .cool_rumors(&member.id, &rumors);
}

/// Given a rumorkey, creates a protobuf rumor for sharing.
///
/// # Locking (see locking.md)
/// * `MemberList::entries` (read)
fn create_member_rumor_mlr(server: &Server, rumor_key: &RumorKey) -> Option<RumorEnvelope> {
    let member = server.member_list.get_cloned_mlr(&rumor_key.to_string())?;
    let payload = Membership { member,
                               health: server.member_list
                                             .health_of_by_id_mlr(&rumor_key.to_string())
                                             .unwrap() };
    let rumor = RumorEnvelope { r#type:  RumorType::Member,
                                from_id: server.member_id().to_string(),
                                kind:    RumorKind::Membership(payload), };
    Some(rumor)
}
<|endoftext|>


<commit_before>#![feature(path_ext)]
#[cfg(not(windows))]
extern crate pkg_config;
use std::fs::{self, PathExt};
use std::env;
use std::path::Path;
use std::process::Command;

#[cfg(windows)]
static FINAL_LIB:&'static str = "libjit.dll";

#[cfg(not(windows))]
static FINAL_LIB:&'static str = "libjit.a";

static MINGW:&'static str = "c:/mingw";

static INSTALL_AUTOTOOLS_MSG:&'static str = "Failed to generate configuration script. Did you forget to install autotools, bison, flex, and libtool?";

static USE_CARGO_MSG:&'static str = "Build script should be ran with Cargo";

#[cfg(windows)]
static INSTALL_COMPILER_MSG:&'static str = "Failed to configure the library for your platform. Did you forget to install MinGW and MSYS?";
#[cfg(not(windows))]
static INSTALL_COMPILER_MSG:&'static str = "Failed to configure the library for your platform. Did you forget to install gcc or clang?";

fn parse(cmd: &str) -> Command {
	let mut words = cmd.split(' ');
	let mut command = Command::new(words.next().unwrap());
	for arg in words {
		command.arg(arg);
	}
	command
}

fn main() {
	if cfg!(windows) && !Path::new(MINGW).exists() {
		panic!("{}", INSTALL_COMPILER_MSG);
	} else if pkg_config::find_library("jit").is_ok() {
		println!("Copy of LibJIT found on system - no need to build");
		return;
	}
	let out_dir = env::var("OUT_DIR").ok().expect(USE_CARGO_MSG);
	let num_jobs = env::var("NUM_JOBS").ok().expect(USE_CARGO_MSG);
	let out_dir = Path::new(&*out_dir);
	let submod_path = Path::new("libjit");
	let final_lib_dir = submod_path.join("jit/.libs");
	if !final_lib_dir.join(FINAL_LIB).exists() {
		run_wocare(&mut parse("git submodule init"));
		run(&mut parse("git submodule update"));
		if !submod_path.exists() {
			run(Command::new("git").args(&["clone", "git://git.savannah.gnu.org/libjit.git", submod_path.to_str().unwrap()]))
		}
		run_nice(parse("sh auto_gen.sh").current_dir(submod_path), INSTALL_AUTOTOOLS_MSG);
		run_nice(parse("sh configure --enable-static --disable-shared CC=clang CFLAGS=-fPIC").current_dir(submod_path), INSTALL_COMPILER_MSG);
		run(Command::new("make").arg(&format!("-j{}", num_jobs)).current_dir(submod_path));
	}
	let from = final_lib_dir.join(FINAL_LIB);
	let to = out_dir.join(FINAL_LIB);
	if let Err(error) = fs::copy(&from, &to) {
		panic!("Failed to copy library from {:?} to {:?} due to {}", from, to, error)
	}
	println!("cargo:rustc-link-lib=jit");
	println!("cargo:rustc-link-search=native={:?}", out_dir);
}
fn run_nice(cmd: &mut Command, text: &str) {
	if !cmd.status().unwrap().success() {
		panic!("{:?} failed - {}", cmd, text)
	}
}
fn run(cmd: &mut Command) {
	if !cmd.status().unwrap().success() {
		panic!("{:?} failed", cmd)
	}
}
fn run_wocare(cmd: &mut Command) {
	cmd.status().unwrap();
}
<commit_msg>Use more general error message in build script<commit_after>#![feature(path_ext)]
#[cfg(not(windows))]
extern crate pkg_config;
use std::fs::{self, PathExt};
use std::env;
use std::path::Path;
use std::process::Command;

#[cfg(windows)]
static FINAL_LIB:&'static str = "libjit.dll";

#[cfg(not(windows))]
static FINAL_LIB:&'static str = "libjit.a";

static MINGW:&'static str = "c:/mingw";

static INSTALL_AUTOTOOLS_MSG:&'static str = "Failed to generate configuration script. Did you forget to install autotools, bison, flex, and libtool?";

static USE_CARGO_MSG:&'static str = "Build script should be ran with Cargo, run `cargo build` instead";

#[cfg(windows)]
static INSTALL_COMPILER_MSG:&'static str = "Failed to configure the library for your platform. Did you forget to install MinGW and MSYS?";
#[cfg(not(windows))]
static INSTALL_COMPILER_MSG:&'static str = "Failed to configure the library for your platform. Did you forget to install a C compiler?";

fn parse(cmd: &str) -> Command {
	let mut words = cmd.split(' ');
	let mut command = Command::new(words.next().unwrap());
	for arg in words {
		command.arg(arg);
	}
	command
}

fn main() {
	if cfg!(windows) && !Path::new(MINGW).exists() {
		panic!("{}", INSTALL_COMPILER_MSG);
	} else if pkg_config::find_library("jit").is_ok() {
		println!("Copy of LibJIT found on system - no need to build");
		return;
	}
	let out_dir = env::var("OUT_DIR").ok().expect(USE_CARGO_MSG);
	let num_jobs = env::var("NUM_JOBS").ok().expect(USE_CARGO_MSG);
	let out_dir = Path::new(&*out_dir);
    let submod_path = Path::new(&env::var("CARGO_MANIFEST_DIR").ok().expect(USE_CARGO_MSG)).join("libjit");
	let final_lib_dir = submod_path.join("jit/.libs");
	if !final_lib_dir.join(FINAL_LIB).exists() {
		run_wocare(&mut parse("git submodule init"));
		run(&mut parse("git submodule update"));
		if !submod_path.exists() {
			run(Command::new("git").args(&["clone", "git://git.savannah.gnu.org/libjit.git", submod_path.to_str().unwrap()]))
		}
		run_nice(parse("sh auto_gen.sh").current_dir(&submod_path), INSTALL_AUTOTOOLS_MSG);
		run_nice(parse("sh configure --enable-static --disable-shared CFLAGS=-fPIC").current_dir(&submod_path), INSTALL_COMPILER_MSG);
		run(Command::new("make").arg(&format!("-j{}", num_jobs)).current_dir(submod_path));
	}
	let from = final_lib_dir.join(FINAL_LIB);
	let to = out_dir.join(FINAL_LIB);
	if let Err(error) = fs::copy(&from, &to) {
		panic!("Failed to copy library from {:?} to {:?} due to {}", from, to, error)
	}
	println!("cargo:rustc-link-search=native={:?}", out_dir);
	println!("cargo:rustc-link-lib=static=jit");
}
fn run_nice(cmd: &mut Command, text: &str) {
	if !cmd.status().unwrap().success() {
		panic!("{:?} failed - {}", cmd, text)
	}
}
fn run(cmd: &mut Command) {
	if !cmd.status().unwrap().success() {
		panic!("{:?} failed", cmd)
	}
}
fn run_wocare(cmd: &mut Command) {
	cmd.status().unwrap();
}
<|endoftext|>