use core::cell::{Cell, RefCell};
use core::future::Future;
use core::task::{Poll, Waker};
use std::collections::VecDeque;
use std::io;
use std::sync::Arc;
use std::time::{Duration, Instant};
use super::inbox::{Inbox, Pop};
use counted::Counted;
use super::backend::Backend;
use super::counters::{self, Counters};
use super::handshake::ParkState;
#[cfg(readiness)]
use super::park::Registrar;
use super::park::{Notifier, Poller};
use super::sources::Sources;
use super::task::{Runnable, ScheduleInfo};
use crate::buf::Pool;
use crate::io::Source;
use crate::sync::atomic_waker::AtomicWaker;
use crate::sync::internal::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
use crate::time::TimerOp;
use crate::time::wheel::Wheel;
use spin::Spin;
mod children;
mod going;
pub(crate) mod locals;
#[cfg(port)]
mod port;
mod run;
pub(crate) mod signal;
mod spin;
mod stats;
mod timers;
pub(crate) use children::{watch_exit, watch_exit_elsewhere};
pub(crate) use run::Worked;
pub(crate) mod counted;
#[cfg(ring)]
pub(crate) mod recv;
#[cfg(ring)]
pub(crate) mod ring;
pub(crate) const LIFO_MAX: u32 = 3;
pub(crate) const INBOX_INTERVAL: u32 = 31;
pub(crate) const DRIVER_INTERVAL: u32 = 61;
pub(crate) const PUBLISH_INTERVAL: u32 = 8;
pub(crate) struct Shared {
inbox: Inbox,
park: ParkState,
notifier: Notifier,
pub(crate) load: AtomicUsize,
stopped: AtomicBool,
draining: AtomicBool,
stop_waker: AtomicWaker,
timer_ops: Counted<TimerOp>,
#[cfg(readiness)]
registrar: Option<Registrar>,
#[cfg(port)]
port: Arc<super::park::iocp::Port>,
io_ops: Counted<IoOp>,
io_closed: AtomicBool,
pub(crate) counters: Counters,
runtime: std::sync::OnceLock<std::sync::Weak<super::runtime::Inner>>,
runtime_addr: AtomicUsize,
writes: AtomicUsize,
released: AtomicBool,
timer_at: AtomicU64,
parks: AtomicU64,
}
pub(crate) enum IoOp {
Register(Arc<Source>),
Release(u64),
#[cfg(ring)]
RingAttach(u64, crate::io::source::requests::Lease),
#[cfg(ring)]
RingDetach(
u32,
[Option<u64>; 2],
Option<crate::io::source::requests::Lease>,
),
#[cfg(ring)]
RingKick(Arc<Source>),
#[cfg(ring)]
RingCancel(u64),
#[cfg(not(ring))]
Touch(Arc<Source>),
Watch(Arc<crate::process::exit::Exit>),
}
impl IoOp {
fn gone(self) {
match self {
IoOp::Register(source) => source.registration_orphaned(),
IoOp::Watch(exit) => {
let orphan = Arc::strong_count(&exit) == 1;
exit.unwatched(orphan);
}
other => drop(other),
}
}
}
impl Shared {
pub(crate) fn push_remote(&self, runnable: Runnable) {
self.inbox.push(runnable);
if self.stopped.load(Ordering::SeqCst) {
self.drop_stopped(false);
return;
}
self.park.wake(|| self.notifier.notify());
}
pub(crate) fn notify(&self) {
self.notifier.notify();
}
pub(crate) fn unpark(&self) {
self.park.wake(|| self.notifier.notify());
}
pub(crate) fn post_timer(&self, op: TimerOp) {
let wake = op.needs_wake();
self.timer_ops.push(op);
crate::sync::internal::fence(Ordering::SeqCst);
if self.stopped.load(Ordering::SeqCst) {
self.drain_timer_ops();
return;
}
if wake {
self.unpark();
}
}
pub(crate) fn drain_timer_ops(&self) {
crate::sync::internal::fence(Ordering::SeqCst);
self.timer_ops.take_all(TimerOp::orphan);
}
#[cfg(readiness)]
pub(crate) fn registrar(&self) -> Option<&Registrar> {
self.registrar.as_ref()
}
#[cfg(port)]
pub(crate) fn port(&self) -> &Arc<super::park::iocp::Port> {
&self.port
}
#[cfg(ring)]
pub(crate) fn is_ring(&self) -> bool {
self.registrar.is_none()
}
#[cfg(test)]
pub(crate) fn state_line(&self) -> String {
format!(
"parked {}, inbox {}, timer ops {}, io ops {}, load {}, stopped {}, draining {}",
self.park.is_parked(),
if self.inbox.is_empty() {
"empty"
} else {
"not empty"
},
self.timer_ops.len(),
self.io_ops.len(),
self.load.load(Ordering::SeqCst),
self.stopped.load(Ordering::SeqCst),
self.draining.load(Ordering::SeqCst),
)
}
pub(crate) fn post_io(&self, op: IoOp) {
self.io_ops.push(op);
crate::sync::internal::fence(Ordering::SeqCst);
if self.io_closed.load(Ordering::SeqCst) {
self.drain_io_ops();
return;
}
self.unpark();
}
pub(crate) fn close_io(&self) {
self.io_closed.store(true, Ordering::SeqCst);
self.drain_io_ops();
}
fn drain_io_ops(&self) {
crate::sync::internal::fence(Ordering::SeqCst);
self.io_ops.take_all(IoOp::gone);
}
pub(crate) fn release_source(self: &Arc<Self>, token: u64) {
let done = super::context::current(|current| {
current.is_some_and(|shard| shard.is(self) && shard.try_release(token))
});
if !done {
self.post_io(IoOp::Release(token));
}
}
pub(crate) fn is_parked(&self) -> bool {
self.park.is_parked()
}
pub(crate) fn is_stopped(&self) -> bool {
self.stopped.load(Ordering::Acquire)
}
pub(crate) fn set_runtime(&self, runtime: std::sync::Weak<super::runtime::Inner>) {
let addr = runtime.as_ptr() as usize;
if self.runtime.set(runtime).is_ok() {
self.runtime_addr.store(addr, Ordering::Release);
}
}
#[inline]
pub(crate) fn enter_runtime(&self) -> Option<super::context::RuntimeSet> {
let addr = self.runtime_addr.load(Ordering::Acquire);
if addr == 0 || super::context::runtime_is(addr as *const super::runtime::Inner) {
return None;
}
Self::set_runtime_here(self.runtime.get()?)
}
#[inline(never)]
fn set_runtime_here(
runtime: &std::sync::Weak<super::runtime::Inner>,
) -> Option<super::context::RuntimeSet> {
runtime
.upgrade()
.and_then(|inner| super::context::try_set_runtime(&inner))
}
pub(crate) fn write_began(&self) {
self.writes.fetch_add(1, Ordering::SeqCst);
}
pub(crate) fn write_ended(&self) {
if self.writes.fetch_sub(1, Ordering::SeqCst) == 1 && self.stopped.load(Ordering::SeqCst) {
self.nudge_runtime();
}
}
pub(crate) fn settled(&self) -> bool {
self.writes.load(Ordering::SeqCst) == 0
&& (!self.released.load(Ordering::SeqCst) || self.inbox.is_idle())
}
pub(crate) fn release_inbox(&self) {
self.drop_stopped(true);
self.released.store(true, Ordering::SeqCst);
}
fn nudge_runtime(&self) {
if let Some(inner) = self.runtime.get().and_then(std::sync::Weak::upgrade) {
inner.lingering().nudge();
}
}
pub(crate) fn stop(&self) {
self.draining.store(true, Ordering::SeqCst);
self.stopped.store(true, Ordering::SeqCst);
self.stop_waker.wake();
self.unpark();
}
#[inline]
pub(crate) fn takes_tasks(&self) -> bool {
!self.draining.load(Ordering::Relaxed)
}
pub(crate) fn drain(&self) {
self.draining.store(true, Ordering::Relaxed);
crate::sync::internal::fence(Ordering::SeqCst);
if self.load.load(Ordering::Relaxed) == 0 {
self.stop_waker.wake();
}
self.unpark();
}
pub(crate) fn last_task_done(&self) {
crate::sync::internal::fence(Ordering::SeqCst);
if self.draining.load(Ordering::Relaxed) {
self.stop_waker.wake();
}
}
fn may_exit(&self) -> bool {
if self.is_stopped() {
return true;
}
if !self.draining.load(Ordering::Acquire) {
return false;
}
crate::sync::internal::fence(Ordering::SeqCst);
self.load.load(Ordering::Acquire) == 0
}
pub(crate) fn stopped(&self) -> impl Future<Output = ()> + '_ {
core::future::poll_fn(move |cx| {
if self.may_exit() {
return Poll::Ready(());
}
self.stop_waker.register(cx.waker());
if self.may_exit() {
Poll::Ready(())
} else {
Poll::Pending
}
})
}
pub(crate) fn stats(&self) -> crate::stats::ShardStats {
self.counters.read(self.load.load(Ordering::Relaxed))
}
pub(crate) fn idle(&self) -> bool {
self.park.is_parked() && !self.has_remote_work()
}
pub(crate) fn timer_at(&self) -> u64 {
self.timer_at.load(Ordering::SeqCst)
}
pub(crate) fn parks(&self) -> u64 {
self.parks.load(Ordering::SeqCst)
}
pub(crate) fn drop_stopped(&self, mut holding: bool) {
loop {
if !holding && !self.inbox.try_take() {
return;
}
unsafe {
self.inbox.drain(drop);
self.inbox.release();
}
holding = false;
if self.inbox.is_empty() {
break;
}
}
self.nudge_runtime();
}
fn has_remote_work(&self) -> bool {
!self.inbox.is_empty() || self.timer_ops.holds_any() || self.io_ops.holds_any()
}
}
#[derive(Clone, Copy, Debug)]
pub(crate) struct Limits {
pub(crate) max_nesting: usize,
pub(crate) buffer_cap: usize,
pub(crate) backend: Backend,
}
fn reserve_group(pool: &Pool, backend: Backend) -> io::Result<usize> {
#[cfg(ring)]
if let Backend::Ring(cfg) | Backend::RingOrPoll(cfg) = backend {
let bytes = recv::reservation(cfg.recv_buffers, cfg.recv_buffer_size);
if !pool.reserve(bytes) {
return Err(recv::too_large(
cfg.recv_buffers,
cfg.recv_buffer_size,
bytes,
pool.cap(),
));
}
return Ok(bytes);
}
let _ = (pool, backend);
Ok(0)
}
#[cfg(test)]
pub(crate) fn least_buffer_cap() -> usize {
let group = match super::backend::chosen() {
#[cfg(ring)]
Ok(Backend::Ring(cfg) | Backend::RingOrPoll(cfg)) => {
recv::reservation(cfg.recv_buffers, cfg.recv_buffer_size)
}
_ => 0,
};
group + crate::buf::CLASSES[0]
}
#[cfg_attr(
ring,
expect(clippy::large_enum_variant, reason = "one per shard, built with it")
)]
enum Driver {
Poll(RefCell<Poller>),
#[cfg(ring)]
Ring(ring::ShardRing),
#[cfg(ring)]
Gone,
}
pub(crate) struct Shard {
pub(crate) shared: Arc<Shared>,
queue: RefCell<VecDeque<Runnable>>,
lifo: Cell<Option<Runnable>>,
lifo_streak: Cell<u32>,
until_inbox: Cell<u32>,
drive_left: Cell<u32>,
drive_at: Cell<u32>,
last_drive: Cell<u64>,
polls: Cell<u64>,
sleeps: Cell<u64>,
slept: Cell<Duration>,
remote_wakes: Cell<u64>,
looks: Cell<u32>,
spin: Spin,
owner: Cell<Option<(u64, usize)>>,
monitor: Option<Arc<super::handoff::Monitor>>,
home: core::cell::OnceCell<Arc<super::handoff::home::Home>>,
limits: Limits,
tuning: super::tuning::Tuning,
driver: Driver,
wheel: RefCell<Wheel>,
precise: RefCell<Wheel>,
epoch: Instant,
fired: RefCell<Vec<Waker>>,
signal: Cell<Option<Arc<signal::Signal>>>,
sources: RefCell<Sources>,
children: RefCell<children::Children>,
pool: Pool,
locals: locals::Locals,
#[cfg(port)]
keeper: RefCell<Option<Arc<port::Keeper>>>,
}
impl Shard {
pub(crate) fn new(limits: Limits) -> io::Result<Self> {
Self::made(limits, None)
}
pub(crate) fn worker(
limits: Limits,
tuning: super::tuning::Tuning,
runtime: u64,
index: usize,
monitor: Option<Arc<super::handoff::Monitor>>,
) -> io::Result<Self> {
let mut shard = Self::made(limits, Some((runtime, index)))?;
#[cfg(feature = "io-stats")]
if tuning.count_io {
shard.shared.counters.count_io();
}
if tuning.record_latencies {
shard.shared.counters.record_latencies();
#[cfg(all(completion, feature = "io-stats"))]
shard.time_io();
}
shard.until_inbox.set(tuning.inbox_interval);
shard.count_drive_from(0, tuning.driver_interval);
#[cfg(ring)]
if let Some(ring) = shard.ring() {
ring.set_zero_copy_min(tuning.zero_copy_min);
}
shard.tuning = tuning;
shard.monitor = monitor;
Ok(shard)
}
pub(crate) fn pool(&self) -> &Pool {
&self.pool
}
pub(crate) fn own_home(&self) -> Arc<super::handoff::home::Home> {
Arc::clone(
self.home.get_or_init(|| {
Arc::new(super::handoff::home::Home::new(Arc::clone(&self.shared)))
}),
)
}
pub(crate) fn owns_home(&self, home: &super::handoff::home::Home) -> bool {
self.home
.get()
.is_some_and(|own| core::ptr::eq(Arc::as_ptr(own), home))
}
fn parked_ended(&self) {
if let Some(monitor) = &self.monitor {
monitor.worker_woke();
}
}
fn made(limits: Limits, owner: Option<(u64, usize)>) -> io::Result<Self> {
#[cfg(readiness)]
let poller = || -> io::Result<_> {
let poller = Poller::new()?;
let (notifier, registrar) = (poller.notifier(), poller.registrar());
Ok((
Driver::Poll(RefCell::new(poller)),
notifier,
Some(registrar),
))
};
#[cfg(port)]
let poller = || -> io::Result<_> {
let poller = Poller::new()?;
let (notifier, port) = (poller.notifier(), Arc::clone(poller.port()));
Ok((Driver::Poll(RefCell::new(poller)), notifier, port))
};
let pool = Pool::new(limits.buffer_cap);
let reserved = reserve_group(&pool, limits.backend)?;
let (driver, notifier, kernel) = match limits.backend {
Backend::Poll => poller()?,
#[cfg(ring)]
Backend::Ring(cfg) | Backend::RingOrPoll(cfg) => {
match ring::ShardRing::for_shard(cfg) {
Ok(ring) => {
let notifier = ring.notifier();
(Driver::Ring(ring), notifier, None)
}
Err(err)
if matches!(limits.backend, Backend::RingOrPoll(_))
&& (err.raw_os_error() == Some(libc::ENOMEM)
|| err.kind() == io::ErrorKind::Unsupported) =>
{
poller()?
}
Err(err) => return Err(err),
}
}
};
let made = match &driver {
#[cfg(ring)]
Driver::Ring(ring) => ring.recv_reservation(),
#[cfg(ring)]
Driver::Gone => 0,
Driver::Poll(_) => 0,
};
pool.unreserve(reserved.saturating_sub(made));
let shared = Arc::new(Shared {
inbox: Inbox::new(),
park: ParkState::new(),
notifier,
load: AtomicUsize::new(0),
stopped: AtomicBool::new(false),
draining: AtomicBool::new(false),
stop_waker: AtomicWaker::new(),
timer_ops: Counted::new(),
#[cfg(readiness)]
registrar: kernel,
#[cfg(port)]
port: kernel,
io_ops: Counted::new(),
io_closed: AtomicBool::new(false),
counters: Counters::new(driver.backend(), pool.cap(), owner),
runtime: std::sync::OnceLock::new(),
runtime_addr: AtomicUsize::new(0),
writes: AtomicUsize::new(0),
released: AtomicBool::new(false),
timer_at: AtomicU64::new(u64::MAX),
parks: AtomicU64::new(0),
});
counters::register(&shared);
Ok(Self {
shared,
queue: RefCell::new(VecDeque::new()),
lifo: Cell::new(None),
lifo_streak: Cell::new(0),
until_inbox: Cell::new(super::tuning::Tuning::default().inbox_interval),
drive_left: Cell::new(1),
drive_at: Cell::new(1),
last_drive: Cell::new(super::quartz::Quartz::now()),
polls: Cell::new(0),
sleeps: Cell::new(0),
slept: Cell::new(Duration::ZERO),
remote_wakes: Cell::new(0),
looks: Cell::new(0),
spin: Spin::new(),
owner: Cell::new(owner),
monitor: None,
home: core::cell::OnceCell::new(),
limits,
tuning: super::tuning::Tuning::default(),
driver,
wheel: RefCell::new(Wheel::new()),
precise: RefCell::new(Wheel::new()),
epoch: crate::time::clock::origin(),
fired: RefCell::new(Vec::new()),
signal: Cell::new(None),
sources: RefCell::new(Sources::default()),
children: RefCell::new(children::Children::default()),
pool,
locals: locals::Locals::default(),
#[cfg(port)]
keeper: RefCell::new(None),
})
}
pub(crate) fn locals(&self) -> Option<&locals::Locals> {
self.owner.get().is_some().then_some(&self.locals)
}
pub(crate) fn register_source(&self, source: &Arc<Source>) -> io::Result<()> {
#[cfg(ring)]
source.registers_with(self.ring().is_some_and(ring::ShardRing::datagrams_ahead));
let token = match self.sources.borrow_mut().insert(Arc::clone(source)) {
Ok(token) => token,
Err(err) => {
self.shared.counters.refused_registration();
source.registration_abandoned();
return Err(err);
}
};
match source.attach(&self.shared, token) {
Some(Err(err)) => Err(err),
_ => Ok(()),
}
}
fn try_release(&self, token: u64) -> bool {
let Ok(mut sources) = self.sources.try_borrow_mut() else {
return false;
};
let gone = sources.remove(token);
drop(sources);
drop(gone);
true
}
fn apply_io_ops(&self) {
self.shared.io_ops.take_all(|op| {
match op {
IoOp::Register(source) => match self.register_source(&source) {
Ok(()) => {}
Err(err) if crate::io::source::requests::is_stopped_shard(&err) => {
source.look_again();
}
Err(err) => source.registration_failed(&err),
},
IoOp::Release(token) => {
let gone = self.sources.borrow_mut().remove(token);
drop(gone);
}
IoOp::Watch(exit) => self.watch(exit),
#[cfg(ring)]
IoOp::RingAttach(token, lease) => {
let source = self.sources.borrow().get(token).cloned();
if let (Some(ring), Some(source)) = (self.ring(), source) {
source.ring_attached(ring, &self.shared, &lease, token);
}
drop(lease);
}
#[cfg(ring)]
IoOp::RingDetach(slot, out, lease) => {
if let Some(ring) = self.ring() {
ring.detach(slot, out, lease);
}
}
#[cfg(ring)]
IoOp::RingKick(source) => source.ring_kick(self),
#[cfg(not(ring))]
IoOp::Touch(source) => source.touch(self),
#[cfg(ring)]
IoOp::RingCancel(user_data) => {
if let Some(ring) = self.ring() {
ring.cancel(user_data);
}
}
}
});
}
pub(crate) fn shared_addr(&self) -> usize {
Arc::as_ptr(&self.shared) as usize
}
pub(crate) fn is(&self, shared: &Arc<Shared>) -> bool {
Arc::ptr_eq(&self.shared, shared)
}
pub(crate) fn worker_index(&self, runtime: u64) -> Option<usize> {
self.owner
.get()
.and_then(|(owner, index)| (owner == runtime).then_some(index))
}
pub(crate) fn push_local(&self, runnable: Runnable, info: ScheduleInfo) {
self.push_local_from(runnable, info, super::context::in_task());
}
#[inline(always)]
pub(crate) fn push_local_from(&self, runnable: Runnable, info: ScheduleInfo, in_task: bool) {
if self.tuning.lifo && !info.woken_while_running && in_task {
if let Some(previous) = self.lifo.replace(Some(runnable)) {
self.queue.borrow_mut().push_back(previous);
}
} else {
self.queue.borrow_mut().push_back(runnable);
}
}
#[inline(always)]
fn next(&self) -> Option<Runnable> {
let left = self.until_inbox.get().wrapping_sub(1);
if left == 0 {
self.until_inbox.set(self.tuning.inbox_interval);
if let Some(r) = self.pop_inbox() {
return Some(r);
}
} else {
self.until_inbox.set(left);
}
if let Some(r) = self.lifo.take() {
if self.lifo_streak.get() < LIFO_MAX {
self.lifo_streak.set(self.lifo_streak.get() + 1);
return Some(r);
}
let mut queue = self.queue.borrow_mut();
if queue.is_empty() {
self.lifo_streak.set(0);
return Some(r);
}
queue.push_back(r);
}
self.lifo_streak.set(0);
let local = self.queue.borrow_mut().pop_front();
local.or_else(|| self.pop_inbox())
}
#[inline]
fn pop_inbox(&self) -> Option<Runnable> {
let popped = match unsafe { self.shared.inbox.pop() } {
Pop::Item(runnable) => Some(runnable),
Pop::Empty | Pop::Busy => super::context::pop_home().or_else(|| {
self.home.get().and_then(|home| unsafe { home.pop() })
}),
};
let runnable = popped?;
self.remote_wakes.set(self.remote_wakes.get() + 1);
Some(runnable)
}
#[inline]
fn has_remote_work(&self) -> bool {
self.has_remote_tasks() || self.has_posted_ops()
}
#[inline]
fn has_remote_tasks(&self) -> bool {
let drained = unsafe { self.shared.inbox.is_drained() }
&& super::context::home_is_drained()
&& self.home.get().is_none_or(|home| unsafe { home.is_drained() });
!drained
}
#[inline]
fn has_posted_ops(&self) -> bool {
!self.shared.timer_ops.is_empty() || !self.shared.io_ops.is_empty()
}
fn queued(&self) -> usize {
let lifo = self.lifo.take();
let n = self.queue.borrow().len() + usize::from(lifo.is_some());
self.lifo.set(lifo);
n
}
fn has_local_work(&self) -> bool {
unsafe { (*self.lifo.as_ptr()).is_some() || !self.queue.borrow().is_empty() }
}
fn drive(&self, wait: Option<Duration>) -> io::Result<()> {
self.last_drive.set(super::quartz::Quartz::now());
let looks = self.looks.get().wrapping_add(1);
self.looks.set(looks);
let publish = wait != Some(Duration::ZERO) || looks.is_multiple_of(PUBLISH_INTERVAL);
if !self.shared.io_ops.is_empty() {
self.apply_io_ops();
}
self.fire_timers();
let wait = if self.has_local_work() {
Some(Duration::ZERO)
} else {
wait
};
let timeout = match (wait, self.timer_wait(wait.is_none())) {
(Some(w), Some(t)) => Some(w.min(t)),
(w, t) => w.or(t),
};
if publish {
self.publish();
}
self.poll_io(self.tuning.max_io_events, timeout)?;
self.fire_timers();
Ok(())
}
fn poll_io(&self, max: usize, timeout: Option<Duration>) -> io::Result<usize> {
match &self.driver {
#[cfg(readiness)]
Driver::Poll(poller) => {
let sources = self.sources.borrow();
let mut events = 0;
poller
.borrow_mut()
.wait_at_most(max, timeout, |token, readiness| {
events += 1;
if token & crate::rt::sources::CHILD != 0 {
self.exit_came(token);
} else if let Some(source) = sources.get(token) {
source.on_event(token, readiness, self);
}
})?;
Ok(events)
}
#[cfg(port)]
Driver::Poll(poller) => {
let mut events = 0;
poller.borrow_mut().wait_at_most(max, timeout, |entry| {
events += 1;
if entry.lpCompletionKey == crate::rt::park::iocp::EXIT {
self.exit_came(entry.lpOverlapped as usize as u64);
return;
}
unsafe { crate::io::source::port::complete(entry, Some(self)) };
})?;
Ok(events)
}
#[cfg(ring)]
Driver::Ring(ring) => ring.wait(Some(self), timeout).map(|(handled, _)| handled),
#[cfg(ring)]
Driver::Gone => Ok(0),
}
}
pub(crate) fn io_backend(&self) -> crate::IoBackend {
self.driver.backend()
}
fn work_may_come_soon(&self) -> bool {
#[cfg(ring)]
return self
.ring()
.is_some_and(ring::ShardRing::expects_completions);
#[cfg(not(ring))]
false
}
fn blocking_out(&self) -> bool {
self.tuning
.blocking
.as_ref()
.is_some_and(|jobs| jobs.load(Ordering::Relaxed) > 0)
}
#[cfg(ring)]
pub(crate) fn ring(&self) -> Option<&ring::ShardRing> {
match &self.driver {
Driver::Ring(ring) => Some(ring),
Driver::Poll(_) | Driver::Gone => None,
}
}
#[expect(
clippy::panic,
reason = "a failure of the poller itself cannot be handed to any task: it ends the shard loudly"
)]
fn io_ready_now(&self) -> bool {
match self.poll_io(usize::MAX, Some(Duration::ZERO)) {
Ok(events) => events > 0,
Err(err) => panic!("the shard's poller failed: {err}"),
}
}
}
#[cfg(all(test, not(loom)))]
mod tests;
#[cfg(all(test, not(loom)))]
mod tests_pool;
#[cfg(all(test, not(loom)))]
mod tests_signal;