use core::mem::MaybeUninit;
use core::task::Waker;
use crate::buf::PoolBuf;
pub(crate) struct After {
held: u8,
wake: MaybeUninit<Waker>,
drop_one: MaybeUninit<PoolBuf>,
more: MaybeUninit<Box<More>>,
#[cfg(ring)]
kick: MaybeUninit<std::sync::Arc<crate::rt::shard::Shared>>,
}
const WAKE: u8 = 1;
const DROP: u8 = 2;
const MORE: u8 = 4;
#[cfg(ring)]
const KICK: u8 = 8;
const STARVED: u8 = 16;
const REGISTER: u8 = 32;
#[cfg(ring)]
const SLOTS: u8 = WAKE | DROP | MORE | KICK;
#[cfg(not(ring))]
const SLOTS: u8 = WAKE | DROP | MORE;
impl Default for After {
#[inline(always)]
fn default() -> Self {
Self {
held: 0,
wake: MaybeUninit::uninit(),
drop_one: MaybeUninit::uninit(),
more: MaybeUninit::uninit(),
#[cfg(ring)]
kick: MaybeUninit::uninit(),
}
}
}
#[derive(Default)]
struct More {
wake: Vec<Waker>,
forget: Wakers,
bufs: Vec<PoolBuf>,
}
impl After {
fn more(&mut self) -> &mut More {
if self.held & MORE == 0 {
self.more.write(Box::default());
self.held |= MORE;
}
unsafe { self.more.assume_init_mut() }
}
#[inline(always)]
pub(crate) fn starved(&self) -> bool {
self.held & STARVED != 0
}
#[inline(always)]
pub(crate) fn set_starved(&mut self) {
self.held |= STARVED;
}
#[inline(always)]
pub(crate) fn must_register(&self) -> bool {
self.held & REGISTER != 0
}
#[inline(always)]
pub(crate) fn set_must_register(&mut self) {
self.held |= REGISTER;
}
#[cfg(ring)]
pub(crate) fn set_kick(&mut self, home: Option<std::sync::Arc<crate::rt::shard::Shared>>) {
drop(self.take_kick());
if let Some(home) = home {
self.kick.write(home);
self.held |= KICK;
}
}
#[cfg(ring)]
#[inline(always)]
pub(crate) fn take_kick(&mut self) -> Option<std::sync::Arc<crate::rt::shard::Shared>> {
if self.held & KICK == 0 {
return None;
}
self.held &= !KICK;
Some(unsafe { self.kick.assume_init_read() })
}
#[inline(always)]
fn take_wake(&mut self) -> Option<Waker> {
if self.held & WAKE == 0 {
return None;
}
self.held &= !WAKE;
Some(unsafe { self.wake.assume_init_read() })
}
#[inline(always)]
fn take_drop(&mut self) -> Option<PoolBuf> {
if self.held & DROP == 0 {
return None;
}
self.held &= !DROP;
Some(unsafe { self.drop_one.assume_init_read() })
}
#[inline(always)]
fn take_more(&mut self) -> Option<Box<More>> {
if self.held & MORE == 0 {
return None;
}
self.held &= !MORE;
Some(unsafe { self.more.assume_init_read() })
}
#[inline]
pub(crate) fn wake(&mut self, wakers: &mut Wakers) {
if let Some(w) = wakers.first.take() {
self.wake_one(w);
}
if !wakers.rest.is_empty() {
self.wake_rest(wakers);
}
}
#[cold]
#[inline(never)]
fn wake_rest(&mut self, wakers: &mut Wakers) {
self.more().wake.append(&mut wakers.rest);
}
pub(crate) fn forget(&mut self, wakers: &mut Wakers) {
if !wakers.is_empty() {
self.more().forget.append(wakers);
}
}
#[inline]
pub(crate) fn wake_one(&mut self, waker: Waker) {
if self.held & WAKE == 0 {
self.wake.write(waker);
self.held |= WAKE;
} else {
self.wake_more(waker);
}
}
#[cold]
#[inline(never)]
fn wake_more(&mut self, waker: Waker) {
self.more().wake.push(waker);
}
pub(crate) fn forget_one(&mut self, waker: Waker) {
self.more().forget.push(waker);
}
pub(crate) fn drop_buf(&mut self, buf: PoolBuf) {
if self.held & DROP == 0 {
self.drop_one.write(buf);
self.held |= DROP;
} else {
self.more().bufs.push(buf);
}
}
#[inline]
pub(crate) fn run(mut self) {
if self.held & SLOTS != 0 {
self.run_held();
}
core::mem::forget(self);
}
#[inline(never)]
fn run_held(&mut self) {
self.flush();
#[cfg(ring)]
drop(self.take_kick());
}
#[inline]
fn flush(&mut self) {
drop(self.take_drop());
match self.take_more() {
None => {
if let Some(w) = self.take_wake() {
w.wake();
}
}
Some(more) => self.flush_more(*more),
}
}
#[inline(never)]
fn flush_more(&mut self, more: More) {
let More { wake, forget, bufs } = more;
drop(bufs);
drop(forget);
if let Some(w) = self.take_wake() {
w.wake();
}
wake.into_iter().for_each(Waker::wake);
}
}
impl Drop for After {
fn drop(&mut self) {
if parking() {
self.park();
} else {
self.flush();
}
#[cfg(ring)]
drop(self.take_kick());
}
}
impl After {
#[inline(always)]
pub(crate) fn forget_if_nothing(self) -> Result<(), Self> {
if self.held == 0 {
core::mem::forget(self);
Ok(())
} else {
Err(self)
}
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.held & SLOTS == 0
}
#[cold]
fn park(&mut self) {
if self.is_empty() {
return;
}
let mut work = core::mem::take(self);
let parked = UNWOUND.try_with(|list| match list.try_borrow_mut() {
Ok(mut list) => {
list.push(core::mem::take(&mut work));
true
}
Err(_) => false,
});
if parked != Ok(true) {
work.flush();
#[cfg(ring)]
drop(work.take_kick());
}
}
}
#[cfg(any(ring, test))]
fn parking() -> bool {
view_live().get() && std::thread::panicking()
}
#[cfg(not(any(ring, test)))]
fn parking() -> bool {
false
}
#[cfg(any(ring, test))]
thread_local! {
static VIEW_LIVE: core::cell::Cell<bool> = const { core::cell::Cell::new(false) };
}
#[cfg(any(ring, test))]
#[inline(always)]
fn view_live() -> &'static core::cell::Cell<bool> {
unsafe { &*VIEW_LIVE.with(core::ptr::from_ref) }
}
thread_local! {
static UNWOUND: core::cell::RefCell<Vec<After>> = const { core::cell::RefCell::new(Vec::new()) };
}
#[cfg(any(ring, test))]
pub(crate) fn run_unwound() {
let Ok(work) = UNWOUND.try_with(|list| core::mem::take(&mut *list.borrow_mut())) else {
return;
};
work.into_iter().for_each(After::run);
}
#[cfg(any(ring, test))]
pub(crate) struct Unwound {
outer: bool,
}
#[cfg(any(ring, test))]
impl Unwound {
pub(crate) fn enter() -> Self {
Self {
outer: view_live().replace(true),
}
}
}
#[cfg(any(ring, test))]
impl Drop for Unwound {
fn drop(&mut self) {
view_live().set(self.outer);
if std::thread::panicking() {
run_unwound();
}
}
}
#[derive(Default)]
pub(crate) struct Wakers {
first: Option<Waker>,
rest: Vec<Waker>,
}
impl Wakers {
#[inline(always)]
pub(crate) fn register(&mut self, waker: &Waker) {
let known = self.first.as_ref().is_some_and(|w| w.will_wake(waker))
|| self.rest.iter().any(|w| w.will_wake(waker));
if known {
return;
}
self.push(waker.clone());
}
#[inline(always)]
fn push(&mut self, waker: Waker) {
if self.first.is_none() {
self.first = Some(waker);
} else {
self.push_rest(waker);
}
}
#[cold]
#[inline(never)]
fn push_rest(&mut self, waker: Waker) {
self.rest.push(waker);
}
pub(crate) fn is_empty(&self) -> bool {
self.first.is_none()
}
#[cfg(any(readiness, test))]
pub(crate) fn len(&self) -> usize {
usize::from(self.first.is_some()) + self.rest.len()
}
fn append(&mut self, other: &mut Wakers) {
if let Some(w) = other.first.take() {
self.push(w);
}
self.rest.append(&mut other.rest);
}
}