summaryrefslogtreecommitdiffstats
path: root/tokio/src/time
diff options
context:
space:
mode:
authorFelix Giese <felix.giese@icloud.com>2020-07-26 09:40:29 +0200
committerGitHub <noreply@github.com>2020-07-26 09:40:29 +0200
commit7f29acd964dfca9c9e90a87af607a7897eb8ea67 (patch)
tree403af7b7011f78fa6b960e1d50cd18b9106bb820 /tokio/src/time
parent2d97d5ad15a19665615ed38219d3b7798df7e250 (diff)
time: fix resetting expired timers causing panics (#2587)
* Add Unit Test demonstrating the issue This test demonstrates a panic that occurs when the user inserts an item with an instant in the past, and then tries to reset the timeout using the returned key * Guard reset_at against removals of expired items Trying to remove an already expired Timer Wheel entry (called by DelayQueue.reset()) causes panics in some cases as described in (#2573) This prevents this panic by removing the item from the expired queue and not the wheel in these cases Fixes: #2473
Diffstat (limited to 'tokio/src/time')
-rw-r--r--tokio/src/time/delay_queue.rs28
1 files changed, 18 insertions, 10 deletions
diff --git a/tokio/src/time/delay_queue.rs b/tokio/src/time/delay_queue.rs
index 55ec7cd6..a947cc6f 100644
--- a/tokio/src/time/delay_queue.rs
+++ b/tokio/src/time/delay_queue.rs
@@ -427,6 +427,22 @@ impl<T> DelayQueue<T> {
}
}
+ /// Removes the key fom the expired queue or the timer wheel
+ /// depending on its expiration status
+ ///
+ /// # Panics
+ /// Panics if the key is not contained in the expired queue or the wheel
+ fn remove_key(&mut self, key: &Key) {
+ use crate::time::wheel::Stack;
+
+ // Special case the `expired` queue
+ if self.slab[key.index].expired {
+ self.expired.remove(&key.index, &mut self.slab);
+ } else {
+ self.wheel.remove(&key.index, &mut self.slab);
+ }
+ }
+
/// Removes the item associated with `key` from the queue.
///
/// There must be an item associated with `key`. The function returns the
@@ -456,15 +472,7 @@ impl<T> DelayQueue<T> {
/// # }
/// ```
pub fn remove(&mut self, key: &Key) -> Expired<T> {
- use crate::time::wheel::Stack;
-
- // Special case the `expired` queue
- if self.slab[key.index].expired {
- self.expired.remove(&key.index, &mut self.slab);
- } else {
- self.wheel.remove(&key.index, &mut self.slab);
- }
-
+ self.remove_key(key);
let data = self.slab.remove(key.index);
Expired {
@@ -508,7 +516,7 @@ impl<T> DelayQueue<T> {
/// # }
/// ```
pub fn reset_at(&mut self, key: &Key, when: Instant) {
- self.wheel.remove(&key.index, &mut self.slab);
+ self.remove_key(key);
// Normalize the deadline. Values cannot be set to expire in the past.
let when = self.normalize_deadline(when);