├── .gitignore ├── src ├── native.rs ├── lib.rs ├── native │ ├── heap_timer.rs │ ├── global.rs │ ├── arc_list.rs │ ├── delay.rs │ ├── atomic_waker.rs │ ├── heap.rs │ └── timer.rs └── wasm.rs ├── tests ├── timeout.rs └── smoke.rs ├── Cargo.toml ├── LICENSE-MIT ├── .github └── workflows │ └── ci.yml ├── README.md └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | .idea 5 | -------------------------------------------------------------------------------- /src/native.rs: -------------------------------------------------------------------------------- 1 | mod arc_list; 2 | mod atomic_waker; 3 | mod delay; 4 | mod global; 5 | mod heap; 6 | mod heap_timer; 7 | mod timer; 8 | 9 | use self::arc_list::{ArcList, Node}; 10 | use self::atomic_waker::AtomicWaker; 11 | use self::heap::{Heap, Slot}; 12 | use self::heap_timer::HeapTimer; 13 | use self::timer::{ScheduledTimer, Timer, TimerHandle}; 14 | 15 | pub use self::delay::Delay; 16 | -------------------------------------------------------------------------------- /tests/timeout.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::time::{Duration, Instant}; 3 | 4 | use futures_timer::Delay; 5 | 6 | #[async_std::test] 7 | async fn smoke() -> Result<(), Box> { 8 | let dur = Duration::from_millis(10); 9 | let start = Instant::now(); 10 | Delay::new(dur).await; 11 | assert!(start.elapsed() >= (dur / 2)); 12 | Ok(()) 13 | } 14 | 15 | #[async_std::test] 16 | async fn two() -> Result<(), Box> { 17 | let dur = Duration::from_millis(10); 18 | Delay::new(dur).await; 19 | Delay::new(dur).await; 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "futures-timer" 3 | version = "3.0.3" 4 | authors = ["Alex Crichton "] 5 | edition = "2018" 6 | license = "MIT/Apache-2.0" 7 | readme = "README.md" 8 | repository = "https://github.com/async-rs/futures-timer" 9 | homepage = "https://github.com/async-rs/futures-timer" 10 | documentation = "https://docs.rs/futures-timer" 11 | description = """ 12 | Timeouts for futures. 13 | """ 14 | 15 | [dependencies] 16 | gloo-timers = { version = "0.2.0", features = ["futures"], optional = true } 17 | send_wrapper = { version = "0.4.0", optional = true } 18 | 19 | [dev-dependencies] 20 | async-std = { version = "1.0.1", features = ["attributes"] } 21 | futures = "0.3.1" 22 | 23 | [features] 24 | wasm-bindgen = [ 25 | "gloo-timers", 26 | "send_wrapper" 27 | ] 28 | -------------------------------------------------------------------------------- /tests/smoke.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::pin::Pin; 3 | use std::time::{Duration, Instant}; 4 | 5 | use futures_timer::Delay; 6 | 7 | #[async_std::test] 8 | async fn works() { 9 | let i = Instant::now(); 10 | let dur = Duration::from_millis(100); 11 | let _d = Delay::new(dur).await; 12 | assert!(i.elapsed() > dur); 13 | } 14 | 15 | #[async_std::test] 16 | async fn reset() -> Result<(), Box> { 17 | let i = Instant::now(); 18 | let dur = Duration::from_millis(100); 19 | let mut d = Delay::new(dur); 20 | 21 | // Allow us to re-use a future 22 | Pin::new(&mut d).await; 23 | 24 | assert!(i.elapsed() > dur); 25 | 26 | let i = Instant::now(); 27 | d.reset(dur); 28 | d.await; 29 | assert!(i.elapsed() > dur); 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A general purpose crate for working with timeouts and delays with futures. 2 | //! 3 | //! # Examples 4 | //! 5 | //! ```no_run 6 | //! # #[async_std::main] 7 | //! # async fn main() { 8 | //! use std::time::Duration; 9 | //! use futures_timer::Delay; 10 | //! 11 | //! let now = Delay::new(Duration::from_secs(3)).await; 12 | //! println!("waited for 3 secs"); 13 | //! # } 14 | //! ``` 15 | 16 | #![deny(missing_docs)] 17 | #![warn(missing_debug_implementations)] 18 | 19 | #[cfg(not(all(target_arch = "wasm32", feature = "wasm-bindgen")))] 20 | mod native; 21 | #[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] 22 | mod wasm; 23 | 24 | #[cfg(not(all(target_arch = "wasm32", feature = "wasm-bindgen")))] 25 | pub use self::native::Delay; 26 | #[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))] 27 | pub use self::wasm::Delay; 28 | -------------------------------------------------------------------------------- /src/native/heap_timer.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Ordering; 2 | use std::sync::Arc; 3 | use std::time::Instant; 4 | 5 | use super::{Node, ScheduledTimer}; 6 | 7 | /// Entries in the timer heap, sorted by the instant they're firing at and then 8 | /// also containing some payload data. 9 | pub(crate) struct HeapTimer { 10 | pub(crate) at: Instant, 11 | pub(crate) gen: usize, 12 | pub(crate) node: Arc>, 13 | } 14 | 15 | impl PartialEq for HeapTimer { 16 | fn eq(&self, other: &HeapTimer) -> bool { 17 | self.at == other.at 18 | } 19 | } 20 | 21 | impl Eq for HeapTimer {} 22 | 23 | impl PartialOrd for HeapTimer { 24 | fn partial_cmp(&self, other: &HeapTimer) -> Option { 25 | Some(self.cmp(other)) 26 | } 27 | } 28 | 29 | impl Ord for HeapTimer { 30 | fn cmp(&self, other: &HeapTimer) -> Ordering { 31 | self.at.cmp(&other.at) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/wasm.rs: -------------------------------------------------------------------------------- 1 | //! A version of `Delay` that works on wasm. 2 | 3 | use gloo_timers::future::TimeoutFuture; 4 | use send_wrapper::SendWrapper; 5 | use std::{ 6 | future::Future, 7 | pin::Pin, 8 | task::{Context, Poll}, 9 | time::Duration, 10 | }; 11 | 12 | /// A version of `Delay` that works on wasm. 13 | #[derive(Debug)] 14 | pub struct Delay(SendWrapper); 15 | 16 | impl Delay { 17 | /// Creates a new future which will fire at `dur` time into the future. 18 | #[inline] 19 | pub fn new(dur: Duration) -> Delay { 20 | Self(SendWrapper::new(TimeoutFuture::new(dur.as_millis() as u32))) 21 | } 22 | 23 | /// Resets the timeout. 24 | #[inline] 25 | pub fn reset(&mut self, dur: Duration) { 26 | *self = Delay::new(dur); 27 | } 28 | } 29 | 30 | impl Future for Delay { 31 | type Output = (); 32 | 33 | fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { 34 | Pin::new(&mut *Pin::into_inner(self).0).poll(cx) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Alex Crichton 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | # env: 5 | # RUSTFLAGS: -Dwarnings 6 | 7 | jobs: 8 | test: 9 | name: Test 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | rust: 14 | - stable 15 | steps: 16 | - uses: actions/checkout@master 17 | - name: Install Rust 18 | run: rustup update ${{ matrix.rust }} && rustup default ${{ matrix.rust }} 19 | - name: cargo test 20 | run: cargo test 21 | - name: cargo doc 22 | run: cargo doc --no-deps 23 | 24 | style: 25 | name: Style 26 | runs-on: ubuntu-latest 27 | strategy: 28 | fail-fast: false 29 | matrix: 30 | component: 31 | - rustfmt 32 | steps: 33 | - uses: actions/checkout@master 34 | - name: Install Rust 35 | shell: bash 36 | run: rustup update stable && rustup default stable 37 | - name: Install component 38 | shell: bash 39 | run: rustup component add ${{ matrix.component }} 40 | - name: cargo fmt 41 | if: matrix.component == 'rustfmt' 42 | run: cargo fmt -- --check 43 | 44 | publish_docs: 45 | name: Publish Documentation 46 | needs: [style, test] 47 | runs-on: ubuntu-latest 48 | steps: 49 | - uses: actions/checkout@master 50 | - name: Install Rust 51 | run: rustup update stable && rustup default stable 52 | - name: Build documentation 53 | run: cargo doc --no-deps --all-features 54 | - name: Publish documentation 55 | run: | 56 | cd target/doc 57 | git init 58 | git add . 59 | git -c user.name='ci' -c user.email='ci' commit -m 'Deploy futures-timer API documentation' 60 | git push -f -q https://git:${{ secrets.github_token }}@github.com/${{ github.repository }} HEAD:gh-pages 61 | if: github.event_name == 'push' && github.event.ref == 'refs/heads/master' && github.repository == 'async-rs/futures-timer' 62 | 63 | check_wasm: 64 | name: Check Wasm 65 | needs: [test] 66 | runs-on: ubuntu-latest 67 | steps: 68 | - uses: actions/checkout@master 69 | - name: Install Rust and add wasm target 70 | run: rustup update stable && rustup target add wasm32-unknown-unknown 71 | - name: cargo check 72 | run: cargo check --target wasm32-unknown-unknown --features wasm-bindgen 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

futures-timer

2 |
3 | 4 | Timeouts for futures. 5 | 6 |
7 | 8 |
9 | 10 |
11 | 12 | 13 | Crates.io version 15 | 16 | 17 | 18 | Download 20 | 21 | 22 | 23 | docs.rs docs 25 | 26 | 27 | chat 29 | 30 |
31 | 32 | 47 | 48 | ## Installation 49 | 50 | With [cargo add][cargo-add] installed run: 51 | 52 | ```sh 53 | $ cargo add futures-timer 54 | ``` 55 | 56 | [cargo-add]: https://github.com/killercup/cargo-edit 57 | 58 | ## Safety 59 | This crate makes use of carefully checked `unsafe` blocks to construct an 60 | efficient timer implementation. 61 | 62 | ## Contributing 63 | Want to join us? Check out our ["Contributing" guide][contributing] and take a 64 | look at some of these issues: 65 | 66 | - [Issues labeled "good first issue"][good-first-issue] 67 | - [Issues labeled "help wanted"][help-wanted] 68 | 69 | [contributing]: https://github.com/async-rs/futures-timer/blob/master.github/CONTRIBUTING.md 70 | [good-first-issue]: https://github.com/async-rs/futures-timer/labels/good%20first%20issue 71 | [help-wanted]: https://github.com/async-rs/futures-timer/labels/help%20wanted 72 | 73 | ## License 74 | 75 | 76 | Licensed under either of Apache License, Version 77 | 2.0 or MIT license at your option. 78 | 79 | 80 |
81 | 82 | 83 | Unless you explicitly state otherwise, any contribution intentionally submitted 84 | for inclusion in this crate by you, as defined in the Apache-2.0 license, shall 85 | be dual licensed as above, without any additional terms or conditions. 86 | 87 | -------------------------------------------------------------------------------- /src/native/global.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | use std::io; 3 | use std::mem::{self, ManuallyDrop}; 4 | use std::pin::Pin; 5 | use std::sync::atomic::{AtomicBool, Ordering}; 6 | use std::sync::Arc; 7 | use std::task::{Context, RawWaker, RawWakerVTable, Waker}; 8 | use std::thread; 9 | use std::thread::Thread; 10 | use std::time::Instant; 11 | 12 | use super::{Timer, TimerHandle}; 13 | 14 | pub struct HelperThread { 15 | thread: Option>, 16 | timer: TimerHandle, 17 | done: Arc, 18 | } 19 | 20 | impl HelperThread { 21 | pub fn new() -> io::Result { 22 | let timer = Timer::new(); 23 | let timer_handle = timer.handle(); 24 | let done = Arc::new(AtomicBool::new(false)); 25 | let done2 = done.clone(); 26 | let thread = thread::Builder::new() 27 | .name("futures-timer".to_owned()) 28 | .spawn(move || run(timer, done2))?; 29 | 30 | Ok(HelperThread { 31 | thread: Some(thread), 32 | done, 33 | timer: timer_handle, 34 | }) 35 | } 36 | 37 | pub fn handle(&self) -> TimerHandle { 38 | self.timer.clone() 39 | } 40 | 41 | pub fn forget(mut self) { 42 | self.thread.take(); 43 | } 44 | } 45 | 46 | impl Drop for HelperThread { 47 | fn drop(&mut self) { 48 | let thread = match self.thread.take() { 49 | Some(thread) => thread, 50 | None => return, 51 | }; 52 | self.done.store(true, Ordering::SeqCst); 53 | thread.thread().unpark(); 54 | drop(thread.join()); 55 | } 56 | } 57 | 58 | fn run(mut timer: Timer, done: Arc) { 59 | let waker = current_thread_waker(); 60 | let mut cx = Context::from_waker(&waker); 61 | 62 | while !done.load(Ordering::SeqCst) { 63 | let _ = Pin::new(&mut timer).poll(&mut cx); 64 | 65 | timer.advance(); 66 | match timer.next_event() { 67 | // Ok, block for the specified time 68 | Some(when) => { 69 | let now = Instant::now(); 70 | if now < when { 71 | thread::park_timeout(when - now) 72 | } else { 73 | // .. continue... 74 | } 75 | } 76 | 77 | // Just wait for one of our futures to wake up 78 | None => thread::park(), 79 | } 80 | } 81 | } 82 | 83 | static VTABLE: RawWakerVTable = RawWakerVTable::new(raw_clone, raw_wake, raw_wake_by_ref, raw_drop); 84 | 85 | fn raw_clone(ptr: *const ()) -> RawWaker { 86 | let me = ManuallyDrop::new(unsafe { Arc::from_raw(ptr as *const Thread) }); 87 | mem::forget(me.clone()); 88 | RawWaker::new(ptr, &VTABLE) 89 | } 90 | 91 | fn raw_wake(ptr: *const ()) { 92 | unsafe { Arc::from_raw(ptr as *const Thread) }.unpark() 93 | } 94 | 95 | fn raw_wake_by_ref(ptr: *const ()) { 96 | ManuallyDrop::new(unsafe { Arc::from_raw(ptr as *const Thread) }).unpark() 97 | } 98 | 99 | fn raw_drop(ptr: *const ()) { 100 | unsafe { Arc::from_raw(ptr as *const Thread) }; 101 | } 102 | 103 | fn current_thread_waker() -> Waker { 104 | let thread = Arc::new(thread::current()); 105 | unsafe { Waker::from_raw(RawWaker::new(Arc::into_raw(thread) as *const (), &VTABLE)) } 106 | } 107 | -------------------------------------------------------------------------------- /src/native/arc_list.rs: -------------------------------------------------------------------------------- 1 | //! An atomically managed intrusive linked list of `Arc` nodes 2 | 3 | use std::marker; 4 | use std::ops::Deref; 5 | use std::sync::atomic::Ordering::SeqCst; 6 | use std::sync::atomic::{AtomicBool, AtomicPtr}; 7 | use std::sync::Arc; 8 | 9 | pub struct ArcList { 10 | list: AtomicPtr>, 11 | _marker: marker::PhantomData, 12 | } 13 | 14 | impl ArcList { 15 | pub fn new() -> ArcList { 16 | ArcList { 17 | list: AtomicPtr::new(Node::EMPTY), 18 | _marker: marker::PhantomData, 19 | } 20 | } 21 | 22 | /// Pushes the `data` provided onto this list if it's not already enqueued 23 | /// in this list. 24 | /// 25 | /// If `data` is already enqueued in this list then this is a noop, 26 | /// otherwise, the `data` here is pushed on the end of the list. 27 | pub fn push(&self, data: &Arc>) -> Result<(), ()> { 28 | if data.enqueued.swap(true, SeqCst) { 29 | // note that even if our list is sealed off then the other end is 30 | // still guaranteed to see us because we were previously enqueued. 31 | return Ok(()); 32 | } 33 | let mut head = self.list.load(SeqCst); 34 | let node = Arc::into_raw(data.clone()) as *mut Node; 35 | loop { 36 | // If we've been sealed off, abort and return an error 37 | if head == Node::SEALED { 38 | unsafe { 39 | drop(Arc::from_raw(node as *mut Node)); 40 | } 41 | return Err(()); 42 | } 43 | 44 | // Otherwise attempt to push this node 45 | data.next.store(head, SeqCst); 46 | match self.list.compare_exchange(head, node, SeqCst, SeqCst) { 47 | Ok(_) => break Ok(()), 48 | Err(new_head) => head = new_head, 49 | } 50 | } 51 | } 52 | 53 | /// Atomically empties this list, returning a new owned copy which can be 54 | /// used to iterate over the entries. 55 | pub fn take(&self) -> ArcList { 56 | let mut list = self.list.load(SeqCst); 57 | loop { 58 | if list == Node::SEALED { 59 | break; 60 | } 61 | match self 62 | .list 63 | .compare_exchange(list, Node::EMPTY, SeqCst, SeqCst) 64 | { 65 | Ok(_) => break, 66 | Err(l) => list = l, 67 | } 68 | } 69 | ArcList { 70 | list: AtomicPtr::new(list), 71 | _marker: marker::PhantomData, 72 | } 73 | } 74 | 75 | /// Atomically empties this list and prevents further successful calls to 76 | /// `push`. 77 | pub fn take_and_seal(&self) -> ArcList { 78 | ArcList { 79 | list: AtomicPtr::new(self.list.swap(Node::SEALED, SeqCst)), 80 | _marker: marker::PhantomData, 81 | } 82 | } 83 | 84 | /// Removes the head of the list of nodes, returning `None` if this is an 85 | /// empty list. 86 | pub fn pop(&mut self) -> Option>> { 87 | let head = *self.list.get_mut(); 88 | if head == Node::EMPTY || head == Node::SEALED { 89 | return None; 90 | } 91 | let head = unsafe { Arc::from_raw(head as *const Node) }; 92 | *self.list.get_mut() = head.next.load(SeqCst); 93 | // At this point, the node is out of the list, so store `false` so we 94 | // can enqueue it again and see further changes. 95 | assert!(head.enqueued.swap(false, SeqCst)); 96 | Some(head) 97 | } 98 | } 99 | 100 | impl Drop for ArcList { 101 | fn drop(&mut self) { 102 | while let Some(_) = self.pop() { 103 | // ... 104 | } 105 | } 106 | } 107 | 108 | pub struct Node { 109 | next: AtomicPtr>, 110 | enqueued: AtomicBool, 111 | data: T, 112 | } 113 | 114 | impl Node { 115 | const EMPTY: *mut Node = std::ptr::null_mut(); 116 | 117 | const SEALED: *mut Node = std::ptr::null_mut::>().wrapping_add(1); 118 | 119 | pub fn new(data: T) -> Node { 120 | Node { 121 | next: AtomicPtr::new(Node::EMPTY), 122 | enqueued: AtomicBool::new(false), 123 | data, 124 | } 125 | } 126 | } 127 | 128 | impl Deref for Node { 129 | type Target = T; 130 | 131 | fn deref(&self) -> &T { 132 | &self.data 133 | } 134 | } 135 | 136 | #[cfg(test)] 137 | mod tests { 138 | use super::*; 139 | 140 | #[test] 141 | fn smoke() { 142 | let a = ArcList::new(); 143 | let n = Arc::new(Node::new(1)); 144 | assert!(a.push(&n).is_ok()); 145 | 146 | let mut l = a.take(); 147 | assert_eq!(**l.pop().unwrap(), 1); 148 | assert!(l.pop().is_none()); 149 | } 150 | 151 | #[test] 152 | fn seal() { 153 | let a = ArcList::new(); 154 | let n = Arc::new(Node::new(1)); 155 | let mut l = a.take_and_seal(); 156 | assert!(l.pop().is_none()); 157 | assert!(a.push(&n).is_err()); 158 | 159 | assert!(a.take().pop().is_none()); 160 | assert!(a.take_and_seal().pop().is_none()); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/native/delay.rs: -------------------------------------------------------------------------------- 1 | //! Support for creating futures that represent timeouts. 2 | //! 3 | //! This module contains the `Delay` type which is a future that will resolve 4 | //! at a particular point in the future. 5 | 6 | use std::fmt; 7 | use std::future::Future; 8 | use std::pin::Pin; 9 | use std::sync::atomic::AtomicUsize; 10 | use std::sync::atomic::Ordering::SeqCst; 11 | use std::sync::{Arc, Mutex}; 12 | use std::task::{Context, Poll}; 13 | use std::time::{Duration, Instant}; 14 | 15 | use super::arc_list::Node; 16 | use super::AtomicWaker; 17 | use super::{ScheduledTimer, TimerHandle}; 18 | 19 | /// A future representing the notification that an elapsed duration has 20 | /// occurred. 21 | /// 22 | /// This is created through the `Delay::new` method indicating when the future should fire. 23 | /// Note that these futures are not intended for high resolution timers, but rather they will 24 | /// likely fire some granularity after the exact instant that they're otherwise indicated to fire 25 | /// at. 26 | pub struct Delay { 27 | state: Option>>, 28 | } 29 | 30 | impl Delay { 31 | /// Creates a new future which will fire at `dur` time into the future. 32 | /// 33 | /// The returned object will be bound to the default timer for this thread. 34 | /// The default timer will be spun up in a helper thread on first use. 35 | #[inline] 36 | pub fn new(dur: Duration) -> Delay { 37 | Delay::new_handle(Instant::now() + dur, Default::default()) 38 | } 39 | 40 | /// Creates a new future which will fire at the time specified by `at`. 41 | /// 42 | /// The returned instance of `Delay` will be bound to the timer specified by 43 | /// the `handle` argument. 44 | pub(crate) fn new_handle(at: Instant, handle: TimerHandle) -> Delay { 45 | let inner = match handle.inner.upgrade() { 46 | Some(i) => i, 47 | None => return Delay { state: None }, 48 | }; 49 | let state = Arc::new(Node::new(ScheduledTimer { 50 | at: Mutex::new(Some(at)), 51 | state: AtomicUsize::new(0), 52 | waker: AtomicWaker::new(), 53 | inner: handle.inner, 54 | slot: Mutex::new(None), 55 | })); 56 | 57 | // If we fail to actually push our node then we've become an inert 58 | // timer, meaning that we'll want to immediately return an error from 59 | // `poll`. 60 | if inner.list.push(&state).is_err() { 61 | return Delay { state: None }; 62 | } 63 | 64 | inner.waker.wake(); 65 | Delay { state: Some(state) } 66 | } 67 | 68 | /// Resets this timeout to an new timeout which will fire at the time 69 | /// specified by `at`. 70 | #[inline] 71 | pub fn reset(&mut self, dur: Duration) { 72 | if self._reset(dur).is_err() { 73 | self.state = None 74 | } 75 | } 76 | 77 | fn _reset(&mut self, dur: Duration) -> Result<(), ()> { 78 | let state = match self.state { 79 | Some(ref state) => state, 80 | None => return Err(()), 81 | }; 82 | if let Some(timeouts) = state.inner.upgrade() { 83 | let mut bits = state.state.load(SeqCst); 84 | loop { 85 | // If we've been invalidated, cancel this reset 86 | if bits & 0b10 != 0 { 87 | return Err(()); 88 | } 89 | let new = bits.wrapping_add(0b100) & !0b11; 90 | match state.state.compare_exchange(bits, new, SeqCst, SeqCst) { 91 | Ok(_) => break, 92 | Err(s) => bits = s, 93 | } 94 | } 95 | *state.at.lock().unwrap() = Some(Instant::now() + dur); 96 | // If we fail to push our node then we've become an inert timer, so 97 | // we'll want to clear our `state` field accordingly 98 | timeouts.list.push(state)?; 99 | timeouts.waker.wake(); 100 | } 101 | 102 | Ok(()) 103 | } 104 | } 105 | 106 | impl Future for Delay { 107 | type Output = (); 108 | 109 | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 110 | let state = match self.state { 111 | Some(ref state) => state, 112 | None => panic!("timer has gone away"), 113 | }; 114 | 115 | if state.state.load(SeqCst) & 1 != 0 { 116 | return Poll::Ready(()); 117 | } 118 | 119 | state.waker.register(cx.waker()); 120 | 121 | // Now that we've registered, do the full check of our own internal 122 | // state. If we've fired the first bit is set, and if we've been 123 | // invalidated the second bit is set. 124 | match state.state.load(SeqCst) { 125 | n if n & 0b01 != 0 => Poll::Ready(()), 126 | n if n & 0b10 != 0 => panic!("timer has gone away"), 127 | _ => Poll::Pending, 128 | } 129 | } 130 | } 131 | 132 | impl Drop for Delay { 133 | fn drop(&mut self) { 134 | let state = match self.state { 135 | Some(ref s) => s, 136 | None => return, 137 | }; 138 | if let Some(timeouts) = state.inner.upgrade() { 139 | *state.at.lock().unwrap() = None; 140 | if timeouts.list.push(state).is_ok() { 141 | timeouts.waker.wake(); 142 | } 143 | } 144 | } 145 | } 146 | 147 | impl fmt::Debug for Delay { 148 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 149 | f.debug_struct("Delay").finish() 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/native/atomic_waker.rs: -------------------------------------------------------------------------------- 1 | use core::cell::UnsafeCell; 2 | use core::fmt; 3 | use core::sync::atomic::AtomicUsize; 4 | use core::sync::atomic::Ordering::{AcqRel, Acquire, Release}; 5 | use core::task::Waker; 6 | 7 | /// A synchronization primitive for task wakeup. 8 | /// 9 | /// Sometimes the task interested in a given event will change over time. 10 | /// An `AtomicWaker` can coordinate concurrent notifications with the consumer 11 | /// potentially "updating" the underlying task to wake up. This is useful in 12 | /// scenarios where a computation completes in another thread and wants to 13 | /// notify the consumer, but the consumer is in the process of being migrated to 14 | /// a new logical task. 15 | /// 16 | /// Consumers should call `register` before checking the result of a computation 17 | /// and producers should call `wake` after producing the computation (this 18 | /// differs from the usual `thread::park` pattern). It is also permitted for 19 | /// `wake` to be called **before** `register`. This results in a no-op. 20 | /// 21 | /// A single `AtomicWaker` may be reused for any number of calls to `register` or 22 | /// `wake`. 23 | /// 24 | /// `AtomicWaker` does not provide any memory ordering guarantees, as such the 25 | /// user should use caution and use other synchronization primitives to guard 26 | /// the result of the underlying computation. 27 | pub struct AtomicWaker { 28 | state: AtomicUsize, 29 | waker: UnsafeCell>, 30 | } 31 | 32 | /// Idle state 33 | const WAITING: usize = 0; 34 | 35 | /// A new waker value is being registered with the `AtomicWaker` cell. 36 | const REGISTERING: usize = 0b01; 37 | 38 | /// The waker currently registered with the `AtomicWaker` cell is being woken. 39 | const WAKING: usize = 0b10; 40 | 41 | impl AtomicWaker { 42 | /// Create an `AtomicWaker`. 43 | pub fn new() -> AtomicWaker { 44 | // Make sure that task is Sync 45 | trait AssertSync: Sync {} 46 | impl AssertSync for Waker {} 47 | 48 | AtomicWaker { 49 | state: AtomicUsize::new(WAITING), 50 | waker: UnsafeCell::new(None), 51 | } 52 | } 53 | 54 | /// Registers the waker to be notified on calls to `wake`. 55 | /// 56 | /// The new task will take place of any previous tasks that were registered 57 | /// by previous calls to `register`. Any calls to `wake` that happen after 58 | /// a call to `register` (as defined by the memory ordering rules), will 59 | /// notify the `register` caller's task and deregister the waker from future 60 | /// notifications. Because of this, callers should ensure `register` gets 61 | /// invoked with a new `Waker` **each** time they require a wakeup. 62 | /// 63 | /// It is safe to call `register` with multiple other threads concurrently 64 | /// calling `wake`. This will result in the `register` caller's current 65 | /// task being notified once. 66 | /// 67 | /// This function is safe to call concurrently, but this is generally a bad 68 | /// idea. Concurrent calls to `register` will attempt to register different 69 | /// tasks to be notified. One of the callers will win and have its task set, 70 | /// but there is no guarantee as to which caller will succeed. 71 | /// 72 | /// # Examples 73 | /// 74 | /// Here is how `register` is used when implementing a flag. 75 | /// 76 | /// ``` 77 | /// use std::future::Future; 78 | /// use std::task::{Context, Poll}; 79 | /// use std::sync::atomic::AtomicBool; 80 | /// use std::sync::atomic::Ordering::SeqCst; 81 | /// use std::pin::Pin; 82 | /// 83 | /// use futures::task::AtomicWaker; 84 | /// 85 | /// struct Flag { 86 | /// waker: AtomicWaker, 87 | /// set: AtomicBool, 88 | /// } 89 | /// 90 | /// impl Future for Flag { 91 | /// type Output = (); 92 | /// 93 | /// fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { 94 | /// // Register **before** checking `set` to avoid a race condition 95 | /// // that would result in lost notifications. 96 | /// self.waker.register(cx.waker()); 97 | /// 98 | /// if self.set.load(SeqCst) { 99 | /// Poll::Ready(()) 100 | /// } else { 101 | /// Poll::Pending 102 | /// } 103 | /// } 104 | /// } 105 | /// ``` 106 | pub fn register(&self, waker: &Waker) { 107 | match self.state.compare_and_swap(WAITING, REGISTERING, Acquire) { 108 | WAITING => { 109 | unsafe { 110 | // Locked acquired, update the waker cell 111 | *self.waker.get() = Some(waker.clone()); 112 | 113 | // Release the lock. If the state transitioned to include 114 | // the `WAKING` bit, this means that a wake has been 115 | // called concurrently, so we have to remove the waker and 116 | // wake it.` 117 | // 118 | // Start by assuming that the state is `REGISTERING` as this 119 | // is what we jut set it to. 120 | let res = self 121 | .state 122 | .compare_exchange(REGISTERING, WAITING, AcqRel, Acquire); 123 | 124 | match res { 125 | Ok(_) => {} 126 | Err(actual) => { 127 | // This branch can only be reached if a 128 | // concurrent thread called `wake`. In this 129 | // case, `actual` **must** be `REGISTERING | 130 | // `WAKING`. 131 | debug_assert_eq!(actual, REGISTERING | WAKING); 132 | 133 | // Take the waker to wake once the atomic operation has 134 | // completed. 135 | let waker = (*self.waker.get()).take().unwrap(); 136 | 137 | // Just swap, because no one could change state while state == `REGISTERING` | `WAKING`. 138 | self.state.swap(WAITING, AcqRel); 139 | 140 | // The atomic swap was complete, now 141 | // wake the task and return. 142 | waker.wake(); 143 | } 144 | } 145 | } 146 | } 147 | WAKING => { 148 | // Currently in the process of waking the task, i.e., 149 | // `wake` is currently being called on the old task handle. 150 | // So, we call wake on the new waker 151 | waker.wake_by_ref(); 152 | } 153 | state => { 154 | // In this case, a concurrent thread is holding the 155 | // "registering" lock. This probably indicates a bug in the 156 | // caller's code as racing to call `register` doesn't make much 157 | // sense. 158 | // 159 | // We just want to maintain memory safety. It is ok to drop the 160 | // call to `register`. 161 | debug_assert!(state == REGISTERING || state == REGISTERING | WAKING); 162 | } 163 | } 164 | } 165 | 166 | /// Calls `wake` on the last `Waker` passed to `register`. 167 | /// 168 | /// If `register` has not been called yet, then this does nothing. 169 | pub fn wake(&self) { 170 | if let Some(waker) = self.take() { 171 | waker.wake(); 172 | } 173 | } 174 | 175 | /// Returns the last `Waker` passed to `register`, so that the user can wake it. 176 | /// 177 | /// 178 | /// Sometimes, just waking the AtomicWaker is not fine grained enough. This allows the user 179 | /// to take the waker and then wake it separately, rather than performing both steps in one 180 | /// atomic action. 181 | /// 182 | /// If a waker has not been registered, this returns `None`. 183 | pub fn take(&self) -> Option { 184 | // AcqRel ordering is used in order to acquire the value of the `task` 185 | // cell as well as to establish a `release` ordering with whatever 186 | // memory the `AtomicWaker` is associated with. 187 | match self.state.fetch_or(WAKING, AcqRel) { 188 | WAITING => { 189 | // The waking lock has been acquired. 190 | let waker = unsafe { (*self.waker.get()).take() }; 191 | 192 | // Release the lock 193 | self.state.fetch_and(!WAKING, Release); 194 | 195 | waker 196 | } 197 | state => { 198 | // There is a concurrent thread currently updating the 199 | // associated task. 200 | // 201 | // Nothing more to do as the `WAKING` bit has been set. It 202 | // doesn't matter if there are concurrent registering threads or 203 | // not. 204 | // 205 | debug_assert!( 206 | state == REGISTERING || state == REGISTERING | WAKING || state == WAKING 207 | ); 208 | None 209 | } 210 | } 211 | } 212 | } 213 | 214 | impl Default for AtomicWaker { 215 | fn default() -> Self { 216 | AtomicWaker::new() 217 | } 218 | } 219 | 220 | impl fmt::Debug for AtomicWaker { 221 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 222 | write!(f, "AtomicWaker") 223 | } 224 | } 225 | 226 | unsafe impl Send for AtomicWaker {} 227 | unsafe impl Sync for AtomicWaker {} 228 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/native/heap.rs: -------------------------------------------------------------------------------- 1 | //! A simple binary heap with support for removal of arbitrary elements 2 | //! 3 | //! This heap is used to manage timer state in the event loop. All timeouts go 4 | //! into this heap and we also cancel timeouts from this heap. The crucial 5 | //! feature of this heap over the standard library's `BinaryHeap` is the ability 6 | //! to remove arbitrary elements. (e.g. when a timer is canceled) 7 | //! 8 | //! Note that this heap is not at all optimized right now, it should hopefully 9 | //! just work. 10 | 11 | use std::mem; 12 | 13 | pub struct Heap { 14 | // Binary heap of items, plus the slab index indicating what position in the 15 | // list they're in. 16 | items: Vec<(T, usize)>, 17 | 18 | // A map from a slab index (assigned to an item above) to the actual index 19 | // in the array the item appears at. 20 | index: Vec>, 21 | next_index: usize, 22 | } 23 | 24 | enum SlabSlot { 25 | Empty { next: usize }, 26 | Full { value: T }, 27 | } 28 | 29 | pub struct Slot { 30 | idx: usize, 31 | } 32 | 33 | impl Heap { 34 | pub fn new() -> Heap { 35 | Heap { 36 | items: Vec::new(), 37 | index: Vec::new(), 38 | next_index: 0, 39 | } 40 | } 41 | 42 | /// Pushes an element onto this heap, returning a slot token indicating 43 | /// where it was pushed on to. 44 | /// 45 | /// The slot can later get passed to `remove` to remove the element from the 46 | /// heap, but only if the element was previously not removed from the heap. 47 | pub fn push(&mut self, t: T) -> Slot { 48 | self.assert_consistent(); 49 | let len = self.items.len(); 50 | let slot = SlabSlot::Full { value: len }; 51 | let slot_idx = if self.next_index == self.index.len() { 52 | self.next_index += 1; 53 | self.index.push(slot); 54 | self.index.len() - 1 55 | } else { 56 | match mem::replace(&mut self.index[self.next_index], slot) { 57 | SlabSlot::Empty { next } => mem::replace(&mut self.next_index, next), 58 | SlabSlot::Full { .. } => panic!(), 59 | } 60 | }; 61 | self.items.push((t, slot_idx)); 62 | self.percolate_up(len); 63 | self.assert_consistent(); 64 | Slot { idx: slot_idx } 65 | } 66 | 67 | pub fn peek(&self) -> Option<&T> { 68 | self.assert_consistent(); 69 | self.items.first().map(|i| &i.0) 70 | } 71 | 72 | pub fn pop(&mut self) -> Option { 73 | self.assert_consistent(); 74 | if self.items.is_empty() { 75 | return None; 76 | } 77 | let slot = Slot { 78 | idx: self.items[0].1, 79 | }; 80 | Some(self.remove(slot)) 81 | } 82 | 83 | pub fn remove(&mut self, slot: Slot) -> T { 84 | self.assert_consistent(); 85 | let empty = SlabSlot::Empty { 86 | next: self.next_index, 87 | }; 88 | let idx = match mem::replace(&mut self.index[slot.idx], empty) { 89 | SlabSlot::Full { value } => value, 90 | SlabSlot::Empty { .. } => panic!(), 91 | }; 92 | self.next_index = slot.idx; 93 | let (item, slot_idx) = self.items.swap_remove(idx); 94 | debug_assert_eq!(slot.idx, slot_idx); 95 | if idx < self.items.len() { 96 | set_index(&mut self.index, self.items[idx].1, idx); 97 | if self.items[idx].0 < item { 98 | self.percolate_up(idx); 99 | } else { 100 | self.percolate_down(idx); 101 | } 102 | } 103 | self.assert_consistent(); 104 | item 105 | } 106 | 107 | fn percolate_up(&mut self, mut idx: usize) -> usize { 108 | while idx > 0 { 109 | let parent = (idx - 1) / 2; 110 | if self.items[idx].0 >= self.items[parent].0 { 111 | break; 112 | } 113 | let (a, b) = self.items.split_at_mut(idx); 114 | mem::swap(&mut a[parent], &mut b[0]); 115 | set_index(&mut self.index, a[parent].1, parent); 116 | set_index(&mut self.index, b[0].1, idx); 117 | idx = parent; 118 | } 119 | idx 120 | } 121 | 122 | fn percolate_down(&mut self, mut idx: usize) -> usize { 123 | loop { 124 | let left = 2 * idx + 1; 125 | let right = 2 * idx + 2; 126 | 127 | let mut swap_left = true; 128 | match (self.items.get(left), self.items.get(right)) { 129 | (Some(left), None) => { 130 | if left.0 >= self.items[idx].0 { 131 | break; 132 | } 133 | } 134 | (Some(left), Some(right)) => { 135 | if left.0 < self.items[idx].0 { 136 | if right.0 < left.0 { 137 | swap_left = false; 138 | } 139 | } else if right.0 < self.items[idx].0 { 140 | swap_left = false; 141 | } else { 142 | break; 143 | } 144 | } 145 | 146 | (None, None) => break, 147 | (None, Some(_right)) => panic!("not possible"), 148 | } 149 | 150 | let (a, b) = if swap_left { 151 | self.items.split_at_mut(left) 152 | } else { 153 | self.items.split_at_mut(right) 154 | }; 155 | mem::swap(&mut a[idx], &mut b[0]); 156 | set_index(&mut self.index, a[idx].1, idx); 157 | set_index(&mut self.index, b[0].1, a.len()); 158 | idx = a.len(); 159 | } 160 | idx 161 | } 162 | 163 | fn assert_consistent(&self) { 164 | if !cfg!(assert_timer_heap_consistent) { 165 | return; 166 | } 167 | 168 | assert_eq!( 169 | self.items.len(), 170 | self.index 171 | .iter() 172 | .filter(|slot| { 173 | match **slot { 174 | SlabSlot::Full { .. } => true, 175 | SlabSlot::Empty { .. } => false, 176 | } 177 | }) 178 | .count() 179 | ); 180 | 181 | for (i, &(_, j)) in self.items.iter().enumerate() { 182 | let index = match self.index[j] { 183 | SlabSlot::Full { value } => value, 184 | SlabSlot::Empty { .. } => panic!(), 185 | }; 186 | if index != i { 187 | panic!( 188 | "self.index[j] != i : i={} j={} self.index[j]={}", 189 | i, j, index 190 | ); 191 | } 192 | } 193 | 194 | for (i, (item, _)) in self.items.iter().enumerate() { 195 | if i > 0 { 196 | assert!(*item >= self.items[(i - 1) / 2].0, "bad at index: {}", i); 197 | } 198 | if let Some(left) = self.items.get(2 * i + 1) { 199 | assert!(*item <= left.0, "bad left at index: {}", i); 200 | } 201 | if let Some(right) = self.items.get(2 * i + 2) { 202 | assert!(*item <= right.0, "bad right at index: {}", i); 203 | } 204 | } 205 | } 206 | } 207 | 208 | fn set_index(slab: &mut Vec>, slab_slot: usize, val: T) { 209 | match slab[slab_slot] { 210 | SlabSlot::Full { ref mut value } => *value = val, 211 | SlabSlot::Empty { .. } => panic!(), 212 | } 213 | } 214 | 215 | #[cfg(test)] 216 | mod tests { 217 | use super::Heap; 218 | 219 | #[test] 220 | fn simple() { 221 | let mut h = Heap::new(); 222 | h.push(1); 223 | h.push(2); 224 | h.push(8); 225 | h.push(4); 226 | assert_eq!(h.pop(), Some(1)); 227 | assert_eq!(h.pop(), Some(2)); 228 | assert_eq!(h.pop(), Some(4)); 229 | assert_eq!(h.pop(), Some(8)); 230 | assert_eq!(h.pop(), None); 231 | assert_eq!(h.pop(), None); 232 | } 233 | 234 | #[test] 235 | fn simple2() { 236 | let mut h = Heap::new(); 237 | h.push(5); 238 | h.push(4); 239 | h.push(3); 240 | h.push(2); 241 | h.push(1); 242 | assert_eq!(h.pop(), Some(1)); 243 | h.push(8); 244 | assert_eq!(h.pop(), Some(2)); 245 | h.push(1); 246 | assert_eq!(h.pop(), Some(1)); 247 | assert_eq!(h.pop(), Some(3)); 248 | assert_eq!(h.pop(), Some(4)); 249 | h.push(5); 250 | assert_eq!(h.pop(), Some(5)); 251 | assert_eq!(h.pop(), Some(5)); 252 | assert_eq!(h.pop(), Some(8)); 253 | } 254 | 255 | #[test] 256 | fn remove() { 257 | let mut h = Heap::new(); 258 | h.push(5); 259 | h.push(4); 260 | h.push(3); 261 | let two = h.push(2); 262 | h.push(1); 263 | assert_eq!(h.pop(), Some(1)); 264 | assert_eq!(h.remove(two), 2); 265 | h.push(1); 266 | assert_eq!(h.pop(), Some(1)); 267 | assert_eq!(h.pop(), Some(3)); 268 | } 269 | 270 | fn vec2heap(v: Vec) -> Heap { 271 | let mut h = Heap::new(); 272 | for t in v { 273 | h.push(t); 274 | } 275 | h 276 | } 277 | 278 | #[test] 279 | fn test_peek_and_pop() { 280 | let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]; 281 | let mut sorted = data.clone(); 282 | sorted.sort(); 283 | let mut heap = vec2heap(data); 284 | while heap.peek().is_some() { 285 | assert_eq!(heap.peek().unwrap(), sorted.first().unwrap()); 286 | assert_eq!(heap.pop().unwrap(), sorted.remove(0)); 287 | } 288 | } 289 | 290 | #[test] 291 | fn test_push() { 292 | let mut heap = Heap::new(); 293 | heap.push(-2); 294 | heap.push(-4); 295 | heap.push(-9); 296 | assert!(*heap.peek().unwrap() == -9); 297 | heap.push(-11); 298 | assert!(*heap.peek().unwrap() == -11); 299 | heap.push(-5); 300 | assert!(*heap.peek().unwrap() == -11); 301 | heap.push(-27); 302 | assert!(*heap.peek().unwrap() == -27); 303 | heap.push(-3); 304 | assert!(*heap.peek().unwrap() == -27); 305 | heap.push(-103); 306 | assert!(*heap.peek().unwrap() == -103); 307 | } 308 | 309 | fn check_to_vec(mut data: Vec) { 310 | let mut heap = Heap::new(); 311 | for data in data.iter() { 312 | heap.push(*data); 313 | } 314 | data.sort(); 315 | let mut v = Vec::new(); 316 | while let Some(i) = heap.pop() { 317 | v.push(i); 318 | } 319 | assert_eq!(v, data); 320 | } 321 | 322 | #[test] 323 | fn test_to_vec() { 324 | check_to_vec(vec![]); 325 | check_to_vec(vec![5]); 326 | check_to_vec(vec![3, 2]); 327 | check_to_vec(vec![2, 3]); 328 | check_to_vec(vec![5, 1, 2]); 329 | check_to_vec(vec![1, 100, 2, 3]); 330 | check_to_vec(vec![1, 3, 5, 7, 9, 2, 4, 6, 8, 0]); 331 | check_to_vec(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]); 332 | check_to_vec(vec![9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]); 333 | check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 334 | check_to_vec(vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]); 335 | check_to_vec(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]); 336 | check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]); 337 | } 338 | 339 | #[test] 340 | fn test_empty_pop() { 341 | let mut heap = Heap::::new(); 342 | assert!(heap.pop().is_none()); 343 | } 344 | 345 | #[test] 346 | fn test_empty_peek() { 347 | let empty = Heap::::new(); 348 | assert!(empty.peek().is_none()); 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /src/native/timer.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::pin::Pin; 3 | use std::sync::atomic::Ordering::SeqCst; 4 | use std::sync::atomic::{AtomicPtr, AtomicUsize}; 5 | use std::sync::{Arc, Mutex, Weak}; 6 | use std::task::{Context, Poll}; 7 | use std::time::Instant; 8 | 9 | use std::future::Future; 10 | 11 | use super::AtomicWaker; 12 | use super::{global, ArcList, Heap, HeapTimer, Node, Slot}; 13 | 14 | /// A "timer heap" used to power separately owned instances of `Delay`. 15 | /// 16 | /// This timer is implemented as a priority queued-based heap. Each `Timer` 17 | /// contains a few primary methods which which to drive it: 18 | /// 19 | /// * `next_wake` indicates how long the ambient system needs to sleep until it 20 | /// invokes further processing on a `Timer` 21 | /// * `advance_to` is what actually fires timers on the `Timer`, and should be 22 | /// called essentially every iteration of the event loop, or when the time 23 | /// specified by `next_wake` has elapsed. 24 | /// * The `Future` implementation for `Timer` is used to process incoming timer 25 | /// updates and requests. This is used to schedule new timeouts, update 26 | /// existing ones, or delete existing timeouts. The `Future` implementation 27 | /// will never resolve, but it'll schedule notifications of when to wake up 28 | /// and process more messages. 29 | /// 30 | /// Note that if you're using this crate you probably don't need to use a 31 | /// `Timer` as there is a global one already available for you run on a helper 32 | /// thread. If this isn't desirable, though, then the 33 | /// `TimerHandle::set_fallback` method can be used instead! 34 | pub struct Timer { 35 | inner: Arc, 36 | timer_heap: Heap, 37 | } 38 | 39 | /// A handle to a `Timer` which is used to create instances of a `Delay`. 40 | #[derive(Clone)] 41 | pub struct TimerHandle { 42 | pub(crate) inner: Weak, 43 | } 44 | 45 | pub(crate) struct Inner { 46 | /// List of updates the `Timer` needs to process 47 | pub(crate) list: ArcList, 48 | 49 | /// The blocked `Timer` task to receive notifications to the `list` above. 50 | pub(crate) waker: AtomicWaker, 51 | } 52 | 53 | /// Shared state between the `Timer` and a `Delay`. 54 | pub(crate) struct ScheduledTimer { 55 | pub(crate) waker: AtomicWaker, 56 | 57 | // The lowest bit here is whether the timer has fired or not, the second 58 | // lowest bit is whether the timer has been invalidated, and all the other 59 | // bits are the "generation" of the timer which is reset during the `reset` 60 | // function. Only timers for a matching generation are fired. 61 | pub(crate) state: AtomicUsize, 62 | 63 | pub(crate) inner: Weak, 64 | pub(crate) at: Mutex>, 65 | 66 | // TODO: this is only accessed by the timer thread, should have a more 67 | // lightweight protection than a `Mutex` 68 | pub(crate) slot: Mutex>, 69 | } 70 | 71 | impl Timer { 72 | /// Creates a new timer heap ready to create new timers. 73 | pub fn new() -> Timer { 74 | Timer { 75 | inner: Arc::new(Inner { 76 | list: ArcList::new(), 77 | waker: AtomicWaker::new(), 78 | }), 79 | timer_heap: Heap::new(), 80 | } 81 | } 82 | 83 | /// Returns a handle to this timer heap, used to create new timeouts. 84 | pub fn handle(&self) -> TimerHandle { 85 | TimerHandle { 86 | inner: Arc::downgrade(&self.inner), 87 | } 88 | } 89 | 90 | /// Returns the time at which this timer next needs to be invoked with 91 | /// `advance_to`. 92 | /// 93 | /// Event loops or threads typically want to sleep until the specified 94 | /// instant. 95 | pub fn next_event(&self) -> Option { 96 | self.timer_heap.peek().map(|t| t.at) 97 | } 98 | 99 | /// Proces any timers which are supposed to fire at or before the current 100 | /// instant. 101 | /// 102 | /// This method is equivalent to `self.advance_to(Instant::now())`. 103 | pub fn advance(&mut self) { 104 | self.advance_to(Instant::now()) 105 | } 106 | 107 | /// Proces any timers which are supposed to fire before `now` specified. 108 | /// 109 | /// This method should be called on `Timer` periodically to advance the 110 | /// internal state and process any pending timers which need to fire. 111 | pub fn advance_to(&mut self, now: Instant) { 112 | loop { 113 | match self.timer_heap.peek() { 114 | Some(head) if head.at <= now => {} 115 | Some(_) => break, 116 | None => break, 117 | }; 118 | 119 | // Flag the timer as fired and then notify its task, if any, that's 120 | // blocked. 121 | let heap_timer = self.timer_heap.pop().unwrap(); 122 | *heap_timer.node.slot.lock().unwrap() = None; 123 | let bits = heap_timer.gen << 2; 124 | match heap_timer 125 | .node 126 | .state 127 | .compare_exchange(bits, bits | 0b01, SeqCst, SeqCst) 128 | { 129 | Ok(_) => heap_timer.node.waker.wake(), 130 | Err(_b) => {} 131 | } 132 | } 133 | } 134 | 135 | /// Either updates the timer at slot `idx` to fire at `at`, or adds a new 136 | /// timer at `idx` and sets it to fire at `at`. 137 | fn update_or_add(&mut self, at: Instant, node: Arc>) { 138 | // TODO: avoid remove + push and instead just do one sift of the heap? 139 | // In theory we could update it in place and then do the percolation 140 | // as necessary 141 | let gen = node.state.load(SeqCst) >> 2; 142 | let mut slot = node.slot.lock().unwrap(); 143 | if let Some(heap_slot) = slot.take() { 144 | self.timer_heap.remove(heap_slot); 145 | } 146 | *slot = Some(self.timer_heap.push(HeapTimer { 147 | at, 148 | gen, 149 | node: node.clone(), 150 | })); 151 | } 152 | 153 | fn remove(&mut self, node: Arc>) { 154 | // If this `idx` is still around and it's still got a registered timer, 155 | // then we jettison it form the timer heap. 156 | let mut slot = node.slot.lock().unwrap(); 157 | let heap_slot = match slot.take() { 158 | Some(slot) => slot, 159 | None => return, 160 | }; 161 | self.timer_heap.remove(heap_slot); 162 | } 163 | 164 | fn invalidate(&mut self, node: Arc>) { 165 | node.state.fetch_or(0b10, SeqCst); 166 | node.waker.wake(); 167 | } 168 | } 169 | 170 | impl Future for Timer { 171 | type Output = (); 172 | 173 | fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { 174 | Pin::new(&mut self.inner).waker.register(cx.waker()); 175 | let mut list = self.inner.list.take(); 176 | while let Some(node) = list.pop() { 177 | let at = *node.at.lock().unwrap(); 178 | match at { 179 | Some(at) => self.update_or_add(at, node), 180 | None => self.remove(node), 181 | } 182 | } 183 | Poll::Pending 184 | } 185 | } 186 | 187 | impl Drop for Timer { 188 | fn drop(&mut self) { 189 | // Seal off our list to prevent any more updates from getting pushed on. 190 | // Any timer which sees an error from the push will immediately become 191 | // inert. 192 | let mut list = self.inner.list.take_and_seal(); 193 | 194 | // Now that we'll never receive another timer, drain the list of all 195 | // updates and also drain our heap of all active timers, invalidating 196 | // everything. 197 | while let Some(t) = list.pop() { 198 | self.invalidate(t); 199 | } 200 | while let Some(t) = self.timer_heap.pop() { 201 | self.invalidate(t.node); 202 | } 203 | } 204 | } 205 | 206 | impl fmt::Debug for Timer { 207 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 208 | f.debug_struct("Timer").field("heap", &"...").finish() 209 | } 210 | } 211 | 212 | impl Default for Timer { 213 | fn default() -> Self { 214 | Self::new() 215 | } 216 | } 217 | 218 | static HANDLE_FALLBACK: AtomicPtr = AtomicPtr::new(EMPTY_HANDLE); 219 | const EMPTY_HANDLE: *mut Inner = std::ptr::null_mut(); 220 | 221 | /// Error returned from `TimerHandle::set_fallback`. 222 | #[derive(Clone, Debug)] 223 | struct SetDefaultError(()); 224 | 225 | impl TimerHandle { 226 | /// Configures this timer handle to be the one returned by 227 | /// `TimerHandle::default`. 228 | /// 229 | /// By default a global thread is initialized on the first call to 230 | /// `TimerHandle::default`. This first call can happen transitively through 231 | /// `Delay::new`. If, however, that hasn't happened yet then the global 232 | /// default timer handle can be configured through this method. 233 | /// 234 | /// This method can be used to prevent the global helper thread from 235 | /// spawning. If this method is successful then the global helper thread 236 | /// will never get spun up. 237 | /// 238 | /// On success this timer handle will have installed itself globally to be 239 | /// used as the return value for `TimerHandle::default` unless otherwise 240 | /// specified. 241 | /// 242 | /// # Errors 243 | /// 244 | /// If another thread has already called `set_as_global_fallback` or this 245 | /// thread otherwise loses a race to call this method then it will fail 246 | /// returning an error. Once a call to `set_as_global_fallback` is 247 | /// successful then no future calls may succeed. 248 | fn set_as_global_fallback(self) -> Result<(), SetDefaultError> { 249 | unsafe { 250 | let val = self.into_raw(); 251 | match HANDLE_FALLBACK.compare_exchange(EMPTY_HANDLE, val, SeqCst, SeqCst) { 252 | Ok(_) => Ok(()), 253 | Err(_) => { 254 | drop(TimerHandle::from_raw(val)); 255 | Err(SetDefaultError(())) 256 | } 257 | } 258 | } 259 | } 260 | 261 | fn into_raw(self) -> *mut Inner { 262 | self.inner.into_raw() as *mut Inner 263 | } 264 | 265 | unsafe fn from_raw(val: *mut Inner) -> TimerHandle { 266 | let inner = Weak::from_raw(val); 267 | TimerHandle { inner } 268 | } 269 | } 270 | 271 | impl Default for TimerHandle { 272 | fn default() -> TimerHandle { 273 | let mut fallback = HANDLE_FALLBACK.load(SeqCst); 274 | 275 | // If the fallback hasn't been previously initialized then let's spin 276 | // up a helper thread and try to initialize with that. If we can't 277 | // actually create a helper thread then we'll just return a "defunkt" 278 | // handle which will return errors when timer objects are attempted to 279 | // be associated. 280 | if fallback == EMPTY_HANDLE { 281 | let helper = match global::HelperThread::new() { 282 | Ok(helper) => helper, 283 | Err(_) => return TimerHandle { inner: Weak::new() }, 284 | }; 285 | 286 | // If we successfully set ourselves as the actual fallback then we 287 | // want to `forget` the helper thread to ensure that it persists 288 | // globally. If we fail to set ourselves as the fallback that means 289 | // that someone was racing with this call to 290 | // `TimerHandle::default`. They ended up winning so we'll destroy 291 | // our helper thread (which shuts down the thread) and reload the 292 | // fallback. 293 | if helper.handle().set_as_global_fallback().is_ok() { 294 | let ret = helper.handle(); 295 | helper.forget(); 296 | return ret; 297 | } 298 | fallback = HANDLE_FALLBACK.load(SeqCst); 299 | } 300 | 301 | // At this point our fallback handle global was configured so we use 302 | // its value to reify a handle, clone it, and then forget our reified 303 | // handle as we don't actually have an owning reference to it. 304 | assert!(fallback != EMPTY_HANDLE); 305 | unsafe { 306 | let handle = TimerHandle::from_raw(fallback); 307 | let ret = handle.clone(); 308 | let _ = handle.into_raw(); 309 | ret 310 | } 311 | } 312 | } 313 | 314 | impl fmt::Debug for TimerHandle { 315 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 316 | f.debug_struct("TimerHandle") 317 | .field("inner", &"...") 318 | .finish() 319 | } 320 | } 321 | --------------------------------------------------------------------------------