<commit_before>/// HTTP2 Ping usage
///
/// hyper uses HTTP2 pings for two purposes:
///
/// 1. Adaptive flow control using BDP
/// 2. Connection keep-alive
///
/// Both cases are optional.
///
/// # BDP Algorithm
///
/// 1. When receiving a DATA frame, if a BDP ping isn't outstanding:
///   1a. Record current time.
///   1b. Send a BDP ping.
/// 2. Increment the number of received bytes.
/// 3. When the BDP ping ack is received:
///   3a. Record duration from sent time.
///   3b. Merge RTT with a running average.
///   3c. Calculate bdp as bytes/rtt.
///   3d. If bdp is over 2/3 max, set new max to bdp and update windows.

#[cfg(feature = "runtime")]
use std::fmt;
#[cfg(feature = "runtime")]
use std::future::Future;
#[cfg(feature = "runtime")]
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{self, Poll};
use std::time::Duration;
#[cfg(not(feature = "runtime"))]
use std::time::Instant;

use h2::{Ping, PingPong};
#[cfg(feature = "runtime")]
use tokio::time::{Delay, Instant};

type WindowSize = u32;

pub(super) fn disabled() -> Recorder {
    Recorder { shared: None }
}

pub(super) fn channel(ping_pong: PingPong, config: Config) -> (Recorder, Ponger) {
    debug_assert!(
        config.is_enabled(),
        "ping channel requires bdp or keep-alive config",
    );

    let bdp = config.bdp_initial_window.map(|wnd| Bdp {
        bdp: wnd,
        max_bandwidth: 0.0,
        samples: 0,
        rtt: 0.0,
    });

    let bytes = bdp.as_ref().map(|_| 0);

    #[cfg(feature = "runtime")]
    let keep_alive = config.keep_alive_interval.map(|interval| KeepAlive {
        interval,
        timeout: config.keep_alive_timeout,
        while_idle: config.keep_alive_while_idle,
        timer: tokio::time::delay_for(interval),
        state: KeepAliveState::Init,
    });

    #[cfg(feature = "runtime")]
    let last_read_at = keep_alive.as_ref().map(|_| Instant::now());

    let shared = Arc::new(Mutex::new(Shared {
        bytes,
        #[cfg(feature = "runtime")]
        last_read_at,
        #[cfg(feature = "runtime")]
        is_keep_alive_timed_out: false,
        ping_pong,
        ping_sent_at: None,
    }));

    (
        Recorder {
            shared: Some(shared.clone()),
        },
        Ponger {
            bdp,
            #[cfg(feature = "runtime")]
            keep_alive,
            shared,
        },
    )
}

#[derive(Clone)]
pub(super) struct Config {
    pub(super) bdp_initial_window: Option<WindowSize>,
    /// If no frames are received in this amount of time, a PING frame is sent.
    #[cfg(feature = "runtime")]
    pub(super) keep_alive_interval: Option<Duration>,
    /// After sending a keepalive PING, the connection will be closed if
    /// a pong is not received in this amount of time.
    #[cfg(feature = "runtime")]
    pub(super) keep_alive_timeout: Duration,
    /// If true, sends pings even when there are no active streams.
    #[cfg(feature = "runtime")]
    pub(super) keep_alive_while_idle: bool,
}

#[derive(Clone)]
pub(crate) struct Recorder {
    shared: Option<Arc<Mutex<Shared>>>,
}

pub(super) struct Ponger {
    bdp: Option<Bdp>,
    #[cfg(feature = "runtime")]
    keep_alive: Option<KeepAlive>,
    shared: Arc<Mutex<Shared>>,
}

struct Shared {
    ping_pong: PingPong,
    ping_sent_at: Option<Instant>,

    // bdp
    /// If `Some`, bdp is enabled, and this tracks how many bytes have been
    /// read during the current sample.
    bytes: Option<usize>,

    // keep-alive
    /// If `Some`, keep-alive is enabled, and the Instant is how long ago
    /// the connection read the last frame.
    #[cfg(feature = "runtime")]
    last_read_at: Option<Instant>,

    #[cfg(feature = "runtime")]
    is_keep_alive_timed_out: bool,
}

struct Bdp {
    /// Current BDP in bytes
    bdp: u32,
    /// Largest bandwidth we've seen so far.
    max_bandwidth: f64,
    /// Count of samples made (ping sent and received)
    samples: usize,
    /// Round trip time in seconds
    rtt: f64,
}

#[cfg(feature = "runtime")]
struct KeepAlive {
    /// If no frames are received in this amount of time, a PING frame is sent.
    interval: Duration,
    /// After sending a keepalive PING, the connection will be closed if
    /// a pong is not received in this amount of time.
    timeout: Duration,
    /// If true, sends pings even when there are no active streams.
    while_idle: bool,

    state: KeepAliveState,
    timer: Delay,
}

#[cfg(feature = "runtime")]
enum KeepAliveState {
    Init,
    Scheduled,
    PingSent,
}

pub(super) enum Ponged {
    SizeUpdate(WindowSize),
    #[cfg(feature = "runtime")]
    KeepAliveTimedOut,
}

#[cfg(feature = "runtime")]
#[derive(Debug)]
pub(super) struct KeepAliveTimedOut;

// ===== impl Config =====

impl Config {
    pub(super) fn is_enabled(&self) -> bool {
        #[cfg(feature = "runtime")]
        {
            self.bdp_initial_window.is_some() || self.keep_alive_interval.is_some()
        }

        #[cfg(not(feature = "runtime"))]
        {
            self.bdp_initial_window.is_some()
        }
    }
}

// ===== impl Recorder =====

impl Recorder {
    pub(crate) fn record_data(&self, len: usize) {
        let shared = if let Some(ref shared) = self.shared {
            shared
        } else {
            return;
        };

        let mut locked = shared.lock().unwrap();

        #[cfg(feature = "runtime")]
        locked.update_last_read_at();

        if let Some(ref mut bytes) = locked.bytes {
            *bytes += len;
        } else {
            // no need to send bdp ping if bdp is disabled
            return;
        }

        if !locked.is_ping_sent() {
            locked.send_ping();
        }
    }

    pub(crate) fn record_non_data(&self) {
        #[cfg(feature = "runtime")]
        {
            let shared = if let Some(ref shared) = self.shared {
                shared
            } else {
                return;
            };

            let mut locked = shared.lock().unwrap();

            locked.update_last_read_at();
        }
    }

    /// If the incoming stream is already closed, convert self into
    /// a disabled reporter.
    pub(super) fn for_stream(self, stream: &h2::RecvStream) -> Self {
        if stream.is_end_stream() {
            disabled()
        } else {
            self
        }
    }

    pub(super) fn ensure_not_timed_out(&self) -> crate::Result<()> {
        #[cfg(feature = "runtime")]
        {
            if let Some(ref shared) = self.shared {
                let locked = shared.lock().unwrap();
                if locked.is_keep_alive_timed_out {
                    return Err(KeepAliveTimedOut.crate_error());
                }
            }
        }

        // else
        Ok(())
    }
}

// ===== impl Ponger =====

impl Ponger {
    pub(super) fn poll(&mut self, cx: &mut task::Context<'_>) -> Poll<Ponged> {
        let mut locked = self.shared.lock().unwrap();
        #[cfg(feature = "runtime")]
        let is_idle = self.is_idle();

        #[cfg(feature = "runtime")]
        {
            if let Some(ref mut ka) = self.keep_alive {
                ka.schedule(is_idle, &locked);
                ka.maybe_ping(cx, &mut locked);
            }
        }

        if !locked.is_ping_sent() {
            // XXX: this doesn't register a waker...?
            return Poll::Pending;
        }

        let (bytes, rtt) = match locked.ping_pong.poll_pong(cx) {
            Poll::Ready(Ok(_pong)) => {
                let rtt = locked
                    .ping_sent_at
                    .expect("pong received implies ping_sent_at")
                    .elapsed();
                locked.ping_sent_at = None;
                trace!("recv pong");

                #[cfg(feature = "runtime")]
                {
                    if let Some(ref mut ka) = self.keep_alive {
                        locked.update_last_read_at();
                        ka.schedule(is_idle, &locked);
                    }
                }

                if let Some(ref mut bdp) = self.bdp {
                    let bytes = locked.bytes.expect("bdp enabled implies bytes");
                    locked.bytes = Some(0); // reset
                    bdp.samples += 1;
                    trace!("received BDP ack; bytes = {}, rtt = {:?}", bytes, rtt);
                    (bytes, rtt)
                } else {
                    // no bdp, done!
                    return Poll::Pending;
                }
            }
            Poll::Ready(Err(e)) => {
                debug!("pong error: {}", e);
                return Poll::Pending;
            }
            Poll::Pending => {
                #[cfg(feature = "runtime")]
                {
                    if let Some(ref mut ka) = self.keep_alive {
                        if let Err(KeepAliveTimedOut) = ka.maybe_timeout(cx) {
                            self.keep_alive = None;
                            locked.is_keep_alive_timed_out = true;
                            return Poll::Ready(Ponged::KeepAliveTimedOut);
                        }
                    }
                }

                return Poll::Pending;
            }
        };

        drop(locked);

        if let Some(bdp) = self.bdp.as_mut().and_then(|bdp| bdp.calculate(bytes, rtt)) {
            Poll::Ready(Ponged::SizeUpdate(bdp))
        } else {
            // XXX: this doesn't register a waker...?
            Poll::Pending
        }
    }

    #[cfg(feature = "runtime")]
    fn is_idle(&self) -> bool {
        Arc::strong_count(&self.shared) <= 2
    }
}

// ===== impl Shared =====

impl Shared {
    fn send_ping(&mut self) {
        match self.ping_pong.send_ping(Ping::opaque()) {
            Ok(()) => {
                self.ping_sent_at = Some(Instant::now());
                trace!("sent ping");
            }
            Err(err) => {
                debug!("error sending ping: {}", err);
            }
        }
    }

    fn is_ping_sent(&self) -> bool {
        self.ping_sent_at.is_some()
    }

    #[cfg(feature = "runtime")]
    fn update_last_read_at(&mut self) {
        if self.last_read_at.is_some() {
            self.last_read_at = Some(Instant::now());
        }
    }

    #[cfg(feature = "runtime")]
    fn last_read_at(&self) -> Instant {
        self.last_read_at.expect("keep_alive expects last_read_at")
    }
}

// ===== impl Bdp =====

/// Any higher than this likely will be hitting the TCP flow control.
const BDP_LIMIT: usize = 1024 * 1024 * 16;

impl Bdp {
    fn calculate(&mut self, bytes: usize, rtt: Duration) -> Option<WindowSize> {
        // No need to do any math if we're at the limit.
        if self.bdp as usize == BDP_LIMIT {
            return None;
        }

        // average the rtt
        let rtt = seconds(rtt);
        if self.samples < 10 {
            // Average the first 10 samples
            self.rtt += (rtt - self.rtt) / (self.samples as f64);
        } else {
            self.rtt += (rtt - self.rtt) / 0.9;
        }

        // calculate the current bandwidth
        let bw = (bytes as f64) / (self.rtt * 1.5);
        trace!("current bandwidth = {:.1}B/s", bw);

        if bw < self.max_bandwidth {
            // not a faster bandwidth, so don't update
            return None;
        } else {
            self.max_bandwidth = bw;
        }

        // if the current `bytes` sample is at least 2/3 the previous
        // bdp, increase to double the current sample.
        if (bytes as f64) >= (self.bdp as f64) * 0.66 {
            self.bdp = (bytes * 2).min(BDP_LIMIT) as WindowSize;
            trace!("BDP increased to {}", self.bdp);
            Some(self.bdp)
        } else {
            None
        }
    }
}

