1 //! Timer state structures. 2 //! 3 //! This module contains the heart of the intrusive timer implementation, and as 4 //! such the structures inside are full of tricky concurrency and unsafe code. 5 //! 6 //! # Ground rules 7 //! 8 //! The heart of the timer implementation here is the [`TimerShared`] structure, 9 //! shared between the [`TimerEntry`] and the driver. Generally, we permit access 10 //! to [`TimerShared`] ONLY via either 1) a mutable reference to [`TimerEntry`] or 11 //! 2) a held driver lock. 12 //! 13 //! It follows from this that any changes made while holding BOTH 1 and 2 will 14 //! be reliably visible, regardless of ordering. This is because of the acq/rel 15 //! fences on the driver lock ensuring ordering with 2, and rust mutable 16 //! reference rules for 1 (a mutable reference to an object can't be passed 17 //! between threads without an acq/rel barrier, and same-thread we have local 18 //! happens-before ordering). 19 //! 20 //! # State field 21 //! 22 //! Each timer has a state field associated with it. This field contains either 23 //! the current scheduled time, or a special flag value indicating its state. 24 //! This state can either indicate that the timer is on the 'pending' queue (and 25 //! thus will be fired with an `Ok(())` result soon) or that it has already been 26 //! fired/deregistered. 27 //! 28 //! This single state field allows for code that is firing the timer to 29 //! synchronize with any racing `reset` calls reliably. 30 //! 31 //! # Cached vs true timeouts 32 //! 33 //! To allow for the use case of a timeout that is periodically reset before 34 //! expiration to be as lightweight as possible, we support optimistically 35 //! lock-free timer resets, in the case where a timer is rescheduled to a later 36 //! point than it was originally scheduled for. 37 //! 38 //! This is accomplished by lazily rescheduling timers. That is, we update the 39 //! state field with the true expiration of the timer from the holder of 40 //! the [`TimerEntry`]. When the driver services timers (ie, whenever it's 41 //! walking lists of timers), it checks this "true when" value, and reschedules 42 //! based on it. 43 //! 44 //! We do, however, also need to track what the expiration time was when we 45 //! originally registered the timer; this is used to locate the right linked 46 //! list when the timer is being cancelled. This is referred to as the "cached 47 //! when" internally. 48 //! 49 //! There is of course a race condition between timer reset and timer 50 //! expiration. If the driver fails to observe the updated expiration time, it 51 //! could trigger expiration of the timer too early. However, because 52 //! [`mark_pending`][mark_pending] performs a compare-and-swap, it will identify this race and 53 //! refuse to mark the timer as pending. 54 //! 55 //! [mark_pending]: TimerHandle::mark_pending 56 57 use crate::loom::cell::UnsafeCell; 58 use crate::loom::sync::atomic::AtomicU64; 59 use crate::loom::sync::atomic::Ordering; 60 61 use crate::runtime::scheduler; 62 use crate::sync::AtomicWaker; 63 use crate::time::Instant; 64 use crate::util::linked_list; 65 66 use std::cell::UnsafeCell as StdUnsafeCell; 67 use std::task::{Context, Poll, Waker}; 68 use std::{marker::PhantomPinned, pin::Pin, ptr::NonNull}; 69 70 type TimerResult = Result<(), crate::time::error::Error>; 71 72 const STATE_DEREGISTERED: u64 = u64::MAX; 73 const STATE_PENDING_FIRE: u64 = STATE_DEREGISTERED - 1; 74 const STATE_MIN_VALUE: u64 = STATE_PENDING_FIRE; 75 /// The largest safe integer to use for ticks. 76 /// 77 /// This value should be updated if any other signal values are added above. 78 pub(super) const MAX_SAFE_MILLIS_DURATION: u64 = u64::MAX - 2; 79 80 /// This structure holds the current shared state of the timer - its scheduled 81 /// time (if registered), or otherwise the result of the timer completing, as 82 /// well as the registered waker. 83 /// 84 /// Generally, the StateCell is only permitted to be accessed from two contexts: 85 /// Either a thread holding the corresponding &mut TimerEntry, or a thread 86 /// holding the timer driver lock. The write actions on the StateCell amount to 87 /// passing "ownership" of the StateCell between these contexts; moving a timer 88 /// from the TimerEntry to the driver requires _both_ holding the &mut 89 /// TimerEntry and the driver lock, while moving it back (firing the timer) 90 /// requires only the driver lock. 91 pub(super) struct StateCell { 92 /// Holds either the scheduled expiration time for this timer, or (if the 93 /// timer has been fired and is unregistered), `u64::MAX`. 94 state: AtomicU64, 95 /// If the timer is fired (an Acquire order read on state shows 96 /// `u64::MAX`), holds the result that should be returned from 97 /// polling the timer. Otherwise, the contents are unspecified and reading 98 /// without holding the driver lock is undefined behavior. 99 result: UnsafeCell<TimerResult>, 100 /// The currently-registered waker 101 waker: AtomicWaker, 102 } 103 104 impl Default for StateCell { default() -> Self105 fn default() -> Self { 106 Self::new() 107 } 108 } 109 110 impl std::fmt::Debug for StateCell { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 112 write!(f, "StateCell({:?})", self.read_state()) 113 } 114 } 115 116 impl StateCell { new() -> Self117 fn new() -> Self { 118 Self { 119 state: AtomicU64::new(STATE_DEREGISTERED), 120 result: UnsafeCell::new(Ok(())), 121 waker: AtomicWaker::new(), 122 } 123 } 124 is_pending(&self) -> bool125 fn is_pending(&self) -> bool { 126 self.state.load(Ordering::Relaxed) == STATE_PENDING_FIRE 127 } 128 129 /// Returns the current expiration time, or None if not currently scheduled. when(&self) -> Option<u64>130 fn when(&self) -> Option<u64> { 131 let cur_state = self.state.load(Ordering::Relaxed); 132 133 if cur_state == STATE_DEREGISTERED { 134 None 135 } else { 136 Some(cur_state) 137 } 138 } 139 140 /// If the timer is completed, returns the result of the timer. Otherwise, 141 /// returns None and registers the waker. poll(&self, waker: &Waker) -> Poll<TimerResult>142 fn poll(&self, waker: &Waker) -> Poll<TimerResult> { 143 // We must register first. This ensures that either `fire` will 144 // observe the new waker, or we will observe a racing fire to have set 145 // the state, or both. 146 self.waker.register_by_ref(waker); 147 148 self.read_state() 149 } 150 read_state(&self) -> Poll<TimerResult>151 fn read_state(&self) -> Poll<TimerResult> { 152 let cur_state = self.state.load(Ordering::Acquire); 153 154 if cur_state == STATE_DEREGISTERED { 155 // SAFETY: The driver has fired this timer; this involves writing 156 // the result, and then writing (with release ordering) the state 157 // field. 158 Poll::Ready(unsafe { self.result.with(|p| *p) }) 159 } else { 160 Poll::Pending 161 } 162 } 163 164 /// Marks this timer as being moved to the pending list, if its scheduled 165 /// time is not after `not_after`. 166 /// 167 /// If the timer is scheduled for a time after not_after, returns an Err 168 /// containing the current scheduled time. 169 /// 170 /// SAFETY: Must hold the driver lock. mark_pending(&self, not_after: u64) -> Result<(), u64>171 unsafe fn mark_pending(&self, not_after: u64) -> Result<(), u64> { 172 // Quick initial debug check to see if the timer is already fired. Since 173 // firing the timer can only happen with the driver lock held, we know 174 // we shouldn't be able to "miss" a transition to a fired state, even 175 // with relaxed ordering. 176 let mut cur_state = self.state.load(Ordering::Relaxed); 177 178 loop { 179 // improve the error message for things like 180 // https://github.com/tokio-rs/tokio/issues/3675 181 assert!( 182 cur_state < STATE_MIN_VALUE, 183 "mark_pending called when the timer entry is in an invalid state" 184 ); 185 186 if cur_state > not_after { 187 break Err(cur_state); 188 } 189 190 match self.state.compare_exchange( 191 cur_state, 192 STATE_PENDING_FIRE, 193 Ordering::AcqRel, 194 Ordering::Acquire, 195 ) { 196 Ok(_) => { 197 break Ok(()); 198 } 199 Err(actual_state) => { 200 cur_state = actual_state; 201 } 202 } 203 } 204 } 205 206 /// Fires the timer, setting the result to the provided result. 207 /// 208 /// Returns: 209 /// * `Some(waker) - if fired and a waker needs to be invoked once the 210 /// driver lock is released 211 /// * `None` - if fired and a waker does not need to be invoked, or if 212 /// already fired 213 /// 214 /// SAFETY: The driver lock must be held. fire(&self, result: TimerResult) -> Option<Waker>215 unsafe fn fire(&self, result: TimerResult) -> Option<Waker> { 216 // Quick initial check to see if the timer is already fired. Since 217 // firing the timer can only happen with the driver lock held, we know 218 // we shouldn't be able to "miss" a transition to a fired state, even 219 // with relaxed ordering. 220 let cur_state = self.state.load(Ordering::Relaxed); 221 if cur_state == STATE_DEREGISTERED { 222 return None; 223 } 224 225 // SAFETY: We assume the driver lock is held and the timer is not 226 // fired, so only the driver is accessing this field. 227 // 228 // We perform a release-ordered store to state below, to ensure this 229 // write is visible before the state update is visible. 230 unsafe { self.result.with_mut(|p| *p = result) }; 231 232 self.state.store(STATE_DEREGISTERED, Ordering::Release); 233 234 self.waker.take_waker() 235 } 236 237 /// Marks the timer as registered (poll will return None) and sets the 238 /// expiration time. 239 /// 240 /// While this function is memory-safe, it should only be called from a 241 /// context holding both `&mut TimerEntry` and the driver lock. set_expiration(&self, timestamp: u64)242 fn set_expiration(&self, timestamp: u64) { 243 debug_assert!(timestamp < STATE_MIN_VALUE); 244 245 // We can use relaxed ordering because we hold the driver lock and will 246 // fence when we release the lock. 247 self.state.store(timestamp, Ordering::Relaxed); 248 } 249 250 /// Attempts to adjust the timer to a new timestamp. 251 /// 252 /// If the timer has already been fired, is pending firing, or the new 253 /// timestamp is earlier than the old timestamp, (or occasionally 254 /// spuriously) returns Err without changing the timer's state. In this 255 /// case, the timer must be deregistered and re-registered. extend_expiration(&self, new_timestamp: u64) -> Result<(), ()>256 fn extend_expiration(&self, new_timestamp: u64) -> Result<(), ()> { 257 let mut prior = self.state.load(Ordering::Relaxed); 258 loop { 259 if new_timestamp < prior || prior >= STATE_MIN_VALUE { 260 return Err(()); 261 } 262 263 match self.state.compare_exchange_weak( 264 prior, 265 new_timestamp, 266 Ordering::AcqRel, 267 Ordering::Acquire, 268 ) { 269 Ok(_) => { 270 return Ok(()); 271 } 272 Err(true_prior) => { 273 prior = true_prior; 274 } 275 } 276 } 277 } 278 279 /// Returns true if the state of this timer indicates that the timer might 280 /// be registered with the driver. This check is performed with relaxed 281 /// ordering, but is conservative - if it returns false, the timer is 282 /// definitely _not_ registered. might_be_registered(&self) -> bool283 pub(super) fn might_be_registered(&self) -> bool { 284 self.state.load(Ordering::Relaxed) != u64::MAX 285 } 286 } 287 288 /// A timer entry. 289 /// 290 /// This is the handle to a timer that is controlled by the requester of the 291 /// timer. As this participates in intrusive data structures, it must be pinned 292 /// before polling. 293 #[derive(Debug)] 294 pub(crate) struct TimerEntry { 295 /// Arc reference to the runtime handle. We can only free the driver after 296 /// deregistering everything from their respective timer wheels. 297 driver: scheduler::Handle, 298 /// Shared inner structure; this is part of an intrusive linked list, and 299 /// therefore other references can exist to it while mutable references to 300 /// Entry exist. 301 /// 302 /// This is manipulated only under the inner mutex. TODO: Can we use loom 303 /// cells for this? 304 inner: StdUnsafeCell<TimerShared>, 305 /// Deadline for the timer. This is used to register on the first 306 /// poll, as we can't register prior to being pinned. 307 deadline: Instant, 308 /// Whether the deadline has been registered. 309 registered: bool, 310 /// Ensure the type is !Unpin 311 _m: std::marker::PhantomPinned, 312 } 313 314 unsafe impl Send for TimerEntry {} 315 unsafe impl Sync for TimerEntry {} 316 317 /// An TimerHandle is the (non-enforced) "unique" pointer from the driver to the 318 /// timer entry. Generally, at most one TimerHandle exists for a timer at a time 319 /// (enforced by the timer state machine). 320 /// 321 /// SAFETY: An TimerHandle is essentially a raw pointer, and the usual caveats 322 /// of pointer safety apply. In particular, TimerHandle does not itself enforce 323 /// that the timer does still exist; however, normally an TimerHandle is created 324 /// immediately before registering the timer, and is consumed when firing the 325 /// timer, to help minimize mistakes. Still, because TimerHandle cannot enforce 326 /// memory safety, all operations are unsafe. 327 #[derive(Debug)] 328 pub(crate) struct TimerHandle { 329 inner: NonNull<TimerShared>, 330 } 331 332 pub(super) type EntryList = crate::util::linked_list::LinkedList<TimerShared, TimerShared>; 333 334 /// The shared state structure of a timer. This structure is shared between the 335 /// frontend (`Entry`) and driver backend. 336 /// 337 /// Note that this structure is located inside the `TimerEntry` structure. 338 pub(crate) struct TimerShared { 339 /// A link within the doubly-linked list of timers on a particular level and 340 /// slot. Valid only if state is equal to Registered. 341 /// 342 /// Only accessed under the entry lock. 343 pointers: linked_list::Pointers<TimerShared>, 344 345 /// The expiration time for which this entry is currently registered. 346 /// Generally owned by the driver, but is accessed by the entry when not 347 /// registered. 348 cached_when: AtomicU64, 349 350 /// The true expiration time. Set by the timer future, read by the driver. 351 true_when: AtomicU64, 352 353 /// Current state. This records whether the timer entry is currently under 354 /// the ownership of the driver, and if not, its current state (not 355 /// complete, fired, error, etc). 356 state: StateCell, 357 358 _p: PhantomPinned, 359 } 360 361 unsafe impl Send for TimerShared {} 362 unsafe impl Sync for TimerShared {} 363 364 impl std::fmt::Debug for TimerShared { fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result365 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 366 f.debug_struct("TimerShared") 367 .field("when", &self.true_when.load(Ordering::Relaxed)) 368 .field("cached_when", &self.cached_when.load(Ordering::Relaxed)) 369 .field("state", &self.state) 370 .finish() 371 } 372 } 373 374 generate_addr_of_methods! { 375 impl<> TimerShared { 376 unsafe fn addr_of_pointers(self: NonNull<Self>) -> NonNull<linked_list::Pointers<TimerShared>> { 377 &self.pointers 378 } 379 } 380 } 381 382 impl TimerShared { new() -> Self383 pub(super) fn new() -> Self { 384 Self { 385 cached_when: AtomicU64::new(0), 386 true_when: AtomicU64::new(0), 387 pointers: linked_list::Pointers::new(), 388 state: StateCell::default(), 389 _p: PhantomPinned, 390 } 391 } 392 393 /// Gets the cached time-of-expiration value. cached_when(&self) -> u64394 pub(super) fn cached_when(&self) -> u64 { 395 // Cached-when is only accessed under the driver lock, so we can use relaxed 396 self.cached_when.load(Ordering::Relaxed) 397 } 398 399 /// Gets the true time-of-expiration value, and copies it into the cached 400 /// time-of-expiration value. 401 /// 402 /// SAFETY: Must be called with the driver lock held, and when this entry is 403 /// not in any timer wheel lists. sync_when(&self) -> u64404 pub(super) unsafe fn sync_when(&self) -> u64 { 405 let true_when = self.true_when(); 406 407 self.cached_when.store(true_when, Ordering::Relaxed); 408 409 true_when 410 } 411 412 /// Sets the cached time-of-expiration value. 413 /// 414 /// SAFETY: Must be called with the driver lock held, and when this entry is 415 /// not in any timer wheel lists. set_cached_when(&self, when: u64)416 unsafe fn set_cached_when(&self, when: u64) { 417 self.cached_when.store(when, Ordering::Relaxed); 418 } 419 420 /// Returns the true time-of-expiration value, with relaxed memory ordering. true_when(&self) -> u64421 pub(super) fn true_when(&self) -> u64 { 422 self.state.when().expect("Timer already fired") 423 } 424 425 /// Sets the true time-of-expiration value, even if it is less than the 426 /// current expiration or the timer is deregistered. 427 /// 428 /// SAFETY: Must only be called with the driver lock held and the entry not 429 /// in the timer wheel. set_expiration(&self, t: u64)430 pub(super) unsafe fn set_expiration(&self, t: u64) { 431 self.state.set_expiration(t); 432 self.cached_when.store(t, Ordering::Relaxed); 433 } 434 435 /// Sets the true time-of-expiration only if it is after the current. extend_expiration(&self, t: u64) -> Result<(), ()>436 pub(super) fn extend_expiration(&self, t: u64) -> Result<(), ()> { 437 self.state.extend_expiration(t) 438 } 439 440 /// Returns a TimerHandle for this timer. handle(&self) -> TimerHandle441 pub(super) fn handle(&self) -> TimerHandle { 442 TimerHandle { 443 inner: NonNull::from(self), 444 } 445 } 446 447 /// Returns true if the state of this timer indicates that the timer might 448 /// be registered with the driver. This check is performed with relaxed 449 /// ordering, but is conservative - if it returns false, the timer is 450 /// definitely _not_ registered. might_be_registered(&self) -> bool451 pub(super) fn might_be_registered(&self) -> bool { 452 self.state.might_be_registered() 453 } 454 } 455 456 unsafe impl linked_list::Link for TimerShared { 457 type Handle = TimerHandle; 458 459 type Target = TimerShared; 460 as_raw(handle: &Self::Handle) -> NonNull<Self::Target>461 fn as_raw(handle: &Self::Handle) -> NonNull<Self::Target> { 462 handle.inner 463 } 464 from_raw(ptr: NonNull<Self::Target>) -> Self::Handle465 unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Self::Handle { 466 TimerHandle { inner: ptr } 467 } 468 pointers( target: NonNull<Self::Target>, ) -> NonNull<linked_list::Pointers<Self::Target>>469 unsafe fn pointers( 470 target: NonNull<Self::Target>, 471 ) -> NonNull<linked_list::Pointers<Self::Target>> { 472 TimerShared::addr_of_pointers(target) 473 } 474 } 475 476 // ===== impl Entry ===== 477 478 impl TimerEntry { 479 #[track_caller] new(handle: &scheduler::Handle, deadline: Instant) -> Self480 pub(crate) fn new(handle: &scheduler::Handle, deadline: Instant) -> Self { 481 // Panic if the time driver is not enabled 482 let _ = handle.driver().time(); 483 484 let driver = handle.clone(); 485 486 Self { 487 driver, 488 inner: StdUnsafeCell::new(TimerShared::new()), 489 deadline, 490 registered: false, 491 _m: std::marker::PhantomPinned, 492 } 493 } 494 inner(&self) -> &TimerShared495 fn inner(&self) -> &TimerShared { 496 unsafe { &*self.inner.get() } 497 } 498 deadline(&self) -> Instant499 pub(crate) fn deadline(&self) -> Instant { 500 self.deadline 501 } 502 is_elapsed(&self) -> bool503 pub(crate) fn is_elapsed(&self) -> bool { 504 !self.inner().state.might_be_registered() && self.registered 505 } 506 507 /// Cancels and deregisters the timer. This operation is irreversible. cancel(self: Pin<&mut Self>)508 pub(crate) fn cancel(self: Pin<&mut Self>) { 509 // We need to perform an acq/rel fence with the driver thread, and the 510 // simplest way to do so is to grab the driver lock. 511 // 512 // Why is this necessary? We're about to release this timer's memory for 513 // some other non-timer use. However, we've been doing a bunch of 514 // relaxed (or even non-atomic) writes from the driver thread, and we'll 515 // be doing more from _this thread_ (as this memory is interpreted as 516 // something else). 517 // 518 // It is critical to ensure that, from the point of view of the driver, 519 // those future non-timer writes happen-after the timer is fully fired, 520 // and from the purpose of this thread, the driver's writes all 521 // happen-before we drop the timer. This in turn requires us to perform 522 // an acquire-release barrier in _both_ directions between the driver 523 // and dropping thread. 524 // 525 // The lock acquisition in clear_entry serves this purpose. All of the 526 // driver manipulations happen with the lock held, so we can just take 527 // the lock and be sure that this drop happens-after everything the 528 // driver did so far and happens-before everything the driver does in 529 // the future. While we have the lock held, we also go ahead and 530 // deregister the entry if necessary. 531 unsafe { self.driver().clear_entry(NonNull::from(self.inner())) }; 532 } 533 reset(mut self: Pin<&mut Self>, new_time: Instant, reregister: bool)534 pub(crate) fn reset(mut self: Pin<&mut Self>, new_time: Instant, reregister: bool) { 535 unsafe { self.as_mut().get_unchecked_mut() }.deadline = new_time; 536 unsafe { self.as_mut().get_unchecked_mut() }.registered = reregister; 537 538 let tick = self.driver().time_source().deadline_to_tick(new_time); 539 540 if self.inner().extend_expiration(tick).is_ok() { 541 return; 542 } 543 544 if reregister { 545 unsafe { 546 self.driver() 547 .reregister(&self.driver.driver().io, tick, self.inner().into()); 548 } 549 } 550 } 551 poll_elapsed( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll<Result<(), super::Error>>552 pub(crate) fn poll_elapsed( 553 mut self: Pin<&mut Self>, 554 cx: &mut Context<'_>, 555 ) -> Poll<Result<(), super::Error>> { 556 if self.driver().is_shutdown() { 557 panic!("{}", crate::util::error::RUNTIME_SHUTTING_DOWN_ERROR); 558 } 559 560 if !self.registered { 561 let deadline = self.deadline; 562 self.as_mut().reset(deadline, true); 563 } 564 565 let this = unsafe { self.get_unchecked_mut() }; 566 567 this.inner().state.poll(cx.waker()) 568 } 569 driver(&self) -> &super::Handle570 pub(crate) fn driver(&self) -> &super::Handle { 571 self.driver.driver().time() 572 } 573 574 #[cfg(all(tokio_unstable, feature = "tracing"))] clock(&self) -> &super::Clock575 pub(crate) fn clock(&self) -> &super::Clock { 576 self.driver.driver().clock() 577 } 578 } 579 580 impl TimerHandle { cached_when(&self) -> u64581 pub(super) unsafe fn cached_when(&self) -> u64 { 582 unsafe { self.inner.as_ref().cached_when() } 583 } 584 sync_when(&self) -> u64585 pub(super) unsafe fn sync_when(&self) -> u64 { 586 unsafe { self.inner.as_ref().sync_when() } 587 } 588 is_pending(&self) -> bool589 pub(super) unsafe fn is_pending(&self) -> bool { 590 unsafe { self.inner.as_ref().state.is_pending() } 591 } 592 593 /// Forcibly sets the true and cached expiration times to the given tick. 594 /// 595 /// SAFETY: The caller must ensure that the handle remains valid, the driver 596 /// lock is held, and that the timer is not in any wheel linked lists. set_expiration(&self, tick: u64)597 pub(super) unsafe fn set_expiration(&self, tick: u64) { 598 self.inner.as_ref().set_expiration(tick); 599 } 600 601 /// Attempts to mark this entry as pending. If the expiration time is after 602 /// `not_after`, however, returns an Err with the current expiration time. 603 /// 604 /// If an `Err` is returned, the `cached_when` value will be updated to this 605 /// new expiration time. 606 /// 607 /// SAFETY: The caller must ensure that the handle remains valid, the driver 608 /// lock is held, and that the timer is not in any wheel linked lists. 609 /// After returning Ok, the entry must be added to the pending list. mark_pending(&self, not_after: u64) -> Result<(), u64>610 pub(super) unsafe fn mark_pending(&self, not_after: u64) -> Result<(), u64> { 611 match self.inner.as_ref().state.mark_pending(not_after) { 612 Ok(()) => { 613 // mark this as being on the pending queue in cached_when 614 self.inner.as_ref().set_cached_when(u64::MAX); 615 Ok(()) 616 } 617 Err(tick) => { 618 self.inner.as_ref().set_cached_when(tick); 619 Err(tick) 620 } 621 } 622 } 623 624 /// Attempts to transition to a terminal state. If the state is already a 625 /// terminal state, does nothing. 626 /// 627 /// Because the entry might be dropped after the state is moved to a 628 /// terminal state, this function consumes the handle to ensure we don't 629 /// access the entry afterwards. 630 /// 631 /// Returns the last-registered waker, if any. 632 /// 633 /// SAFETY: The driver lock must be held while invoking this function, and 634 /// the entry must not be in any wheel linked lists. fire(self, completed_state: TimerResult) -> Option<Waker>635 pub(super) unsafe fn fire(self, completed_state: TimerResult) -> Option<Waker> { 636 self.inner.as_ref().state.fire(completed_state) 637 } 638 } 639 640 impl Drop for TimerEntry { drop(&mut self)641 fn drop(&mut self) { 642 unsafe { Pin::new_unchecked(self) }.as_mut().cancel() 643 } 644 } 645