use std::{marker, mem, ptr};
use dope_core::driver::{self, schedule::ready};
pub(in crate::link::egress::load::credit::wait) use nodes::{NodeView, Nodes};
use o3::alloc;
use crate::link::egress::{
create,
load::credit::{
self,
wait::{store::bound::Bound, tree},
},
metadata,
};
mod bound;
mod nodes;
#[derive(Clone, Copy)]
pub(super) struct Waiting<'d> {
pub(in crate::link::egress::load::credit::wait) key: ready::Retained<'d>,
pub(in crate::link::egress::load::credit::wait) amount: credit::Queued,
pub(in crate::link::egress::load::credit::wait) bypasses: usize,
}
struct Granted<'p, 'd> {
key: ready::Retained<'d>,
grant: credit::Grant<'p>,
}
enum Kind {
Idle,
Waiting,
Granted,
}
union Payload<'p, 'd> {
idle: (),
waiting: mem::ManuallyDrop<Waiting<'d>>,
granted: mem::ManuallyDrop<Granted<'p, 'd>>,
}
struct Record<'p, 'd> {
kind: Kind,
payload: Payload<'p, 'd>,
}
impl Drop for Record<'_, '_> {
fn drop(&mut self) {
if let Kind::Granted = self.kind {
let granted = unsafe { mem::ManuallyDrop::take(&mut self.payload.granted) };
granted.grant.release();
}
}
}
pub(super) enum State<'a, 'p, 'd> {
Idle(Idle<'a, 'p, 'd>),
Waiting(Queued<'a, 'p, 'd>),
Granted(Ready<'a, 'p, 'd>),
}
pub(super) struct Idle<'a, 'p, 'd>(&'a mut Record<'p, 'd>);
pub(super) struct Queued<'a, 'p, 'd> {
record: &'a mut Record<'p, 'd>,
index: tree::Index,
}
pub(super) struct Ready<'a, 'p, 'd>(&'a mut Record<'p, 'd>);
#[must_use]
pub(in crate::link::egress::load::credit) struct Selected<'a, 'pool, 'p, 'd> {
record: &'a mut Record<'p, 'd>,
scope: &'pool credit::Pool<'p, 'd, credit::Ready<'p, 'd>>,
index: tree::Candidate,
key: ready::Retained<'d>,
amount: credit::Queued,
}
pub(super) struct Records<'a, 'p, 'd> {
pointer: ptr::NonNull<Record<'p, 'd>>,
borrow: marker::PhantomData<&'a mut [Record<'p, 'd>]>,
}
pub(super) struct Core<'p, 'd> {
memory: alloc::raw::Block<Bound<'d, Record<'p, 'd>>, (), (), Record<'p, 'd>>,
}
impl<'p, 'd> Record<'p, 'd> {
const fn idle() -> Self {
Self {
kind: Kind::Idle,
payload: Payload { idle: () },
}
}
}
impl<'a, 'p, 'd> Idle<'a, 'p, 'd> {
pub(in crate::link::egress::load::credit::wait) fn wait(
self,
index: tree::Index,
waiting: Waiting<'d>,
) -> Queued<'a, 'p, 'd> {
self.0.payload.waiting = mem::ManuallyDrop::new(waiting);
self.0.kind = Kind::Waiting;
Queued {
record: self.0,
index,
}
}
}
impl<'p, 'd> Queued<'_, 'p, 'd> {
pub(in crate::link::egress::load::credit::wait) fn value(&self) -> Waiting<'d> {
unsafe { *self.record.payload.waiting }
}
pub(in crate::link::egress::load::credit::wait) fn replace(
self,
waiting: Waiting<'d>,
) -> tree::Waiting {
self.record.payload.waiting = mem::ManuallyDrop::new(waiting);
tree::Waiting::new(self.index)
}
pub(in crate::link::egress::load::credit::wait) fn proof(self) -> tree::Waiting {
tree::Waiting::new(self.index)
}
pub(in crate::link::egress::load::credit::wait) fn clear(self) -> tree::Waiting {
self.record.kind = Kind::Idle;
tree::Waiting::new(self.index)
}
}
impl<'a, 'p, 'd> Ready<'a, 'p, 'd> {
pub(in crate::link::egress::load::credit::wait) fn matches(
&self,
key: ready::Retained<'d>,
amount: credit::Queued,
) -> bool {
let granted = unsafe { &*self.0.payload.granted };
granted.key == key && granted.grant.amount() == amount.amount()
}
pub(in crate::link::egress::load::credit::wait) fn take(self) -> credit::Grant<'p> {
self.vacate().1
}
pub(in crate::link::egress::load::credit::wait) fn vacate(
self,
) -> (Idle<'a, 'p, 'd>, credit::Grant<'p>) {
let granted = unsafe { mem::ManuallyDrop::take(&mut self.0.payload.granted) };
self.0.kind = Kind::Idle;
(Idle(self.0), granted.grant)
}
}
impl<'pool, 'p, 'd> Selected<'_, 'pool, 'p, 'd> {
fn lane(&self) -> credit::Lane<'pool, 'p, 'd, credit::Ready<'p, 'd>> {
credit::Lane {
pool: self.scope,
index: metadata::Lane::at(self.index.position()),
}
}
pub(in crate::link::egress::load::credit) fn activate(self, owner: driver::Reference<'d>) {
let lane = self.lane();
match owner.ready().try_activate(self.key) {
Ok(()) => {
let grant = lane.account().acquire(self.amount.amount());
self.record.payload.granted = mem::ManuallyDrop::new(Granted {
key: self.key,
grant,
});
self.record.kind = Kind::Granted;
}
Err(ready::Stale) => {
self.record.kind = Kind::Idle;
}
}
}
}
impl<'p, 'd> Core<'p, 'd> {
pub(in crate::link::egress::load::credit::wait) fn try_new(
lanes: metadata::LaneCount,
) -> Result<Self, create::Error> {
let capacity = Bound::try_new(lanes).map_err(create::Error::Wait)?;
let memory = alloc::raw::Block::try_from_fn(
capacity,
(),
|_| Record::idle(),
|_| tree::Node::idle(),
)
.map_err(alloc::Error::from)
.map_err(create::Error::Allocation)?;
Ok(Self { memory })
}
pub(in crate::link::egress::load::credit::wait) fn is_busy(
&self,
lane: credit::Lane<'_, 'p, 'd, credit::Ready<'p, 'd>>,
) -> bool {
let index = tree::Index::from(lane);
let record = unsafe { self.memory.as_ref().get_unchecked(index.offset()) };
!matches!(record.kind, Kind::Idle)
}
pub(in crate::link::egress::load::credit::wait) fn parts(
&mut self,
) -> (Records<'_, 'p, 'd>, Nodes<'_>) {
let (_, records, nodes) = self.memory.parts_mut();
(
Records {
pointer: ptr::NonNull::from(records).cast(),
borrow: marker::PhantomData,
},
Nodes {
pointer: ptr::NonNull::from(nodes).cast(),
borrow: marker::PhantomData,
},
)
}
pub(in crate::link::egress::load::credit::wait) fn nodes(&self) -> NodeView<'_> {
NodeView {
pointer: ptr::NonNull::from(self.memory.tail()).cast(),
borrow: marker::PhantomData,
}
}
pub(in crate::link::egress::load::credit::wait) fn try_bypass(
&mut self,
index: tree::Candidate,
) -> bool {
let limit = self.memory.extent().len.get() as usize - 1;
let record = unsafe { self.memory.as_mut().get_unchecked_mut(index.offset()) };
let waiting = unsafe { &mut *record.payload.waiting };
if waiting.bypasses >= limit {
return false;
}
waiting.bypasses += 1;
true
}
}
impl<'a, 'p, 'd> Records<'a, 'p, 'd> {
pub(in crate::link::egress::load::credit::wait) fn state(
&mut self,
index: tree::Index,
) -> State<'_, 'p, 'd> {
let state = unsafe { &mut *self.pointer.as_ptr().add(index.offset()) };
match state.kind {
Kind::Idle => State::Idle(Idle(state)),
Kind::Waiting => State::Waiting(Queued {
record: state,
index,
}),
Kind::Granted => State::Granted(Ready(state)),
}
}
pub(in crate::link::egress::load::credit::wait) fn selected<'pool>(
self,
index: tree::Candidate,
scope: &'pool credit::Pool<'p, 'd, credit::Ready<'p, 'd>>,
) -> (Selected<'a, 'pool, 'p, 'd>, tree::Waiting) {
let record = unsafe { &mut *self.pointer.as_ptr().add(index.offset()) };
let waiting = unsafe { *record.payload.waiting };
let proof = tree::Waiting::new(index.index());
(
Selected {
record,
scope,
index,
key: waiting.key,
amount: waiting.amount,
},
proof,
)
}
}
const _: () = {
assert!(mem::size_of::<Core<'static, 'static>>() == 3 * mem::size_of::<usize>());
assert!(mem::size_of::<Queued<'static, 'static, 'static>>() == 2 * mem::size_of::<usize>());
assert!(mem::size_of::<Ready<'static, 'static, 'static>>() == mem::size_of::<usize>());
assert!(mem::size_of::<NodeView<'static>>() == mem::size_of::<usize>());
assert!(
mem::size_of::<Record<'static, 'static>>().is_multiple_of(mem::align_of::<tree::Node>())
);
assert!(
Bound::<'_, Record<'static, 'static>>::stride()
.is_multiple_of(mem::align_of::<Record<'static, 'static>>())
);
assert!(
Bound::<'_, Record<'static, 'static>>::stride()
.is_multiple_of(mem::align_of::<tree::Node>())
);
};