fn seconds(dur: Duration) -> f64 {
    const NANOS_PER_SEC: f64 = 1_000_000_000.0;
    let secs = dur.as_secs() as f64;
    secs + (dur.subsec_nanos() as f64) / NANOS_PER_SEC
}

// ===== impl KeepAlive =====

#[cfg(feature = "runtime")]
impl KeepAlive {
    fn schedule(&mut self, is_idle: bool, shared: &Shared) {
        match self.state {
            KeepAliveState::Init => {
                if !self.while_idle && is_idle {
                    return;
                }

                self.state = KeepAliveState::Scheduled;
                let interval = shared.last_read_at() + self.interval;
                self.timer.reset(interval);
            }
            KeepAliveState::Scheduled | KeepAliveState::PingSent => (),
        }
    }

    fn maybe_ping(&mut self, cx: &mut task::Context<'_>, shared: &mut Shared) {
        match self.state {
            KeepAliveState::Scheduled => {
                if Pin::new(&mut self.timer).poll(cx).is_pending() {
                    return;
                }
                // check if we've received a frame while we were scheduled
                if shared.last_read_at() + self.interval > self.timer.deadline() {
                    self.state = KeepAliveState::Init;
                    cx.waker().wake_by_ref(); // schedule us again
                    return;
                }
                trace!("keep-alive interval ({:?}) reached", self.interval);
                shared.send_ping();
                self.state = KeepAliveState::PingSent;
                let timeout = Instant::now() + self.timeout;
                self.timer.reset(timeout);
            }
            KeepAliveState::Init | KeepAliveState::PingSent => (),
        }
    }

    fn maybe_timeout(&mut self, cx: &mut task::Context<'_>) -> Result<(), KeepAliveTimedOut> {
        match self.state {
            KeepAliveState::PingSent => {
                if Pin::new(&mut self.timer).poll(cx).is_pending() {
                    return Ok(());
                }
                trace!("keep-alive timeout ({:?}) reached", self.timeout);
                Err(KeepAliveTimedOut)
            }
            KeepAliveState::Init | KeepAliveState::Scheduled => Ok(()),
        }
    }
}

// ===== impl KeepAliveTimedOut =====

#[cfg(feature = "runtime")]
impl KeepAliveTimedOut {
    pub(super) fn crate_error(self) -> crate::Error {
        crate::Error::new(crate::error::Kind::Http2).with(self)
    }
}

#[cfg(feature = "runtime")]
impl fmt::Display for KeepAliveTimedOut {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("keep-alive timed out")
    }
}

#[cfg(feature = "runtime")]
impl std::error::Error for KeepAliveTimedOut {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        Some(&crate::error::TimedOut)
    }
}
<commit_msg>refactor(http2): change rtt weighted moving average beta to 1/8<commit_after>/// HTTP2 Ping usage
///
/// hyper uses HTTP2 pings for two purposes:
///
/// 1. Adaptive flow control using BDP
/// 2. Connection keep-alive
///
/// Both cases are optional.
///
/// # BDP Algorithm
///
/// 1. When receiving a DATA frame, if a BDP ping isn't outstanding:
///   1a. Record current time.
///   1b. Send a BDP ping.
/// 2. Increment the number of received bytes.
/// 3. When the BDP ping ack is received:
///   3a. Record duration from sent time.
///   3b. Merge RTT with a running average.
///   3c. Calculate bdp as bytes/rtt.
///   3d. If bdp is over 2/3 max, set new max to bdp and update windows.

#[cfg(feature = "runtime")]
use std::fmt;
#[cfg(feature = "runtime")]
use std::future::Future;
#[cfg(feature = "runtime")]
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{self, Poll};
use std::time::Duration;
#[cfg(not(feature = "runtime"))]
use std::time::Instant;

use h2::{Ping, PingPong};
#[cfg(feature = "runtime")]
use tokio::time::{Delay, Instant};

type WindowSize = u32;

pub(super) fn disabled() -> Recorder {
    Recorder { shared: None }
}

pub(super) fn channel(ping_pong: PingPong, config: Config) -> (Recorder, Ponger) {
    debug_assert!(
        config.is_enabled(),
        "ping channel requires bdp or keep-alive config",
    );

    let bdp = config.bdp_initial_window.map(|wnd| Bdp {
        bdp: wnd,
        max_bandwidth: 0.0,
        rtt: 0.0,
    });

    let bytes = bdp.as_ref().map(|_| 0);

    #[cfg(feature = "runtime")]
    let keep_alive = config.keep_alive_interval.map(|interval| KeepAlive {
        interval,
        timeout: config.keep_alive_timeout,
        while_idle: config.keep_alive_while_idle,
        timer: tokio::time::delay_for(interval),
        state: KeepAliveState::Init,
    });

    #[cfg(feature = "runtime")]
    let last_read_at = keep_alive.as_ref().map(|_| Instant::now());

    let shared = Arc::new(Mutex::new(Shared {
        bytes,
        #[cfg(feature = "runtime")]
        last_read_at,
        #[cfg(feature = "runtime")]
        is_keep_alive_timed_out: false,
        ping_pong,
        ping_sent_at: None,
    }));

    (
        Recorder {
            shared: Some(shared.clone()),
        },
        Ponger {
            bdp,
            #[cfg(feature = "runtime")]
            keep_alive,
            shared,
        },
    )
}

#[derive(Clone)]
pub(super) struct Config {
    pub(super) bdp_initial_window: Option<WindowSize>,
    /// If no frames are received in this amount of time, a PING frame is sent.
    #[cfg(feature = "runtime")]
    pub(super) keep_alive_interval: Option<Duration>,
    /// After sending a keepalive PING, the connection will be closed if
    /// a pong is not received in this amount of time.
    #[cfg(feature = "runtime")]
    pub(super) keep_alive_timeout: Duration,
    /// If true, sends pings even when there are no active streams.
    #[cfg(feature = "runtime")]
    pub(super) keep_alive_while_idle: bool,
}

#[derive(Clone)]
pub(crate) struct Recorder {
    shared: Option<Arc<Mutex<Shared>>>,
}

pub(super) struct Ponger {
    bdp: Option<Bdp>,
    #[cfg(feature = "runtime")]
    keep_alive: Option<KeepAlive>,
    shared: Arc<Mutex<Shared>>,
}

struct Shared {
    ping_pong: PingPong,
    ping_sent_at: Option<Instant>,

    // bdp
    /// If `Some`, bdp is enabled, and this tracks how many bytes have been
    /// read during the current sample.
    bytes: Option<usize>,

    // keep-alive
    /// If `Some`, keep-alive is enabled, and the Instant is how long ago
    /// the connection read the last frame.
    #[cfg(feature = "runtime")]
    last_read_at: Option<Instant>,

    #[cfg(feature = "runtime")]
    is_keep_alive_timed_out: bool,
}

struct Bdp {
    /// Current BDP in bytes
    bdp: u32,
    /// Largest bandwidth we've seen so far.
    max_bandwidth: f64,
    /// Round trip time in seconds
    rtt: f64,
}

#[cfg(feature = "runtime")]
struct KeepAlive {
    /// If no frames are received in this amount of time, a PING frame is sent.
    interval: Duration,
    /// After sending a keepalive PING, the connection will be closed if
    /// a pong is not received in this amount of time.
    timeout: Duration,
    /// If true, sends pings even when there are no active streams.
    while_idle: bool,

    state: KeepAliveState,
    timer: Delay,
}

#[cfg(feature = "runtime")]
enum KeepAliveState {
    Init,
    Scheduled,
    PingSent,
}

pub(super) enum Ponged {
    SizeUpdate(WindowSize),
    #[cfg(feature = "runtime")]
    KeepAliveTimedOut,
}

#[cfg(feature = "runtime")]
#[derive(Debug)]
pub(super) struct KeepAliveTimedOut;

// ===== impl Config =====

impl Config {
    pub(super) fn is_enabled(&self) -> bool {
        #[cfg(feature = "runtime")]
        {
            self.bdp_initial_window.is_some() || self.keep_alive_interval.is_some()
        }

        #[cfg(not(feature = "runtime"))]
        {
            self.bdp_initial_window.is_some()
        }
    }
}

// ===== impl Recorder =====

impl Recorder {
    pub(crate) fn record_data(&self, len: usize) {
        let shared = if let Some(ref shared) = self.shared {
            shared
        } else {
            return;
        };

        let mut locked = shared.lock().unwrap();

        #[cfg(feature = "runtime")]
        locked.update_last_read_at();

        if let Some(ref mut bytes) = locked.bytes {
            *bytes += len;
        } else {
            // no need to send bdp ping if bdp is disabled
            return;
        }

        if !locked.is_ping_sent() {
            locked.send_ping();
        }
    }

    pub(crate) fn record_non_data(&self) {
        #[cfg(feature = "runtime")]
        {
            let shared = if let Some(ref shared) = self.shared {
                shared
            } else {
                return;
            };

            let mut locked = shared.lock().unwrap();

            locked.update_last_read_at();
        }
    }

    /// If the incoming stream is already closed, convert self into
    /// a disabled reporter.
    pub(super) fn for_stream(self, stream: &h2::RecvStream) -> Self {
        if stream.is_end_stream() {
            disabled()
        } else {
            self
        }
    }

    pub(super) fn ensure_not_timed_out(&self) -> crate::Result<()> {
        #[cfg(feature = "runtime")]
        {
            if let Some(ref shared) = self.shared {
                let locked = shared.lock().unwrap();
                if locked.is_keep_alive_timed_out {
                    return Err(KeepAliveTimedOut.crate_error());
                }
            }
        }

        // else
        Ok(())
    }
}

// ===== impl Ponger =====

impl Ponger {
    pub(super) fn poll(&mut self, cx: &mut task::Context<'_>) -> Poll<Ponged> {
        let mut locked = self.shared.lock().unwrap();
        #[cfg(feature = "runtime")]
        let is_idle = self.is_idle();

        #[cfg(feature = "runtime")]
        {
            if let Some(ref mut ka) = self.keep_alive {
                ka.schedule(is_idle, &locked);
                ka.maybe_ping(cx, &mut locked);
            }
        }

        if !locked.is_ping_sent() {
            // XXX: this doesn't register a waker...?
            return Poll::Pending;
        }

        let (bytes, rtt) = match locked.ping_pong.poll_pong(cx) {
            Poll::Ready(Ok(_pong)) => {
                let rtt = locked
                    .ping_sent_at
                    .expect("pong received implies ping_sent_at")
                    .elapsed();
                locked.ping_sent_at = None;
                trace!("recv pong");

                #[cfg(feature = "runtime")]
                {
                    if let Some(ref mut ka) = self.keep_alive {
                        locked.update_last_read_at();
                        ka.schedule(is_idle, &locked);
                    }
                }

                if self.bdp.is_some() {
                    let bytes = locked.bytes.expect("bdp enabled implies bytes");
                    locked.bytes = Some(0); // reset
                    trace!("received BDP ack; bytes = {}, rtt = {:?}", bytes, rtt);
                    (bytes, rtt)
                } else {
                    // no bdp, done!
                    return Poll::Pending;
                }
            }
            Poll::Ready(Err(e)) => {
                debug!("pong error: {}", e);
                return Poll::Pending;
            }
            Poll::Pending => {
                #[cfg(feature = "runtime")]
                {
                    if let Some(ref mut ka) = self.keep_alive {
                        if let Err(KeepAliveTimedOut) = ka.maybe_timeout(cx) {
                            self.keep_alive = None;
                            locked.is_keep_alive_timed_out = true;
                            return Poll::Ready(Ponged::KeepAliveTimedOut);
                        }
                    }
                }

                return Poll::Pending;
            }
        };

        drop(locked);

        if let Some(bdp) = self.bdp.as_mut().and_then(|bdp| bdp.calculate(bytes, rtt)) {
            Poll::Ready(Ponged::SizeUpdate(bdp))
        } else {
            // XXX: this doesn't register a waker...?
            Poll::Pending
        }
    }

