use core::future::Future;
use core::pin::Pin;
use core::task::{Context, Poll};
use std::sync::Arc;
use super::context;
use super::handoff::home::Home;
use super::shard::Shared;
use super::task::{Runnable, Schedule, ScheduleInfo};
use crate::sync::internal::Ordering;
pub(crate) struct Sched {
pub(crate) shard: Arc<Shared>,
pub(crate) home: Option<Arc<Home>>,
pub(crate) hooks: Option<Arc<super::tuning::TaskHooks>>,
}
unsafe impl Schedule for Sched {
fn schedule(&self, runnable: Runnable, info: ScheduleInfo) {
if let Some(home) = &self.home {
let remote = context::current(|current| match current {
Some(shard) if context::is_home(home) || shard.owns_home(home) => {
shard.push_local(runnable, info);
None
}
_ => Some(runnable),
});
if let Some(runnable) = remote {
let keep = runnable.waker();
home.push(runnable);
drop(keep);
}
return;
}
let remote = context::current(|current| match current {
Some(shard) if shard.is(&self.shard) => {
shard.push_local(runnable, info);
None
}
_ => Some(runnable),
});
if let Some(runnable) = remote {
let keep = runnable.waker();
self.shard.push_remote(runnable);
drop(keep);
}
}
fn before_poll(&self, id: super::task::Id) {
if let Some(hooks) = &self.hooks {
super::tuning::call(hooks.before_poll.as_ref(), id);
}
}
fn after_poll(&self, id: super::task::Id) {
if let Some(hooks) = &self.hooks {
super::tuning::call(hooks.after_poll.as_ref(), id);
}
}
fn terminated(&self, id: super::task::Id) {
if let Some(hooks) = &self.hooks {
super::tuning::call(hooks.terminate.as_ref(), id);
}
}
fn panicked(&self, _id: super::task::Id) {
let runtime = self
.hooks
.as_ref()
.and_then(|hooks| hooks.shutdown.as_ref());
if let Some(runtime) = runtime.and_then(std::sync::Weak::upgrade) {
super::task::abort_on_panic(|| runtime.shut_down_on_panic());
}
}
}
pub(crate) struct Counted<F> {
future: F,
shard: *const Shared,
}
unsafe impl<F: Send> Send for Counted<F> {}
impl<F> Counted<F> {
pub(crate) fn new(future: F, shard: &Shared) -> Self {
shard.load.fetch_add(1, Ordering::Relaxed);
Self { future, shard }
}
}
impl<F: Future> Future for Counted<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
unsafe { self.map_unchecked_mut(|c| &mut c.future) }.poll(cx)
}
}
impl<F> Drop for Counted<F> {
fn drop(&mut self) {
let shard = unsafe { &*self.shard };
if shard.load.fetch_sub(1, Ordering::Release) == 1 {
shard.last_task_done();
}
}
}
pub(crate) struct AtHome<F> {
future: F,
home: *const Home,
}
impl<F> AtHome<F> {
pub(crate) fn new(future: F, home: &Home) -> Self {
home.began();
Self { future, home }
}
}
impl<F: Future> Future for AtHome<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
unsafe { self.map_unchecked_mut(|c| &mut c.future) }.poll(cx)
}
}
impl<F> Drop for AtHome<F> {
fn drop(&mut self) {
unsafe { &*self.home }.ended();
}
}