From 070cd265e47a601b572a26f0cc2dd30473f700fc Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 13 Mar 2022 01:39:59 +0900 Subject: [PATCH] Do not panic on very large timeout --- crossbeam-channel/src/channel.rs | 5 +++-- crossbeam-channel/src/flavors/at.rs | 2 +- crossbeam-channel/src/flavors/tick.rs | 3 ++- crossbeam-channel/src/select.rs | 4 ++-- crossbeam-channel/src/utils.rs | 8 ++++++++ crossbeam-utils/src/sync/parker.rs | 7 ++++++- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/crossbeam-channel/src/channel.rs b/crossbeam-channel/src/channel.rs index 8988235db..e16f226b1 100644 --- a/crossbeam-channel/src/channel.rs +++ b/crossbeam-channel/src/channel.rs @@ -14,6 +14,7 @@ use crate::err::{ }; use crate::flavors; use crate::select::{Operation, SelectHandle, Token}; +use crate::utils; /// Creates a channel of unbounded capacity. /// @@ -471,7 +472,7 @@ impl Sender { /// ); /// ``` pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError> { - self.send_deadline(msg, Instant::now() + timeout) + self.send_deadline(msg, utils::timeout_to_deadline(timeout)) } /// Waits for a message to be sent into the channel, but only until a given deadline. @@ -861,7 +862,7 @@ impl Receiver { /// ); /// ``` pub fn recv_timeout(&self, timeout: Duration) -> Result { - self.recv_deadline(Instant::now() + timeout) + self.recv_deadline(utils::timeout_to_deadline(timeout)) } /// Waits for a message to be received from the channel, but only before a given deadline. diff --git a/crossbeam-channel/src/flavors/at.rs b/crossbeam-channel/src/flavors/at.rs index 23a7ae734..ee49244c4 100644 --- a/crossbeam-channel/src/flavors/at.rs +++ b/crossbeam-channel/src/flavors/at.rs @@ -35,7 +35,7 @@ impl Channel { /// Creates a channel that delivers a message after a certain duration of time. #[inline] pub(crate) fn new_timeout(dur: Duration) -> Self { - Self::new_deadline(Instant::now() + dur) + Self::new_deadline(utils::timeout_to_deadline(dur)) } /// Attempts to receive a message without blocking. diff --git a/crossbeam-channel/src/flavors/tick.rs b/crossbeam-channel/src/flavors/tick.rs index bd12929a9..147098c68 100644 --- a/crossbeam-channel/src/flavors/tick.rs +++ b/crossbeam-channel/src/flavors/tick.rs @@ -10,6 +10,7 @@ use crossbeam_utils::atomic::AtomicCell; use crate::context::Context; use crate::err::{RecvTimeoutError, TryRecvError}; use crate::select::{Operation, SelectHandle, Token}; +use crate::utils; /// Result of a receive operation. pub(crate) type TickToken = Option; @@ -28,7 +29,7 @@ impl Channel { #[inline] pub(crate) fn new(dur: Duration) -> Self { Channel { - delivery_time: AtomicCell::new(Instant::now() + dur), + delivery_time: AtomicCell::new(utils::timeout_to_deadline(dur)), duration: dur, } } diff --git a/crossbeam-channel/src/select.rs b/crossbeam-channel/src/select.rs index ea70a9eb1..b2f3e01b3 100644 --- a/crossbeam-channel/src/select.rs +++ b/crossbeam-channel/src/select.rs @@ -487,7 +487,7 @@ pub fn select_timeout<'a>( handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], timeout: Duration, ) -> Result, SelectTimeoutError> { - select_deadline(handles, Instant::now() + timeout) + select_deadline(handles, utils::timeout_to_deadline(timeout)) } /// Blocks until a given deadline, or until one of the operations becomes ready and selects it. @@ -1043,7 +1043,7 @@ impl<'a> Select<'a> { /// } /// ``` pub fn ready_timeout(&mut self, timeout: Duration) -> Result { - self.ready_deadline(Instant::now() + timeout) + self.ready_deadline(utils::timeout_to_deadline(timeout)) } /// Blocks until a given deadline, or until one of the operations becomes ready. diff --git a/crossbeam-channel/src/utils.rs b/crossbeam-channel/src/utils.rs index 557b6a0d7..cebe59da1 100644 --- a/crossbeam-channel/src/utils.rs +++ b/crossbeam-channel/src/utils.rs @@ -61,6 +61,14 @@ pub(crate) fn sleep_until(deadline: Option) { } } +// https://github.com/crossbeam-rs/crossbeam/issues/795 +pub(crate) fn timeout_to_deadline(timeout: Duration) -> Instant { + match Instant::now().checked_add(timeout) { + Some(deadline) => deadline, + None => Instant::now() + Duration::from_secs(86400 * 365 * 30), + } +} + /// A simple spinlock. pub(crate) struct Spinlock { flag: AtomicBool, diff --git a/crossbeam-utils/src/sync/parker.rs b/crossbeam-utils/src/sync/parker.rs index 531f5a5fc..021e7c87c 100644 --- a/crossbeam-utils/src/sync/parker.rs +++ b/crossbeam-utils/src/sync/parker.rs @@ -121,7 +121,12 @@ impl Parker { /// p.park_timeout(Duration::from_millis(500)); /// ``` pub fn park_timeout(&self, timeout: Duration) { - self.park_deadline(Instant::now() + timeout) + // https://github.com/crossbeam-rs/crossbeam/issues/795 + let deadline = match Instant::now().checked_add(timeout) { + Some(deadline) => deadline, + None => Instant::now() + Duration::from_secs(86400 * 365 * 30), + }; + self.park_deadline(deadline) } /// Blocks the current thread until the token is made available, or until a certain deadline.