    #[cfg(feature = "runtime")]
    fn is_idle(&self) -> bool {
        Arc::strong_count(&self.shared) <= 2
    }
}

// ===== impl Shared =====

impl Shared {
    fn send_ping(&mut self) {
        match self.ping_pong.send_ping(Ping::opaque()) {
            Ok(()) => {
                self.ping_sent_at = Some(Instant::now());
                trace!("sent ping");
            }
            Err(err) => {
                debug!("error sending ping: {}", err);
            }
        }
    }

    fn is_ping_sent(&self) -> bool {
        self.ping_sent_at.is_some()
    }

    #[cfg(feature = "runtime")]
    fn update_last_read_at(&mut self) {
        if self.last_read_at.is_some() {
            self.last_read_at = Some(Instant::now());
        }
    }

    #[cfg(feature = "runtime")]
    fn last_read_at(&self) -> Instant {
        self.last_read_at.expect("keep_alive expects last_read_at")
    }
}

// ===== impl Bdp =====

/// Any higher than this likely will be hitting the TCP flow control.
const BDP_LIMIT: usize = 1024 * 1024 * 16;

impl Bdp {
    fn calculate(&mut self, bytes: usize, rtt: Duration) -> Option<WindowSize> {
        // No need to do any math if we're at the limit.
        if self.bdp as usize == BDP_LIMIT {
            return None;
        }

        // average the rtt
        let rtt = seconds(rtt);
        if self.rtt == 0.0 {
            // First sample means rtt is first rtt.
            self.rtt = rtt;
        } else {
            // Weigh this rtt as 1/8 for a moving average.
            self.rtt += (rtt - self.rtt) * 0.125;
        }

        // calculate the current bandwidth
        let bw = (bytes as f64) / (self.rtt * 1.5);
        trace!("current bandwidth = {:.1}B/s", bw);

        if bw < self.max_bandwidth {
            // not a faster bandwidth, so don't update
            return None;
        } else {
            self.max_bandwidth = bw;
        }

        // if the current `bytes` sample is at least 2/3 the previous
        // bdp, increase to double the current sample.
        if bytes >= self.bdp as usize * 2 / 3 {
            self.bdp = (bytes * 2).min(BDP_LIMIT) as WindowSize;
            trace!("BDP increased to {}", self.bdp);
            Some(self.bdp)
        } else {
            None
        }
    }
}

fn seconds(dur: Duration) -> f64 {
    const NANOS_PER_SEC: f64 = 1_000_000_000.0;
    let secs = dur.as_secs() as f64;
    secs + (dur.subsec_nanos() as f64) / NANOS_PER_SEC
}

// ===== impl KeepAlive =====

#[cfg(feature = "runtime")]
impl KeepAlive {
    fn schedule(&mut self, is_idle: bool, shared: &Shared) {
        match self.state {
            KeepAliveState::Init => {
                if !self.while_idle && is_idle {
                    return;
                }

                self.state = KeepAliveState::Scheduled;
                let interval = shared.last_read_at() + self.interval;
                self.timer.reset(interval);
            }
            KeepAliveState::Scheduled | KeepAliveState::PingSent => (),
        }
    }

    fn maybe_ping(&mut self, cx: &mut task::Context<'_>, shared: &mut Shared) {
        match self.state {
            KeepAliveState::Scheduled => {
                if Pin::new(&mut self.timer).poll(cx).is_pending() {
                    return;
                }
                // check if we've received a frame while we were scheduled
                if shared.last_read_at() + self.interval > self.timer.deadline() {
                    self.state = KeepAliveState::Init;
                    cx.waker().wake_by_ref(); // schedule us again
                    return;
                }
                trace!("keep-alive interval ({:?}) reached", self.interval);
                shared.send_ping();
                self.state = KeepAliveState::PingSent;
                let timeout = Instant::now() + self.timeout;
                self.timer.reset(timeout);
            }
            KeepAliveState::Init | KeepAliveState::PingSent => (),
        }
    }

    fn maybe_timeout(&mut self, cx: &mut task::Context<'_>) -> Result<(), KeepAliveTimedOut> {
        match self.state {
            KeepAliveState::PingSent => {
                if Pin::new(&mut self.timer).poll(cx).is_pending() {
                    return Ok(());
                }
                trace!("keep-alive timeout ({:?}) reached", self.timeout);
                Err(KeepAliveTimedOut)
            }
            KeepAliveState::Init | KeepAliveState::Scheduled => Ok(()),
        }
    }
}

// ===== impl KeepAliveTimedOut =====

#[cfg(feature = "runtime")]
impl KeepAliveTimedOut {
    pub(super) fn crate_error(self) -> crate::Error {
        crate::Error::new(crate::error::Kind::Http2).with(self)
    }
}

#[cfg(feature = "runtime")]
impl fmt::Display for KeepAliveTimedOut {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("keep-alive timed out")
    }
}

#[cfg(feature = "runtime")]
impl std::error::Error for KeepAliveTimedOut {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        Some(&crate::error::TimedOut)
    }
}
<|endoftext|>


<commit_before>use buckets::Buckets;
use time;
use std::net::TcpStream;
use std::io::{BufReader, BufRead, Write};
use std::fmt::Write as fmtWrite;

