use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::Ordering;
use std::task::{Context, Poll};
use super::future_task::{JoinState, TaskShared};
use super::state::{ThreadShared, WorkerCompletion};
#[cfg(debug_assertions)]
use crate::trace_targets;
#[derive(Debug)]
#[non_exhaustive]
pub enum QueueError {
Closed,
Full,
}
impl std::fmt::Display for QueueError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Closed => f.write_str("target runtime thread is closed"),
Self::Full => f.write_str("target runtime thread remote queue is full"),
}
}
}
impl std::error::Error for QueueError {}
#[derive(Clone)]
pub struct ThreadHandle {
pub(crate) shared: Arc<ThreadShared>,
}
pub struct WorkerHandle {
pub(crate) thread: ThreadHandle,
pub(crate) completion: Arc<WorkerCompletion>,
}
#[derive(Clone)]
pub struct TimeoutHandle {
pub(crate) id: usize,
pub(crate) generation: u64,
}
impl TimeoutHandle {
pub fn cancel(&self) {
super::scheduler::cancel_timeout(self);
}
}
#[derive(Clone)]
pub struct IntervalHandle {
pub(crate) id: usize,
pub(crate) generation: u64,
}
impl IntervalHandle {
pub fn cancel(&self) {
super::scheduler::cancel_interval(self);
}
}
pub struct JoinHandle<T> {
pub(crate) state: Rc<JoinState<T>>,
}
impl<T> JoinHandle<T> {
pub fn abort(&self) {
self.state.shared.abort();
}
pub fn is_finished(&self) -> bool {
self.state.shared.is_finished()
}
pub fn abort_handle(&self) -> AbortHandle {
AbortHandle {
shared: Rc::clone(&self.state.shared),
}
}
}
impl<T> Future for JoinHandle<T> {
type Output = Result<T, crate::task::JoinError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.state.poll(cx)
}
}
#[derive(Clone)]
pub struct AbortHandle {
shared: Rc<TaskShared>,
}
impl AbortHandle {
pub fn abort(&self) {
self.shared.abort();
}
pub fn is_finished(&self) -> bool {
self.shared.is_finished()
}
}
pub struct YieldNow {
pub(crate) yielded: bool,
}
impl Future for YieldNow {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.yielded {
Poll::Ready(())
} else {
self.yielded = true;
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
impl ThreadHandle {
pub fn queue_macrotask<F>(&self, task: F) -> Result<(), QueueError>
where
F: FnOnce() + Send + 'static,
{
let result = self.shared.enqueue_macro(Box::new(task));
#[cfg(debug_assertions)]
tracing::trace!(
target: trace_targets::SCHEDULER,
event = "queue_remote_task",
queue = "remote_macro",
queued = result.is_ok(),
"queueing remote macrotask"
);
result
}
pub(crate) fn queue_internal_wake<F>(&self, task: F) -> Result<(), QueueError>
where
F: FnOnce() + Send + 'static,
{
self.shared.enqueue_internal_wake(Box::new(task))
}
pub fn is_closed(&self) -> bool {
self.shared.closed.load(Ordering::Acquire)
}
pub fn is_current(&self) -> bool {
super::state::try_with_installed_thread(|state| {
state
.map(|s| Arc::ptr_eq(&self.shared, &s.shared))
.unwrap_or(false)
})
}
#[allow(dead_code)]
pub(crate) fn begin_async_operation(&self) {
self.shared.pending_ops.fetch_add(1, Ordering::AcqRel);
}
#[allow(dead_code)]
pub(crate) fn finish_async_operation(&self) {
let previous = self.shared.pending_ops.fetch_sub(1, Ordering::AcqRel);
debug_assert!(previous > 0, "async operation count underflow");
self.shared.notify();
}
}
impl WorkerHandle {
pub fn queue_macrotask<F>(&self, task: F) -> Result<(), QueueError>
where
F: FnOnce() + Send + 'static,
{
self.thread.queue_macrotask(task)
}
pub fn is_finished(&self) -> bool {
self.completion.finished.load(Ordering::Acquire)
}
pub fn thread(&self) -> ThreadHandle {
self.thread.clone()
}
}