use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread::{self, Thread};
use std::time::{Duration, Instant};
#[derive(Clone)]
pub struct TaskFuture {
count: Arc<AtomicUsize>,
owner_thread: Thread,
}
impl TaskFuture {
pub(crate) fn new(task_count: usize) -> Self {
TaskFuture {
count: Arc::new(AtomicUsize::new(task_count)),
owner_thread: thread::current(),
}
}
#[must_use]
#[inline]
pub fn is_complete(&self) -> bool {
self.count.load(Ordering::Acquire) == 0
}
#[inline]
pub fn wait(&self) {
debug_assert_eq!(
self.owner_thread.id(),
thread::current().id(),
"TaskFuture::wait() must be called from the thread that created it."
);
while !self.is_complete() {
thread::park();
}
}
#[must_use]
#[inline]
pub fn wait_timeout(&self, timeout: Duration) -> bool {
debug_assert_eq!(
self.owner_thread.id(),
thread::current().id(),
"TaskFuture::wait_timeout() must be called from the thread that created it."
);
let start = Instant::now();
loop {
if self.is_complete() {
return true;
}
let elapsed = start.elapsed();
if elapsed >= timeout {
return false;
}
thread::park_timeout(timeout.saturating_sub(elapsed));
}
}
pub(crate) fn complete_many(&self, count: usize) {
if self.count.fetch_sub(count, Ordering::Release) == count {
self.owner_thread.unpark();
}
}
}