#![allow(unsafe_code)]
use core::fmt;
use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use super::internal::{Ordering, UnsafeCell};
use super::list::List;
use super::queue::{Arrivals, FIRST_BIT, Policy, QUEUED, Step, WaitQueue};
use super::waiter::{Cancel, Wait, WakeList};
const SET: usize = 1 << FIRST_BIT;
pub struct Event {
queue: WaitQueue,
waiting: UnsafeCell<List>,
}
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
impl Event {
loom_const_fn! {
pub fn new() -> Self {
Self::with_state(0)
}
}
loom_const_fn! {
pub(super) fn new_set(set: bool) -> Self {
Self::with_state(if set { SET } else { 0 })
}
}
loom_const_fn! {
fn with_state(state: usize) -> Self {
Self { queue: WaitQueue::new(state), waiting: UnsafeCell::new(List::new()) }
}
}
pub fn set(&self) {
self.transition(|state| {
if state & SET != 0 {
Step::Keep
} else if state & QUEUED != 0 {
Step::Drain(state | SET)
} else {
Step::Set(state | SET)
}
});
}
pub fn is_set(&self) -> bool {
self.queue.state.load(Ordering::Acquire) & SET != 0
}
pub fn wait(&self) -> EventWait<'_> {
EventWait {
event: self,
wait: Wait::new(),
}
}
}
impl Policy for Event {
fn queue(&self) -> &WaitQueue {
&self.queue
}
fn pass(&self, arrivals: Arrivals, woken: &mut WakeList<'_>, _wake_front: bool) -> usize {
let pool = &self.queue;
let set = self.is_set();
self.waiting.with_mut(|waiting| unsafe {
let waiting = &mut *waiting;
waiting.absorb(arrivals, pool);
waiting.tidy(&self.queue);
while set && let Some(node) = waiting.front(pool) {
waiting.pop_front();
woken.grant(node);
}
if waiting.front(pool).is_none() {
QUEUED
} else {
0
}
})
}
}
impl Drop for Event {
fn drop(&mut self) {
let pool = &self.queue;
self.waiting
.with_mut(|waiting| unsafe { (*waiting).clear(pool) });
}
}
impl Default for Event {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for Event {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Event")
.field("set", &self.is_set())
.finish()
}
}
#[must_use = "futures do nothing unless polled"]
pub struct EventWait<'a> {
event: &'a Event,
wait: Wait,
}
impl Future for EventWait<'_> {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
let this = self.get_mut();
let event = this.event;
if this.wait.is_queued() {
return this.wait.poll(&event.queue, Some(cx.waker())).map(drop);
}
if event.is_set() {
return Poll::Ready(());
}
event.enqueue(&mut this.wait, 0, cx.waker());
this.wait.poll(&event.queue, None).map(drop)
}
}
impl Drop for EventWait<'_> {
fn drop(&mut self) {
if let Cancel::Withdrawn(_) = self.wait.cancel(&self.event.queue) {
self.event.withdrawn(false);
}
}
}
impl fmt::Debug for EventWait<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EventWait").finish_non_exhaustive()
}
}
#[cfg(all(test, not(loom)))]
mod tests {
use super::*;
use crate::sync::test_support::{Polled, block_on};
use std::sync::Arc;
#[test]
fn setting_wakes_every_waiter_and_later_waits_pass() {
let event = Event::new();
let mut waiters: Vec<_> = (0..3).map(|_| Polled::new(event.wait())).collect();
for waiter in &mut waiters {
waiter.pending();
}
drop(waiters.pop());
event.set();
event.set();
for waiter in &mut waiters {
assert_eq!(waiter.wakes(), 1);
waiter.ready();
}
Polled::new(event.wait()).ready();
}
#[test]
fn a_set_from_another_thread_is_seen() {
let event = Arc::new(Event::new());
let setter = Arc::clone(&event);
let thread = std::thread::spawn(move || setter.set());
block_on(event.wait());
thread.join().expect("setter");
assert!(event.is_set());
}
}