/// Handle the management commands
/// returning the response to send back.
pub fn exec(stream: TcpStream, buckets: &Buckets) {
    let mut reader = BufReader::new(stream);
    let mut done = false;

    while !done {
        let mut buffer = String::new();
        let _ = reader.read_line(&mut buffer);
        let command = buffer.split_whitespace()
            .next()
            .unwrap_or("")
            .to_lowercase();
        let mut writer = reader.get_mut();
        let mut out = String::new();

        // Trigger Deref<Target = str>
        match &*command {
            "help" => {
                out.push_str("Statsd Admin Console:\n");
                out.push_str("\n");
                out.push_str("Available commands:\n");
                out.push_str("stats    - print server stats.\n");
                out.push_str("counters - print counter data.\n");
                out.push_str("gauges   - print gauge data.\n");
                out.push_str("timers   - print timer data.\n");
                out.push_str("clear    - clear stored metrics.\n");
                out.push_str("quit     - close this connection.\n");
            },
            "stats" => {
                let uptime = (time::get_time() - buckets.start_time()).num_seconds();
                write!(out, "uptime: {} seconds\n", uptime).unwrap();
                write!(out, "bad_messages: {}\n", buckets.bad_messages()).unwrap();
                write!(out, "total_messages: {}\n", buckets.total_messages()).unwrap();
                write!(out, "END\n\n").unwrap();
            },
            "counters" => {
                for (key, value) in buckets.counters().iter() {
                    write!(out, " {}: {}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "gauges" => {
                for (key, value) in buckets.gauges().iter() {
                    write!(out, " {}: {}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "timers" => {
                for (key, value) in buckets.timers().iter() {
                    write!(out, " {}: {:?}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "quit" => {
                write!(out, "Good bye!\n\n").unwrap();
                done = true
            },
            x => {
                write!(out, "ERROR - unknown command `{}`\n", x).unwrap();
            }
        }
        let _ = writer.write(&out.as_bytes());
        let _ = writer.flush();
    }
}
<commit_msg>Add stats clearing.<commit_after>use buckets::Buckets;
use time;
use std::net::TcpStream;
use std::io::{BufReader, BufRead, Write};
use std::fmt::Write as fmtWrite;

/// Handle the management commands
/// returning the response to send back.
pub fn exec(stream: TcpStream, buckets: &mut Buckets) {
    let mut reader = BufReader::new(stream);
    let mut done = false;

    while !done {
        let mut buffer = String::new();
        let _ = reader.read_line(&mut buffer);
        let command = buffer.split_whitespace()
            .next()
            .unwrap_or("")
            .to_lowercase();
        let mut writer = reader.get_mut();
        let mut out = String::new();

        // Trigger Deref<Target = str>
        match &*command {
            "help" => {
                out.push_str("Statsd Admin Console:\n");
                out.push_str("\n");
                out.push_str("Available commands:\n");
                out.push_str("stats    - print server stats.\n");
                out.push_str("counters - print counter data.\n");
                out.push_str("gauges   - print gauge data.\n");
                out.push_str("timers   - print timer data.\n");
                out.push_str("clear    - clear stored metrics.\n");
                out.push_str("quit     - close this connection.\n");
            },
            "stats" => {
                let uptime = (time::get_time() - buckets.start_time()).num_seconds();
                write!(out, "uptime: {} seconds\n", uptime).unwrap();
                write!(out, "bad_messages: {}\n", buckets.bad_messages()).unwrap();
                write!(out, "total_messages: {}\n", buckets.total_messages()).unwrap();
                write!(out, "END\n\n").unwrap();
            },
            "counters" => {
                for (key, value) in buckets.counters().iter() {
                    write!(out, " {}: {}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "gauges" => {
                for (key, value) in buckets.gauges().iter() {
                    write!(out, " {}: {}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "timers" => {
                for (key, value) in buckets.timers().iter() {
                    write!(out, " {}: {:?}\n", key, value).unwrap();
                }
                write!(out, "END\n\n").unwrap();
            },
            "quit" => {
                write!(out, "Good bye!\n\n").unwrap();
                done = true
            },
            "clear" => {
                buckets.reset();
                write!(out, "Timers, counters and internal stats cleared.\n").unwrap();
            },
            x => {
                write!(out, "ERROR - unknown command `{}`\n", x).unwrap();
            }
        }
        let _ = writer.write(&out.as_bytes());
        let _ = writer.flush();
    }
}
<|endoftext|>


<commit_before>use std::io::{File};
use std::slice;
use std::fmt;

#[deriving(Show)]
enum OPCode {
	NOP,
	PUSH,
	POP,
	LOAD,
	STORE,
	JMP,
	JZ,
	JNZ,
	ADD,
	SUB,
	MUL,
	DIV,
	PRINT,
	STOP
}

impl fmt::Show for VM {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f,
			   "Stack Pointer: {}\nInstruction Pointer: {}\nRegisters: {}\nInstructions: {}",
			   self.sp,
			   self.ip,
			   self.register.as_slice(),
			   self.instructions.slice(self.ip,self.ip+10))
	}
}

fn new() -> VM {
	VM{sp:0, ip:0, register:[0, ..16], stack:[0, ..256], instructions:[0, ..65536]}
}

impl VM {
	fn push(&mut self) -> () {
		if self.sp >= 254 { fail!("Stack overflow at line {}", self.ip); }
		self.stack[self.sp] = 0;
		for i in range(0, 4) {
			self.stack[self.sp] += self.instructions[self.ip+1+i] as i32 << 8*i;
		}
		self.sp += 1;
		self.ip += 5;
	}

	fn bare_pop(&mut self) -> () {
		let _ = self.pop();
	}

	fn pop(&mut self) -> i32 {
		if self.sp > 0 {
			self.sp -= 1;
		} else {
			fail!("Attempted to pop empty stack at line {}", self.ip);
		}
		self.stack[self.sp]
	}

	fn load(&mut self) -> () {
		let r = self.instructions[self.ip+1];
		self.stack[self.sp] = self.register[r as uint];
		self.sp += 1;
		self.ip += 2;
	}

	fn store(&mut self) -> () {
		let r = self.instructions[self.ip + 1];
		self.register[r as uint] = self.pop();
		self.ip += 2;
	}

	fn jump(&mut self) -> () {
		let mut dest = self.instructions[self.ip+1] as uint;
		dest += self.instructions[self.ip+2] as uint << 8;
		self.ip = dest;
	}

	fn jz(&mut self) -> () {
		let tos = self.pop();
		if tos == 0 {
			self.jump();
		} else {
			self.ip += 3;
		}
	}

	fn jnz(&mut self) -> () {
		let tos = self.pop();
		if tos != 0 {
			self.jump();
		} else{
			self.ip += 3;
		}
	}

	fn add(&mut self) -> () {
		let s1 = self.pop();
		let s2 = self.pop();
		self.stack[self.sp] = s1 + s2;
		self.sp += 1;
		self.ip += 1;
	}

	fn sub(&mut self) -> () {
		let s1 = self.pop();
		let s2 = self.pop();
		self.stack[self.sp] = s2 - s1;
		self.sp += 1;
		self.ip += 1;
	}

	fn mul(&mut self) -> () {
		let s1 = self.pop();
		let s2 = self.pop();
		self.stack[self.sp] = s2 * s1;
		self.sp += 1;
		self.ip += 1;
	}

	fn div(&mut self) -> () {
		let s1 = self.pop();
		let s2 = self.pop();
		self.stack[self.sp] = s2 / s1;
		self.sp += 1;
		self.ip += 1;
	}

	fn print(&mut self) -> () {
		let tos = self.pop();
		println!("{}", tos);
		self.ip += 1;
	}

	fn execute(&mut self) -> () {
		let mut i = 0u;
		loop {
			println!("{}", self);
			println!("Stack: {}\n", self.stack.slice(0,10));
			match self.instructions[self.ip] {
				0x00 => (),
				0x01 => self.push(),
				0x02 => self.bare_pop(),
				0x03 => self.load(),
				0x04 => self.store(),
				0x05 => self.jump(),
				0x06 => self.jz(),
				0x07 => self.jnz(),
				0x08 => self.add(),
				0x09 => self.sub(),
				0x0a => self.mul(),
				0x0b => self.div(),
				0x0c => self.print(),
				0x0d => break,
				x => println!("Encountered {}", x)
			}
			i += 1;
			//if i > 15 {break;}
		}
	}
}

struct VM  {
	sp : uint,
	ip : uint,
	register : [i32, ..16],
	stack : [i32, ..256],
	instructions : [u8, ..65536],
}

fn main() {
	let mut x  = new();
	match File::open(&Path::new("factorial.bcm")).read_to_end() {
		Ok(contents) => slice::bytes::copy_memory(x.instructions, contents.as_slice()),
		Err(e) => println!("Failed to read factorial.bcm with error {}", e),
	}

	x.execute();

}
<commit_msg>Retab<commit_after>use std::io::{File};
use std::slice;
use std::fmt;

#[deriving(Show)]
enum OPCode {
    NOP,
    PUSH,
    POP,
    LOAD,
    STORE,
    JMP,
    JZ,
    JNZ,
    ADD,
    SUB,
    MUL,
    DIV,
    PRINT,
    STOP
}

impl fmt::Show for VM {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "Stack Pointer: {}\nInstruction Pointer: {}\nRegisters: {}\nInstructions: {}",
               self.sp,
               self.ip,
               self.register.as_slice(),
               self.instructions.slice(self.ip,self.ip+10))
    }
}

fn new() -> VM {
    VM{sp:0, ip:0, register:[0, ..16], stack:[0, ..256], instructions:[0, ..65536]}
}

impl VM {
    fn push(&mut self) -> () {
        if self.sp >= 254 { fail!("Stack overflow at line {}", self.ip); }
        self.stack[self.sp] = 0;
        for i in range(0, 4) {
            self.stack[self.sp] += self.instructions[self.ip+1+i] as i32 << 8*i;
        }
        self.sp += 1;
        self.ip += 5;
    }

    fn bare_pop(&mut self) -> () {
        let _ = self.pop();
    }

    fn pop(&mut self) -> i32 {
        if self.sp > 0 {
            self.sp -= 1;
        } else {
            fail!("Attempted to pop empty stack at line {}", self.ip);
        }
        self.stack[self.sp]
    }

    fn load(&mut self) -> () {
        let r = self.instructions[self.ip+1];
        self.stack[self.sp] = self.register[r as uint];
        self.sp += 1;
        self.ip += 2;
    }

    fn store(&mut self) -> () {
        let r = self.instructions[self.ip + 1];
        self.register[r as uint] = self.pop();
        self.ip += 2;
    }

    fn jump(&mut self) -> () {
        let mut dest = self.instructions[self.ip+1] as uint;
        dest += self.instructions[self.ip+2] as uint << 8;
        self.ip = dest;
    }

    fn jz(&mut self) -> () {
        let tos = self.pop();
        if tos == 0 {
            self.jump();
        } else {
            self.ip += 3;
        }
    }

    fn jnz(&mut self) -> () {
        let tos = self.pop();
        if tos != 0 {
            self.jump();
        } else{
            self.ip += 3;
        }
    }

    fn add(&mut self) -> () {
        let s1 = self.pop();
        let s2 = self.pop();
        self.stack[self.sp] = s1 + s2;
        self.sp += 1;
        self.ip += 1;
    }

    fn sub(&mut self) -> () {
        let s1 = self.pop();
        let s2 = self.pop();
        self.stack[self.sp] = s2 - s1;
        self.sp += 1;
        self.ip += 1;
    }

    fn mul(&mut self) -> () {
        let s1 = self.pop();
        let s2 = self.pop();
        self.stack[self.sp] = s2 * s1;
        self.sp += 1;
        self.ip += 1;
    }

    fn div(&mut self) -> () {
        let s1 = self.pop();
        let s2 = self.pop();
        self.stack[self.sp] = s2 / s1;
        self.sp += 1;
        self.ip += 1;
    }

    fn print(&mut self) -> () {
        let tos = self.pop();
        println!("{}", tos);
        self.ip += 1;
    }

    fn execute(&mut self) -> () {
        let mut i = 0u;
        loop {
            println!("{}", self);
            println!("Stack: {}\n", self.stack.slice(0,10));
            match self.instructions[self.ip] {
                0x00 => (),
                0x01 => self.push(),
                0x02 => self.bare_pop(),
                0x03 => self.load(),
                0x04 => self.store(),
                0x05 => self.jump(),
                0x06 => self.jz(),
                0x07 => self.jnz(),
                0x08 => self.add(),
                0x09 => self.sub(),
                0x0a => self.mul(),
                0x0b => self.div(),
                0x0c => self.print(),
                0x0d => break,
                x => println!("Encountered {}", x)
            }
            i += 1;
            //if i > 15 {break;}
        }
    }
}

struct VM  {
    sp : uint,
    ip : uint,
    register : [i32, ..16],
    stack : [i32, ..256],
    instructions : [u8, ..65536],
}

fn main() {
    let mut x  = new();
    match File::open(&Path::new("factorial.bcm")).read_to_end() {
        Ok(contents) => slice::bytes::copy_memory(x.instructions, contents.as_slice()),
        Err(e) => println!("Failed to read factorial.bcm with error {}", e),
    }

    x.execute();

}
<|endoftext|>


<commit_before>//! The two public types `Resolver` and `Query`.
//!
//! These two are here together because `Query` needs to be able to access
//! `Resolver`’s transport handles yet I don’t want to expose them publicly.

use std::io;
use std::sync::Arc;
use futures::{Async, Future, Poll};
use rand::random;
use tokio_core::reactor;
use ::bits::{DName, MessageBuf, Question};
use ::iana::Rcode;
use super::conf::{ResolvConf, ResolvOptions};
use super::error::Error;
use super::request::{QueryRequest, RequestMessage, TransportHandle};
use super::tcp::tcp_transport;
use super::udp::udp_transport;

//------------ Resolver ------------------------------------------------------

/// Access to a DNS resolver.
///
/// This type collects all information making it possible to start DNS
/// queries. You can create a new resoler using the system’s configuration
/// using the [`new()`] associate function or using your own configuration
/// with [`from_conf()`]. Either function will spawn everything necessary
/// into a `tokio_core` reactor core represented by a handle.
///
/// Resolver values can be cloned relatively cheaply as they keep all
/// information behind an arc. This is may already be useful when starting
/// a query using the [`query()`] method. Since queries need their own copy
/// of resolver, the method consumes the resolver leaving it to clone it if
/// you need it later on or saving a clone if you don’t.
///
/// If you want to run a single query or lookup on a resolver synchronously,
/// you can safe yourself all the boiler plate of creating a reactor core
/// (even if this is nowhere near as dangerous as it sounds) and resolver by
/// using the [`run()`] or [`run_with_conf()`] associated functions.
///
/// [`new()`]: #method.new
/// [`from_conf()`]: #method.from_conf
/// [`query()`]: #method.query
/// [`run()`]: #method.run
/// [`run_with_conf()`]: #method.run_with_conf
#[derive(Clone, Debug)]
pub struct Resolver(Arc<ResolverInner>);

/// The actual resolver.
#[derive(Clone, Debug)]
struct ResolverInner {
    /// Handles to all UDP transports.
    udp: Vec<TransportHandle>,

    /// Handles to all TCP transports.
    tcp: Vec<TransportHandle>,

    /// Our resolver configuration.
    conf: ResolvConf,
}

impl Resolver {
    /// Creates a new resolver using the system’s default configuration.
    ///
    /// All the networking components of the resolver will be spawned into
    /// the reactor core referenced by `reactor`.
    pub fn new(reactor: &reactor::Handle) -> Self {
        Self::from_conf(reactor, ResolvConf::default())
    }

    /// Creates a new resolver using the given configuration.
    ///
    /// All the components of the resolver will be spawned into the reactor
    /// referenced by `reactor`.
    pub fn from_conf(reactor: &reactor::Handle, conf: ResolvConf)
                     -> Self {
        let mut udp = Vec::new();
        let mut tcp = Vec::new();

        for server in &conf.servers {
            if let Some(transport) = udp_transport(reactor, server) {
                udp.push(transport)
            }
            if let Some(transport) = tcp_transport(reactor, server) {
                tcp.push(transport)
            }
        }

        Resolver(Arc::new(ResolverInner {
            udp: udp,
            tcp: tcp,
            conf: conf
        }))
    }

    /// Trades the resolver for a DNS query.
    ///
    /// This starts a query for something that can be turned into a question.
    /// In particular, both a tripel of a domain name, record type, and class
    /// as well as a pair of domain name and record type can be turned into
    /// a question, the latter assuming the class IN.
    ///
    /// If you need to keep the resolver, clone it before calling `query()`.
    pub fn query<N, Q>(self, question: Q) -> Query
                 where N: DName, Q: Into<Question<N>> {
        Query::new(self, question)
    }

    /// Returns a reference to the list of UDP service handles.
    fn udp(&self) -> &[TransportHandle] {
        &self.0.udp
    }

    /// Returns a reference to the list of TCP service handles.
    fn tcp(&self) -> &[TransportHandle] {
        &self.0.tcp
    }

    /// Returns a reference to the configuration of this resolver.
    pub fn conf(&self) -> &ResolvConf {
        &self.0.conf
    }

    /// Returns a reference to the configuration options of this resolver.
    pub fn options(&self) -> &ResolvOptions {
        &self.0.conf.options
    }
}

/// # Shortcuts
///
impl Resolver {
    /// Synchronously perform a DNS operation atop a standard resolver.
    ///
    /// This associated functions removes almost all boiler plate for the
    /// case that you want to perform some DNS operation, either a query or
    /// lookup, on a resolver using the system’s configuration and wait for
    /// the result.
    ///
    /// The only argument is a closure taking a `Resolver` and returning a
    /// future. Whatever that future resolves to will be returned.
    pub fn run<R, F>(op: F) -> Result<R::Item, R::Error>
               where R: Future,
                     R::Error: From<io::Error>,
                     F: FnOnce(Resolver) -> R {
        Self::run_with_conf(ResolvConf::default(), op)
    }

    /// Synchronously perform a DNS operation atop a configuredresolver.
    ///
    /// This is like [`run()`] but also takes a resolver configuration for
    /// tailor-making your own resolver.
    ///
    /// [`run()`]: #method.run
    pub fn run_with_conf<R, F>(conf: ResolvConf, op: F)
                               -> Result<R::Item, R::Error>
                         where R: Future,
                               R::Error: From<io::Error>,
                               F: FnOnce(Resolver) -> R {
        let mut reactor = reactor::Core::new()?;
        let resolver = Self::from_conf(&reactor.handle(), conf);
        reactor.run(op(resolver))
    }
}

//------------ Query ---------------------------------------------------------

/// A DNS query.
///
/// A query is a future that resolves a DNS question for all the resource
/// records for a given domain name, record type, and class into either a
/// successful response or query error. It will follow the rules set down
/// by the resolver configuration in trying to find an upstream server that
/// replies to the question.
///
/// While you can start a query directly by calling the `Query::new()`
/// function, the resolver’s `query()` method may be more convenient.
//
//  Since a query can fail very early on when building the request message,
//  but we don’t really want to complicate things by `Query::new()` returning
//  a result, it internally consists of that `Result`. If it is `Ok()`, we
//  really do have a query to poll, otherwise we have an error to take out
//  and return.
//
//  This is okay because the early failure should be rather unlikely.
pub struct Query(Result<QueryInner, Option<Error>>);

impl Query {
    /// Starts a new query.
    pub fn new<N, Q>(resolv: Resolver, question: Q) -> Self
               where N: DName, Q: Into<Question<N>> {
        let message = match RequestMessage::new(question, resolv.conf()) {
            Ok(message) => message,
            Err(err) => return Query(Err(Some(err.into())))
        };
        Query(Ok(QueryInner::new(resolv, message)))
    }
}

//--- Future

impl Future for Query {
    type Item = MessageBuf;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.0 {
            Ok(ref mut inner) => inner.poll(),
            Err(ref mut err) => {
                match err.take() {
                    Some(err) => Err(err),
                    None => panic!("polling a resolved Query")
                }
            }
        }
    }
}

//------------ QueryInner ----------------------------------------------------

struct QueryInner {
    /// The resolver we are working with.
    resolver: Resolver,

    /// The request we are currently processing.
    request: QueryRequest,

    /// Are we on datagram track?
    ///
    /// A query can be in one of two *tracks,* datagram track or stream
    /// track. Unless the config states that we should use the stream
    /// track only, we will start out in datagram track and only switch to
    /// the stream track if we receive a truncated response.
    dgram: bool,

    /// The index of the service we started at.
    ///
    /// The index references either `resolver.udp` or `resolver.tcp`,
    /// depending on the value of `dgram`. We need to keep the index we
    /// started at because of the rotate option which makes us start at a
    /// random service.
    start_index: usize,

    /// The index of the service we currently are using.
    curr_index: usize,

    /// The how-many-th attempt this is, starting at attempt 0.
    attempt: usize,
}

impl QueryInner {
    fn new(resolver: Resolver, message: RequestMessage) -> Self {
        let dgram = !resolver.options().use_vc;
        let (index, request) = Self::start(&resolver, dgram, message);
        QueryInner {
            resolver: resolver,
            request: request,
            dgram: dgram,
            start_index: index,
            curr_index: index,
            attempt: 0
        }
    }

    /// Processes a response received from a request.
    ///
    /// This will either resolve the future or switch to stream mode and
    /// continue.
    fn response(&mut self, response: MessageBuf, message: RequestMessage)
                -> Poll<MessageBuf, Error> {
        if response.header().tc() && self.dgram
                && !self.resolver.options().ign_tc {
            self.start_stream(message)
        }
        else if response.header().rcode() != Rcode::NoError {
            Err(response.header().rcode().into())
        }
        else {
            Ok(Async::Ready(response))
        }
    }

    /// Processes an error received from a request.
    ///
    /// Proceeds to the next request or errors out.
    fn error(&mut self, _error: Error, message: RequestMessage)
             -> Poll<MessageBuf, Error> {
        self.curr_index += 1;
        if (self.curr_index % self.track().len()) == self.start_index {
            self.attempt += 1;
            if self.attempt == self.resolver.conf().attempts {
                return Err(Error::Timeout)
            }
            let (index, request) = Self::start(&self.resolver,
                                               self.dgram, message);
            self.start_index = index;
            self.curr_index = index;
            self.request = request;
        }
        else {
            self.request = QueryRequest::new(message,
                                             &self.track()[self.curr_index]);
        }
        self.poll()
    }

    /// Switches to stream mode and starts the first request.
    fn start_stream(&mut self, message: RequestMessage)
                    -> Poll<MessageBuf, Error> {
        self.dgram = false;
        let (index, request) = Self::start(&self.resolver, false,
                                           message);
        self.start_index = index;
        self.curr_index = index;
        self.request = request;
        self.poll()
    }

    /// Determines the start index and request for a new attempt.
    fn start(resolver: &Resolver, dgram: bool, message: RequestMessage)
             -> (usize, QueryRequest) {
        let track = if dgram { resolver.udp() }
                    else { resolver.tcp() };
        let index = if resolver.options().rotate {
            random::<usize>() % track.len()
        }
        else { 0 };
        let request = QueryRequest::new(message, &track[index]);
        (index, request)
    }

    /// Returns the current track.
    ///
    /// This is either the UDP or TCP service handles of the resolver,
    /// depending on whether we are in datagram or stream mode.
    fn track(&self) -> &[TransportHandle] {
        if self.dgram {
            self.resolver.udp()
        }
        else {
            self.resolver.tcp()
        }
    }
}

//--- Future

impl Future for QueryInner {
    type Item = MessageBuf;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.request.poll() {
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Ok(Async::Ready((response, message))) => {
                self.response(response, message)
            }
            Err((error, message)) => {
                self.error(error, message)
            }
        }
    }
}

<commit_msg>Keep QueryInner::curr_index within the track’s length.<commit_after>//! The two public types `Resolver` and `Query`.
//!
//! These two are here together because `Query` needs to be able to access
//! `Resolver`’s transport handles yet I don’t want to expose them publicly.

use std::io;
use std::sync::Arc;
use futures::{Async, Future, Poll};
use rand::random;
use tokio_core::reactor;
use ::bits::{DName, MessageBuf, Question};
use ::iana::Rcode;
use super::conf::{ResolvConf, ResolvOptions};
use super::error::Error;
use super::request::{QueryRequest, RequestMessage, TransportHandle};
use super::tcp::tcp_transport;
use super::udp::udp_transport;

//------------ Resolver ------------------------------------------------------

/// Access to a DNS resolver.
///
/// This type collects all information making it possible to start DNS
/// queries. You can create a new resoler using the system’s configuration
/// using the [`new()`] associate function or using your own configuration
/// with [`from_conf()`]. Either function will spawn everything necessary
/// into a `tokio_core` reactor core represented by a handle.
///
/// Resolver values can be cloned relatively cheaply as they keep all
/// information behind an arc. This is may already be useful when starting
/// a query using the [`query()`] method. Since queries need their own copy
/// of resolver, the method consumes the resolver leaving it to clone it if
/// you need it later on or saving a clone if you don’t.
///
/// If you want to run a single query or lookup on a resolver synchronously,
/// you can safe yourself all the boiler plate of creating a reactor core
/// (even if this is nowhere near as dangerous as it sounds) and resolver by
/// using the [`run()`] or [`run_with_conf()`] associated functions.
///
/// [`new()`]: #method.new
/// [`from_conf()`]: #method.from_conf
/// [`query()`]: #method.query
/// [`run()`]: #method.run
/// [`run_with_conf()`]: #method.run_with_conf
#[derive(Clone, Debug)]
pub struct Resolver(Arc<ResolverInner>);

/// The actual resolver.
#[derive(Clone, Debug)]
struct ResolverInner {
    /// Handles to all UDP transports.
    udp: Vec<TransportHandle>,

    /// Handles to all TCP transports.
    tcp: Vec<TransportHandle>,

    /// Our resolver configuration.
    conf: ResolvConf,
}

impl Resolver {
    /// Creates a new resolver using the system’s default configuration.
    ///
    /// All the networking components of the resolver will be spawned into
    /// the reactor core referenced by `reactor`.
    pub fn new(reactor: &reactor::Handle) -> Self {
        Self::from_conf(reactor, ResolvConf::default())
    }

    /// Creates a new resolver using the given configuration.
    ///
    /// All the components of the resolver will be spawned into the reactor
    /// referenced by `reactor`.
    pub fn from_conf(reactor: &reactor::Handle, conf: ResolvConf)
                     -> Self {
        let mut udp = Vec::new();
        let mut tcp = Vec::new();

        for server in &conf.servers {
            if let Some(transport) = udp_transport(reactor, server) {
                udp.push(transport)
            }
            if let Some(transport) = tcp_transport(reactor, server) {
                tcp.push(transport)
            }
        }

        Resolver(Arc::new(ResolverInner {
            udp: udp,
            tcp: tcp,
            conf: conf
        }))
    }

    /// Trades the resolver for a DNS query.
    ///
    /// This starts a query for something that can be turned into a question.
    /// In particular, both a tripel of a domain name, record type, and class
    /// as well as a pair of domain name and record type can be turned into
    /// a question, the latter assuming the class IN.
    ///
    /// If you need to keep the resolver, clone it before calling `query()`.
    pub fn query<N, Q>(self, question: Q) -> Query
                 where N: DName, Q: Into<Question<N>> {
        Query::new(self, question)
    }

    /// Returns a reference to the list of UDP service handles.
    fn udp(&self) -> &[TransportHandle] {
        &self.0.udp
    }

    /// Returns a reference to the list of TCP service handles.
    fn tcp(&self) -> &[TransportHandle] {
        &self.0.tcp
    }

    /// Returns a reference to the configuration of this resolver.
    pub fn conf(&self) -> &ResolvConf {
        &self.0.conf
    }

    /// Returns a reference to the configuration options of this resolver.
    pub fn options(&self) -> &ResolvOptions {
        &self.0.conf.options
    }
}

/// # Shortcuts
///
impl Resolver {
    /// Synchronously perform a DNS operation atop a standard resolver.
    ///
    /// This associated functions removes almost all boiler plate for the
    /// case that you want to perform some DNS operation, either a query or
    /// lookup, on a resolver using the system’s configuration and wait for
    /// the result.
    ///
    /// The only argument is a closure taking a `Resolver` and returning a
    /// future. Whatever that future resolves to will be returned.
    pub fn run<R, F>(op: F) -> Result<R::Item, R::Error>
               where R: Future,
                     R::Error: From<io::Error>,
                     F: FnOnce(Resolver) -> R {
        Self::run_with_conf(ResolvConf::default(), op)
    }

    /// Synchronously perform a DNS operation atop a configuredresolver.
    ///
    /// This is like [`run()`] but also takes a resolver configuration for
    /// tailor-making your own resolver.
    ///
    /// [`run()`]: #method.run
    pub fn run_with_conf<R, F>(conf: ResolvConf, op: F)
                               -> Result<R::Item, R::Error>
                         where R: Future,
                               R::Error: From<io::Error>,
                               F: FnOnce(Resolver) -> R {
        let mut reactor = reactor::Core::new()?;
        let resolver = Self::from_conf(&reactor.handle(), conf);
        reactor.run(op(resolver))
    }
}

//------------ Query ---------------------------------------------------------

/// A DNS query.
///
/// A query is a future that resolves a DNS question for all the resource
/// records for a given domain name, record type, and class into either a
/// successful response or query error. It will follow the rules set down
/// by the resolver configuration in trying to find an upstream server that
/// replies to the question.
///
/// While you can start a query directly by calling the `Query::new()`
/// function, the resolver’s `query()` method may be more convenient.
//
//  Since a query can fail very early on when building the request message,
//  but we don’t really want to complicate things by `Query::new()` returning
//  a result, it internally consists of that `Result`. If it is `Ok()`, we
//  really do have a query to poll, otherwise we have an error to take out
//  and return.
//
//  This is okay because the early failure should be rather unlikely.
pub struct Query(Result<QueryInner, Option<Error>>);

impl Query {
    /// Starts a new query.
    pub fn new<N, Q>(resolv: Resolver, question: Q) -> Self
               where N: DName, Q: Into<Question<N>> {
        let message = match RequestMessage::new(question, resolv.conf()) {
            Ok(message) => message,
            Err(err) => return Query(Err(Some(err.into())))
        };
        Query(Ok(QueryInner::new(resolv, message)))
    }
}

//--- Future

impl Future for Query {
    type Item = MessageBuf;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.0 {
            Ok(ref mut inner) => inner.poll(),
            Err(ref mut err) => {
                match err.take() {
                    Some(err) => Err(err),
                    None => panic!("polling a resolved Query")
                }
            }
        }
    }
}

//------------ QueryInner ----------------------------------------------------

struct QueryInner {
    /// The resolver we are working with.
    resolver: Resolver,

    /// The request we are currently processing.
    request: QueryRequest,

    /// Are we on datagram track?
    ///
    /// A query can be in one of two *tracks,* datagram track or stream
    /// track. Unless the config states that we should use the stream
    /// track only, we will start out in datagram track and only switch to
    /// the stream track if we receive a truncated response.
    dgram: bool,

    /// The index of the service we started at.
    ///
    /// The index references either `resolver.udp` or `resolver.tcp`,
    /// depending on the value of `dgram`. We need to keep the index we
    /// started at because of the rotate option which makes us start at a
    /// random service.
    start_index: usize,

    /// The index of the service we currently are using.
    curr_index: usize,

    /// The how-many-th attempt this is, starting at attempt 0.
    attempt: usize,
}

impl QueryInner {
    fn new(resolver: Resolver, message: RequestMessage) -> Self {
        let dgram = !resolver.options().use_vc;
        let (index, request) = Self::start(&resolver, dgram, message);
        QueryInner {
            resolver: resolver,
            request: request,
            dgram: dgram,
            start_index: index,
            curr_index: index,
            attempt: 0
        }
    }

    /// Processes a response received from a request.
    ///
    /// This will either resolve the future or switch to stream mode and
    /// continue.
    fn response(&mut self, response: MessageBuf, message: RequestMessage)
                -> Poll<MessageBuf, Error> {
        if response.header().tc() && self.dgram
                && !self.resolver.options().ign_tc {
            self.start_stream(message)
        }
        else if response.header().rcode() != Rcode::NoError {
            Err(response.header().rcode().into())
        }
        else {
            Ok(Async::Ready(response))
        }
    }

    /// Processes an error received from a request.
    ///
    /// Proceeds to the next request or errors out.
    fn error(&mut self, _error: Error, message: RequestMessage)
             -> Poll<MessageBuf, Error> {
        self.curr_index = (self.curr_index + 1) % self.track().len();
        if self.curr_index == self.start_index {
            self.attempt += 1;
            if self.attempt == self.resolver.conf().attempts {
                return Err(Error::Timeout)
            }
            let (index, request) = Self::start(&self.resolver,
                                               self.dgram, message);
            self.start_index = index;
            self.curr_index = index;
            self.request = request;
        }
        else {
            self.request = QueryRequest::new(message,
                                             &self.track()[self.curr_index]);
        }
        self.poll()
    }

    /// Switches to stream mode and starts the first request.
    fn start_stream(&mut self, message: RequestMessage)
                    -> Poll<MessageBuf, Error> {
        self.dgram = false;
        let (index, request) = Self::start(&self.resolver, false,
                                           message);
        self.start_index = index;
        self.curr_index = index;
        self.request = request;
        self.poll()
    }

    /// Determines the start index and request for a new attempt.
    fn start(resolver: &Resolver, dgram: bool, message: RequestMessage)
             -> (usize, QueryRequest) {
        let track = if dgram { resolver.udp() }
                    else { resolver.tcp() };
        let index = if resolver.options().rotate {
            random::<usize>() % track.len()
        }
        else { 0 };
        let request = QueryRequest::new(message, &track[index]);
        (index, request)
    }

    /// Returns the current track.
    ///
    /// This is either the UDP or TCP service handles of the resolver,
    /// depending on whether we are in datagram or stream mode.
    fn track(&self) -> &[TransportHandle] {
        if self.dgram {
            self.resolver.udp()
        }
        else {
            self.resolver.tcp()
        }
    }
}

//--- Future

impl Future for QueryInner {
    type Item = MessageBuf;
    type Error = Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.request.poll() {
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Ok(Async::Ready((response, message))) => {
                self.response(response, message)
            }
            Err((error, message)) => {
                self.error(error, message)
            }
        }
    }
}

<|endoftext|>


<commit_before>use {Backend, QueueFamily};
use device::{Device, PhysicalDevice};
use internal::Channel;
use native;

use std::sync::Arc;
use std::thread;

use hal::{self, format, image};
use hal::{Backbuffer, SwapchainConfig};
use hal::window::Extent2D;

use core_graphics::geometry::{CGRect, CGSize};
use foreign_types::{ForeignType, ForeignTypeRef};
use parking_lot::{Mutex, MutexGuard};
use metal;
use objc::rc::autoreleasepool;
use objc::runtime::Object;

pub type CAMetalLayer = *mut Object;

pub struct Surface {
    inner: Arc<SurfaceInner>,
    main_thread_id: thread::ThreadId,
    has_swapchain: bool,
}

#[derive(Debug)]
pub(crate) struct SurfaceInner {
    pub(crate) view: *mut Object,
    pub(crate) render_layer: Mutex<CAMetalLayer>,
}

unsafe impl Send for SurfaceInner {}
unsafe impl Sync for SurfaceInner {}

impl Drop for SurfaceInner {
    fn drop(&mut self) {
        unsafe { msg_send![self.view, release]; }
    }
}

impl SurfaceInner {
    pub(crate) fn into_surface(self) -> Surface {
        Surface {
            inner: Arc::new(self),
            main_thread_id: thread::current().id(),
            has_swapchain: false,
        }
    }

    fn next_frame<'a>(&self, frames: &'a [Frame]) -> Result<(usize, MutexGuard<'a, FrameInner>), ()> {
        let layer_ref = self.render_layer.lock();
        autoreleasepool(|| { // for the drawable
            let (drawable, texture_temp): (&metal::DrawableRef, &metal::TextureRef) = unsafe {
                let drawable = msg_send![*layer_ref, nextDrawable];
                (drawable, msg_send![drawable, texture])
            };

            trace!("looking for {:?}", texture_temp);
            match frames.iter().position(|f| f.texture.as_ptr() == texture_temp.as_ptr()) {
                Some(index) => {
                    let mut frame = frames[index].inner.lock();
                    assert!(frame.drawable.is_none());
                    frame.drawable = Some(drawable.to_owned());

                    debug!("next is frame[{}]", index);
                    Ok((index, frame))
                }
                None => Err(()),
            }
        })
    }
}

#[derive(Debug)]
struct FrameInner {
    drawable: Option<metal::Drawable>,
    /// If there is a `drawable`, availability indicates if it's free for grabs.
    /// If there is `None`, `available == false` means that the frame has already
    /// been acquired and the `drawable` will appear at some point.
    available: bool,
    last_frame: usize,
}

#[derive(Debug)]
struct Frame {
    inner: Mutex<FrameInner>,
    texture: metal::Texture,
}

unsafe impl Send for Frame {}
unsafe impl Sync for Frame {}

impl Drop for Frame {
    fn drop(&mut self) {
        info!("dropping Frame");
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AcquireMode {
    Wait,
    Oldest,
}

pub struct Swapchain {
    frames: Arc<Vec<Frame>>,
    surface: Arc<SurfaceInner>,
    extent: Extent2D,
    last_frame: usize,
    image_ready_callbacks: Vec<Arc<Mutex<Option<SwapchainImage>>>>,
    pub acquire_mode: AcquireMode,
}

impl Drop for Swapchain {
    fn drop(&mut self) {
        info!("dropping Swapchain");
        for ir in self.image_ready_callbacks.drain(..) {
            if ir.lock().take().is_some() {
                debug!("\twith a callback");
            }
        }
    }
}

impl Swapchain {
    /// Returns the drawable for the specified swapchain image index,
    /// marks the index as free for future use.
    pub(crate) fn take_drawable(&self, index: hal::SwapImageIndex) -> metal::Drawable {
        let mut frame = self
            .frames[index as usize]
            .inner
            .lock();
        assert!(!frame.available);
        frame.available = true;
        frame.drawable
            .take()
            .expect("Drawable has not been acquired!")
    }

    fn signal_sync(&self, sync: hal::FrameSync<Backend>) {
        match sync {
            hal::FrameSync::Semaphore(semaphore) => {
                if let Some(ref system) = semaphore.system {
                    system.signal();
                }
            }
            hal::FrameSync::Fence(fence) => {
                *fence.0.borrow_mut() = native::FenceInner::Idle { signaled: true };
            }
        }
    }
}

#[derive(Debug)]
pub struct SwapchainImage {
    frames: Arc<Vec<Frame>>,
    surface: Arc<SurfaceInner>,
    index: hal::SwapImageIndex,
}

impl SwapchainImage {
    /// Waits until the specified swapchain index is available for rendering.
    /// Returns the number of frames it had to wait.
    pub fn wait_until_ready(&self) -> usize {
        // check the target frame first
        {
            let frame = self.frames[self.index as usize].inner.lock();
            assert!(!frame.available);
            if frame.drawable.is_some() {
                return 0;
            }
        }
        // wait for new frames to come until we meet the chosen one
        let mut count = 1;
        while self.surface.next_frame(&self.frames).unwrap().0 != self.index as usize {
            count += 1;
        }
        debug!("Swapchain image is ready after {} frames", count);
        count
    }
}

impl hal::Surface<Backend> for Surface {
    fn kind(&self) -> image::Kind {
        let ex = self.inner.dimensions();
        image::Kind::D2(ex.width, ex.height, 1, 1)
    }

    fn compatibility(
        &self, device: &PhysicalDevice,
    ) -> (hal::SurfaceCapabilities, Option<Vec<format::Format>>, Vec<hal::PresentMode>) {
        let current_extent = if self.main_thread_id == thread::current().id() {
            Some(self.inner.dimensions())
        } else {
            warn!("Unable to get the current view dimensions on a non-main thread");
            None
        };

        let caps = hal::SurfaceCapabilities {
            //Note: this is hardcoded in `CAMetalLayer` documentation
            image_count: 2 .. 4,
            current_extent,
            extents: Extent2D { width: 4, height: 4} .. Extent2D { width: 4096, height: 4096 },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT | image::Usage::SAMPLED |
                image::Usage::TRANSFER_SRC | image::Usage::TRANSFER_DST,
        };

        let formats = vec![
            format::Format::Bgra8Unorm,
            format::Format::Bgra8Srgb,
            format::Format::Rgba16Float,
        ];

        let device_caps = &device.private_caps;
        let can_set_display_sync = device_caps.os_is_mac && device_caps.has_version_at_least(10, 13);

        let present_modes = if can_set_display_sync {
            vec![hal::PresentMode::Fifo, hal::PresentMode::Immediate]
        } else {
            vec![hal::PresentMode::Fifo]
        };

        (caps, Some(formats), present_modes)
    }

    fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
        // we only expose one family atm, so it's compatible
        true
    }
}

impl SurfaceInner {
    fn dimensions(&self) -> Extent2D {
        unsafe {
            // NSView/UIView bounds are measured in DIPs
            let bounds: CGRect = msg_send![self.view, bounds];
            //let bounds_pixel: NSRect = msg_send![self.nsview, convertRectToBacking:bounds];
            Extent2D {
                width: bounds.size.width as _,
                height: bounds.size.height as _,
            }
        }
    }
}

impl Device {
    pub(crate) fn build_swapchain(
        &self,
        surface: &mut Surface,
        config: SwapchainConfig,
    ) -> (Swapchain, Backbuffer<Backend>) {
        info!("build_swapchain {:?}", config);

        let caps = &self.private_caps;
        let mtl_format = caps
            .map_format(config.format)
            .expect("unsupported backbuffer format");

        let render_layer_borrow = surface.inner.render_layer.lock();
        let render_layer = *render_layer_borrow;
        let format_desc = config.format.surface_desc();
        let framebuffer_only = config.image_usage == image::Usage::COLOR_ATTACHMENT;
        let display_sync = config.present_mode != hal::PresentMode::Immediate;
        let is_mac = caps.os_is_mac;
        let can_set_next_drawable_timeout = if is_mac {
            caps.has_version_at_least(10, 13)
        } else {
            caps.has_version_at_least(11, 0)
        };
        let can_set_display_sync = is_mac && caps.has_version_at_least(10, 13);
        let device = self.shared.device.lock();
        let device_raw: &metal::DeviceRef = &*device;

        unsafe {
            msg_send![render_layer, setDevice: device_raw];
            msg_send![render_layer, setPixelFormat: mtl_format];
            msg_send![render_layer, setFramebufferOnly: framebuffer_only];
            msg_send![render_layer, setMaximumDrawableCount: config.image_count as u64];
            msg_send![render_layer, setDrawableSize: CGSize::new(config.extent.width as f64, config.extent.height as f64)];
            if can_set_next_drawable_timeout {
                msg_send![render_layer, setAllowsNextDrawableTimeout:false];
            }
            if can_set_display_sync {
                msg_send![render_layer, setDisplaySyncEnabled: display_sync];
            }
        };

        let frames = (0 .. config.image_count)
            .map(|index| autoreleasepool(|| { // for the drawable & texture
                let (drawable, texture) = unsafe {
                    let drawable: &metal::DrawableRef = msg_send![render_layer, nextDrawable];
                    assert!(!drawable.as_ptr().is_null());
                    let texture: &metal::TextureRef = msg_send![drawable, texture];
                    (drawable, texture)
                };
                trace!("\tframe[{}] = {:?}", index, texture);

                let drawable = if index == 0 && surface.has_swapchain {
                    // when resizing, this trick frees up the currently shown frame
                    // HACK: the has_swapchain is unfortunate, and might not be
                    //       correct in all cases.
                    drawable.present();
                    None
                } else {
                    Some(drawable.to_owned())
                };
                Frame {
                    inner: Mutex::new(FrameInner {
                        drawable,
                        available: true,
                        last_frame: 0,
                    }),
                    texture: texture.to_owned(),
                }
            }))
            .collect::<Vec<_>>();

        let images = frames
            .iter()
            .map(|frame| native::Image {
                like: native::ImageLike::Texture(frame.texture.clone()),
                kind: image::Kind::D2(config.extent.width, config.extent.height, 1, 1),
                format_desc,
                shader_channel: Channel::Float,
                mtl_format,
                mtl_type: metal::MTLTextureType::D2,
            })
            .collect();

        surface.has_swapchain = true;

        let swapchain = Swapchain {
            frames: Arc::new(frames),
            surface: surface.inner.clone(),
            extent: config.extent,
            last_frame: 0,
            image_ready_callbacks: Vec::new(),
            acquire_mode: AcquireMode::Wait,
        };

        (swapchain, Backbuffer::Images(images))
    }
}

impl hal::Swapchain<Backend> for Swapchain {
    fn acquire_image(
        &mut self, _timeout_ns: u64, sync: hal::FrameSync<Backend>
    ) -> Result<hal::SwapImageIndex, hal::AcquireError> {
        self.last_frame += 1;

        //TODO: figure out a proper story of HiDPI
        if false && self.surface.dimensions() != self.extent {
            unimplemented!()
        }

        let mut oldest_index = 0;
        let mut oldest_frame = self.last_frame;

        for (index, frame_arc) in self.frames.iter().enumerate() {
            let mut frame = frame_arc.inner.lock();
            if !frame.available {
                continue
            }
            if frame.drawable.is_some() {
                frame.available = false;
                frame.last_frame = self.last_frame;
                self.signal_sync(sync);
                return Ok(index as _);
            }
            if frame.last_frame < oldest_frame {
                oldest_frame = frame.last_frame;
                oldest_index = index;
            }
        }

        let (index, mut frame) = match self.acquire_mode {
            AcquireMode::Wait => {
                self.surface.next_frame(&self.frames)
                    .map_err(|_| hal::AcquireError::OutOfDate)?
            }
            AcquireMode::Oldest => {
                self.image_ready_callbacks.retain(|ir| ir.lock().is_some());
                match sync {
                    hal::FrameSync::Semaphore(semaphore) => {
                        self.image_ready_callbacks.push(Arc::clone(&semaphore.image_ready));
                        let mut sw_image = semaphore.image_ready.lock();
                        assert!(sw_image.is_none());
                        *sw_image = Some(SwapchainImage {
                            frames: self.frames.clone(),
                            surface: self.surface.clone(),
                            index: oldest_index as _,
                        });
                    }
                    hal::FrameSync::Fence(_fence) => {
                        //TODO: need presentation handlers always created and setting a bool
                        unimplemented!()
                    }
                }

                let frame = self.frames[oldest_index].inner.lock();
                (oldest_index, frame)
            }
        };

        assert!(frame.available);
        frame.last_frame = self.last_frame;
        frame.available = false;

        Ok(index as _)
    }
}
<commit_msg>[mtl] switch to Oldest acquire mode by default<commit_after>use {Backend, QueueFamily};
use device::{Device, PhysicalDevice};
use internal::Channel;
use native;

use std::sync::Arc;
use std::thread;

use hal::{self, format, image};
use hal::{Backbuffer, SwapchainConfig};
use hal::window::Extent2D;

use core_graphics::geometry::{CGRect, CGSize};
use foreign_types::{ForeignType, ForeignTypeRef};
use parking_lot::{Mutex, MutexGuard};
use metal;
use objc::rc::autoreleasepool;
use objc::runtime::Object;

pub type CAMetalLayer = *mut Object;

pub struct Surface {
    inner: Arc<SurfaceInner>,
    main_thread_id: thread::ThreadId,
    has_swapchain: bool,
}

#[derive(Debug)]
pub(crate) struct SurfaceInner {
    pub(crate) view: *mut Object,
    pub(crate) render_layer: Mutex<CAMetalLayer>,
}

unsafe impl Send for SurfaceInner {}
unsafe impl Sync for SurfaceInner {}

impl Drop for SurfaceInner {
    fn drop(&mut self) {
        unsafe { msg_send![self.view, release]; }
    }
}

impl SurfaceInner {
    pub(crate) fn into_surface(self) -> Surface {
        Surface {
            inner: Arc::new(self),
            main_thread_id: thread::current().id(),
            has_swapchain: false,
        }
    }

    fn next_frame<'a>(&self, frames: &'a [Frame]) -> Result<(usize, MutexGuard<'a, FrameInner>), ()> {
        let layer_ref = self.render_layer.lock();
        autoreleasepool(|| { // for the drawable
            let (drawable, texture_temp): (&metal::DrawableRef, &metal::TextureRef) = unsafe {
                let drawable = msg_send![*layer_ref, nextDrawable];
                (drawable, msg_send![drawable, texture])
            };

            trace!("looking for {:?}", texture_temp);
            match frames.iter().position(|f| f.texture.as_ptr() == texture_temp.as_ptr()) {
                Some(index) => {
                    let mut frame = frames[index].inner.lock();
                    assert!(frame.drawable.is_none());
                    frame.drawable = Some(drawable.to_owned());

                    debug!("next is frame[{}]", index);
                    Ok((index, frame))
                }
                None => Err(()),
            }
        })
    }
}

#[derive(Debug)]
struct FrameInner {
    drawable: Option<metal::Drawable>,
    /// If there is a `drawable`, availability indicates if it's free for grabs.
    /// If there is `None`, `available == false` means that the frame has already
    /// been acquired and the `drawable` will appear at some point.
    available: bool,
    last_frame: usize,
}

#[derive(Debug)]
struct Frame {
    inner: Mutex<FrameInner>,
    texture: metal::Texture,
}

unsafe impl Send for Frame {}
unsafe impl Sync for Frame {}

impl Drop for Frame {
    fn drop(&mut self) {
        info!("dropping Frame");
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AcquireMode {
    Wait,
    Oldest,
}

pub struct Swapchain {
    frames: Arc<Vec<Frame>>,
    surface: Arc<SurfaceInner>,
    extent: Extent2D,
    last_frame: usize,
    image_ready_callbacks: Vec<Arc<Mutex<Option<SwapchainImage>>>>,
    pub acquire_mode: AcquireMode,
}

impl Drop for Swapchain {
    fn drop(&mut self) {
        info!("dropping Swapchain");
        for ir in self.image_ready_callbacks.drain(..) {
            if ir.lock().take().is_some() {
                debug!("\twith a callback");
            }
        }
    }
}

impl Swapchain {
    /// Returns the drawable for the specified swapchain image index,
    /// marks the index as free for future use.
    pub(crate) fn take_drawable(&self, index: hal::SwapImageIndex) -> metal::Drawable {
        let mut frame = self
            .frames[index as usize]
            .inner
            .lock();
        assert!(!frame.available);
        frame.available = true;
        frame.drawable
            .take()
            .expect("Drawable has not been acquired!")
    }

    fn signal_sync(&self, sync: hal::FrameSync<Backend>) {
        match sync {
            hal::FrameSync::Semaphore(semaphore) => {
                if let Some(ref system) = semaphore.system {
                    system.signal();
                }
            }
            hal::FrameSync::Fence(fence) => {
                *fence.0.borrow_mut() = native::FenceInner::Idle { signaled: true };
            }
        }
    }
}

#[derive(Debug)]
pub struct SwapchainImage {
    frames: Arc<Vec<Frame>>,
    surface: Arc<SurfaceInner>,
    index: hal::SwapImageIndex,
}

impl SwapchainImage {
    /// Waits until the specified swapchain index is available for rendering.
    /// Returns the number of frames it had to wait.
    pub fn wait_until_ready(&self) -> usize {
        // check the target frame first
        {
            let frame = self.frames[self.index as usize].inner.lock();
            assert!(!frame.available);
            if frame.drawable.is_some() {
                return 0;
            }
        }
        // wait for new frames to come until we meet the chosen one
        let mut count = 1;
        while self.surface.next_frame(&self.frames).unwrap().0 != self.index as usize {
            count += 1;
        }
        debug!("Swapchain image is ready after {} frames", count);
        count
    }
}

impl hal::Surface<Backend> for Surface {
    fn kind(&self) -> image::Kind {
        let ex = self.inner.dimensions();
        image::Kind::D2(ex.width, ex.height, 1, 1)
    }

    fn compatibility(
        &self, device: &PhysicalDevice,
    ) -> (hal::SurfaceCapabilities, Option<Vec<format::Format>>, Vec<hal::PresentMode>) {
        let current_extent = if self.main_thread_id == thread::current().id() {
            Some(self.inner.dimensions())
        } else {
            warn!("Unable to get the current view dimensions on a non-main thread");
            None
        };

        let caps = hal::SurfaceCapabilities {
            //Note: this is hardcoded in `CAMetalLayer` documentation
            image_count: 2 .. 4,
            current_extent,
            extents: Extent2D { width: 4, height: 4} .. Extent2D { width: 4096, height: 4096 },
            max_image_layers: 1,
            usage: image::Usage::COLOR_ATTACHMENT | image::Usage::SAMPLED |
                image::Usage::TRANSFER_SRC | image::Usage::TRANSFER_DST,
        };

        let formats = vec![
            format::Format::Bgra8Unorm,
            format::Format::Bgra8Srgb,
            format::Format::Rgba16Float,
        ];

        let device_caps = &device.private_caps;
        let can_set_display_sync = device_caps.os_is_mac && device_caps.has_version_at_least(10, 13);

        let present_modes = if can_set_display_sync {
            vec![hal::PresentMode::Fifo, hal::PresentMode::Immediate]
        } else {
            vec![hal::PresentMode::Fifo]
        };

        (caps, Some(formats), present_modes)
    }

    fn supports_queue_family(&self, _queue_family: &QueueFamily) -> bool {
        // we only expose one family atm, so it's compatible
        true
    }
}

impl SurfaceInner {
    fn dimensions(&self) -> Extent2D {
        unsafe {
            // NSView/UIView bounds are measured in DIPs
            let bounds: CGRect = msg_send![self.view, bounds];
            //let bounds_pixel: NSRect = msg_send![self.nsview, convertRectToBacking:bounds];
            Extent2D {
                width: bounds.size.width as _,
                height: bounds.size.height as _,
            }
        }
    }
}

impl Device {
    pub(crate) fn build_swapchain(
        &self,
        surface: &mut Surface,
        config: SwapchainConfig,
    ) -> (Swapchain, Backbuffer<Backend>) {
        info!("build_swapchain {:?}", config);

        let caps = &self.private_caps;
        let mtl_format = caps
            .map_format(config.format)
            .expect("unsupported backbuffer format");

        let render_layer_borrow = surface.inner.render_layer.lock();
        let render_layer = *render_layer_borrow;
        let format_desc = config.format.surface_desc();
        let framebuffer_only = config.image_usage == image::Usage::COLOR_ATTACHMENT;
        let display_sync = config.present_mode != hal::PresentMode::Immediate;
        let is_mac = caps.os_is_mac;
        let can_set_next_drawable_timeout = if is_mac {
            caps.has_version_at_least(10, 13)
        } else {
            caps.has_version_at_least(11, 0)
        };
        let can_set_display_sync = is_mac && caps.has_version_at_least(10, 13);
        let device = self.shared.device.lock();
        let device_raw: &metal::DeviceRef = &*device;

        unsafe {
            msg_send![render_layer, setDevice: device_raw];
            msg_send![render_layer, setPixelFormat: mtl_format];
            msg_send![render_layer, setFramebufferOnly: framebuffer_only];
            msg_send![render_layer, setMaximumDrawableCount: config.image_count as u64];
            msg_send![render_layer, setDrawableSize: CGSize::new(config.extent.width as f64, config.extent.height as f64)];
            if can_set_next_drawable_timeout {
                msg_send![render_layer, setAllowsNextDrawableTimeout:false];
            }
            if can_set_display_sync {
                msg_send![render_layer, setDisplaySyncEnabled: display_sync];
            }
        };

        let frames = (0 .. config.image_count)
            .map(|index| autoreleasepool(|| { // for the drawable & texture
                let (drawable, texture) = unsafe {
                    let drawable: &metal::DrawableRef = msg_send![render_layer, nextDrawable];
                    assert!(!drawable.as_ptr().is_null());
                    let texture: &metal::TextureRef = msg_send![drawable, texture];
                    (drawable, texture)
                };
                trace!("\tframe[{}] = {:?}", index, texture);

                let drawable = if index == 0 && surface.has_swapchain {
                    // when resizing, this trick frees up the currently shown frame
                    // HACK: the has_swapchain is unfortunate, and might not be
                    //       correct in all cases.
                    drawable.present();
                    None
                } else {
                    Some(drawable.to_owned())
                };
                Frame {
                    inner: Mutex::new(FrameInner {
                        drawable,
                        available: true,
                        last_frame: 0,
                    }),
                    texture: texture.to_owned(),
                }
            }))
            .collect::<Vec<_>>();

        let images = frames
            .iter()
            .map(|frame| native::Image {
                like: native::ImageLike::Texture(frame.texture.clone()),
                kind: image::Kind::D2(config.extent.width, config.extent.height, 1, 1),
                format_desc,
                shader_channel: Channel::Float,
                mtl_format,
                mtl_type: metal::MTLTextureType::D2,
            })
            .collect();

        surface.has_swapchain = true;

        let swapchain = Swapchain {
            frames: Arc::new(frames),
            surface: surface.inner.clone(),
            extent: config.extent,
            last_frame: 0,
            image_ready_callbacks: Vec::new(),
            acquire_mode: AcquireMode::Oldest,
        };

        (swapchain, Backbuffer::Images(images))
    }
}

impl hal::Swapchain<Backend> for Swapchain {
    fn acquire_image(
        &mut self, _timeout_ns: u64, sync: hal::FrameSync<Backend>
    ) -> Result<hal::SwapImageIndex, hal::AcquireError> {
        self.last_frame += 1;

        //TODO: figure out a proper story of HiDPI
        if false && self.surface.dimensions() != self.extent {
            unimplemented!()
        }

        let mut oldest_index = 0;
        let mut oldest_frame = self.last_frame;

        for (index, frame_arc) in self.frames.iter().enumerate() {
            let mut frame = frame_arc.inner.lock();
            if !frame.available {
                continue
            }
            if frame.drawable.is_some() {
                frame.available = false;
                frame.last_frame = self.last_frame;
                self.signal_sync(sync);
                return Ok(index as _);
            }
            if frame.last_frame < oldest_frame {
                oldest_frame = frame.last_frame;
                oldest_index = index;
            }
        }

        let (index, mut frame) = match self.acquire_mode {
            AcquireMode::Wait => {
                self.surface.next_frame(&self.frames)
                    .map_err(|_| hal::AcquireError::OutOfDate)?
            }
            AcquireMode::Oldest => {
                self.image_ready_callbacks.retain(|ir| ir.lock().is_some());
                match sync {
                    hal::FrameSync::Semaphore(semaphore) => {
                        self.image_ready_callbacks.push(Arc::clone(&semaphore.image_ready));
                        let mut sw_image = semaphore.image_ready.lock();
                        assert!(sw_image.is_none());
                        *sw_image = Some(SwapchainImage {
                            frames: self.frames.clone(),
                            surface: self.surface.clone(),
                            index: oldest_index as _,
                        });
                    }
                    hal::FrameSync::Fence(_fence) => {
                        //TODO: need presentation handlers always created and setting a bool
                        unimplemented!()
                    }
                }

                let frame = self.frames[oldest_index].inner.lock();
                (oldest_index, frame)
            }
        };

        assert!(frame.available);
        frame.last_frame = self.last_frame;
        frame.available = false;

        Ok(index as _)
    }
}
<|endoftext|>


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

//! Interface to SYSTICK timer.

#[path="../../lib/ioreg.rs"] mod ioreg;

/// A constant that requests to use hardware calibration value.
pub static CALIBRATED: u32 = 0xffffffff;

/// Initializes systick timer.
///
/// Arguments:
///
///  * calibration: Timer reload value, or `CALIBRATED` to use the device 10ms
///                 calibrated value.
///  * enable_irq: true, if IRQ should be initially enabled.
pub fn setup(calibration: u32, enable_irq: bool) {
  reg::SYSTICK.set_CONTROL(0b100);  // disabled, no interrupt
  let reload_val: u32 = match calibration {
    CALIBRATED => reg::SYSTICK.CALIBRATION() & 0xffffff,
    val => val,
  };
  reg::SYSTICK.set_RELOAD(reload_val);
  reg::SYSTICK.set_CURRENT(0);
  if enable_irq {
    reg::SYSTICK.set_CONTROL(0b110);
  }
}

/// Enables the timer.
pub fn enable() {
  reg::SYSTICK.set_CONTROL(reg::SYSTICK.CONTROL() | 1);
}

/// Enables interrupts generation for timer.
pub fn enable_irq() {
  reg::SYSTICK.set_CONTROL(reg::SYSTICK.CONTROL() | 0b010);
}

/// Disables interrupts generation for timer, which is still ticking.
pub fn disable_irq() {
  reg::SYSTICK.set_CONTROL(reg::SYSTICK.CONTROL() & !0b010);
}

mod reg {
  use lib::volatile_cell::VolatileCell;

  ioreg!(SYSTICKReg: u32, CONTROL, RELOAD, CURRENT, CALIBRATION)
  reg_rw!(SYSTICKReg, u32, CONTROL,     set_CONTROL, CONTROL)
  reg_rw!(SYSTICKReg, u32, RELOAD,      set_RELOAD,  RELOAD)
  reg_rw!(SYSTICKReg, u32, CURRENT,     set_CURRENT, CURRENT)
  reg_r!( SYSTICKReg, u32, CALIBRATION,              CALIBRATION)

  extern {
    #[link_name="armmem_SYSTICK"] pub static SYSTICK: SYSTICKReg;
  }
}
<commit_msg>systick: Note that not all implementations support CALIBRATED<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Interface to SYSTICK timer.

#[path="../../lib/ioreg.rs"] mod ioreg;

/// A constant that requests to use hardware calibration value.
/// Note that not all core implementations support this.
pub static CALIBRATED: u32 = 0xffffffff;

/// Initializes systick timer.
///
/// Arguments:
///
///  * calibration: Timer reload value, or `CALIBRATED` to use the device 10ms
///                 calibrated value.
///  * enable_irq: true, if IRQ should be initially enabled.
pub fn setup(calibration: u32, enable_irq: bool) {
  reg::SYSTICK.set_CONTROL(0b100);  // disabled, no interrupt
  let reload_val: u32 = match calibration {
    CALIBRATED => reg::SYSTICK.CALIBRATION() & 0xffffff,
    val => val,
  };
  reg::SYSTICK.set_RELOAD(reload_val);
  reg::SYSTICK.set_CURRENT(0);
  if enable_irq {
    reg::SYSTICK.set_CONTROL(0b110);
  }
}

/// Enables the timer.
pub fn enable() {
  reg::SYSTICK.set_CONTROL(reg::SYSTICK.CONTROL() | 1);
}

/// Enables interrupts generation for timer.
pub fn enable_irq() {
  reg::SYSTICK.set_CONTROL(reg::SYSTICK.CONTROL() | 0b010);
}

/// Disables interrupts generation for timer, which is still ticking.
pub fn disable_irq() {
  reg::SYSTICK.set_CONTROL(reg::SYSTICK.CONTROL() & !0b010);
}

mod reg {
  use lib::volatile_cell::VolatileCell;

  ioreg!(SYSTICKReg: u32, CONTROL, RELOAD, CURRENT, CALIBRATION)
  reg_rw!(SYSTICKReg, u32, CONTROL,     set_CONTROL, CONTROL)
  reg_rw!(SYSTICKReg, u32, RELOAD,      set_RELOAD,  RELOAD)
  reg_rw!(SYSTICKReg, u32, CURRENT,     set_CURRENT, CURRENT)
  reg_r!( SYSTICKReg, u32, CALIBRATION,              CALIBRATION)

  extern {
    #[link_name="armmem_SYSTICK"] pub static SYSTICK: SYSTICKReg;
  }
}
<|endoftext|>