killswitch 0.4.2

Killswitch used to broadcast a shutdown request.
Documentation
//! The killswitch trigger half implementation

use std::{
  future::Future,
  pin::Pin,
  sync::atomic::Ordering,
  sync::Arc,
  task::{Context, Poll}
};

use super::Shared;


/// The kill trigger is used to signal that tasks should self-terminate.
///
/// It's possible to `.await` `KillTrig` objects to wait for all associated
/// [`KillWait`](super::KillWait) objects have been dropped.  It is important
/// that the task calling `await`ing the `KillTrig` does not own an associated
/// `KillWait` since this would cause a deadlock.
pub struct KillTrig(pub(super) Arc<Shared>);

impl KillTrig {
  /// Signal all associated [`KillWait`](crate::pair::KillWait) objects that
  /// their tasks should terminate.
  pub fn trigger(&self) {
    // Mark killswitch as "set".
    self.0.triggered.store(true, Ordering::SeqCst);

    // Tell all waiting tasks to wake up [and check the kill switch].
    let mut state = self.0.state.lock();
    for (_, waker) in state.waiting.drain() {
      waker.wake();
    }
  }
}

impl Future for KillTrig {
  type Output = ();
  fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
    let mut state = self.0.state.lock();

    // It's important that this is done within the lock
    if Arc::<super::Shared>::strong_count(&self.0) == 1 {
      Poll::Ready(())
    } else {
      state.waker = Some(ctx.waker().clone());
      Poll::Pending
    }
  }
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :