Skip to main content

RingContract

Struct RingContract 

Source
pub struct RingContract { /* private fields */ }
Expand description

An executable form of this crate’s conservation rules.

Fed by the caller rather than wired into crate::Batch, for two reasons. A ring can be driven through push_raw and the _raw entry points without any of this crate’s bookkeeping being involved at all, so an internal hook would silently cover less than it appears to. And a consumer validating its own harness needs to drive the same rules from outside.

§What this costs to run, which is bounded (M28.2)

Memory here is a function of operations in flight, not of operations ever performed. An operation that finishes leaves the tracking map, so a consumer that pushes and claims forever holds a map whose size follows its own concurrency rather than its uptime.

That was not true before M28.2: a claimed operation was marked Completed and kept, so the oracle retained one entry per operation for the life of the process. The sample never showed it because it appends 24 records, and nothing documented it – so a long-running consumer following this crate’s own recommendation grew without limit. It is also why an always-on checked inventory was ruled out in M23.3, since a check that cannot be left running is not a check.

Retiring an entry would lose the ability to call a later completion for it a duplicate rather than merely unrecognised, so the last FINISHED_HISTORY finished identities are remembered for that purpose alone. Beyond that window a duplicate is still reported, under the weaker name.

§Example

use windows_ioring_sys::contract::RingContract;

let mut contract = RingContract::new();
contract.observe_push(0x1234);
contract.observe_completion(0x1234);
assert!(contract.check_quiescent().is_empty());

Implementations§

Source§

impl RingContract

Source

pub fn new() -> Self

A contract with nothing observed yet.

Source

pub fn observe_push(&mut self, user_data: usize)

Record that an SQE was successfully queued with this user_data.

Report only pushes that queued. A Build* call that failed synchronously releases its reservation and produces no completion, so reporting it would manufacture an Violation::Outstanding at teardown.

There is one push observer, as of M28.5. There were two: observe_push recorded a push that returned a token, and observe_tokenless_push recorded an SQE that carried no token to claim – the _raw flush and cancel entry points – because reporting one through observe_push produced a leak violation its caller had no way to satisfy, there being no token to claim. D-74 removed the leak rule, which made the two identical in body as well as in purpose, and two names for one behaviour is a restatement waiting for the next change to reach only one of them.

Source

pub fn observe_completion(&mut self, user_data: usize)

Record a completion popped from the ring.

Source

pub fn in_flight(&self) -> usize

How many operations have been pushed and not yet completed.

The same number RingContract::check_quiescent turns into one Violation::Outstanding each, offered directly because a consumer usually wants the count rather than the diagnosis – a drain loop asks “is anything left?”, not “what is wrong?”.

This exists because two callers had already written it by hand, and both were a restatement of what this type already knew. epoch_log’s appender kept a usize beside its contract and drove it at every push and every completion, which is precisely the record-the-same-event-twice shape that D-55 exists to remove. The other counted Outstanding violations out of check_quiescent, allocating a Vec to answer a question about a map’s length.

Source

pub fn observe_buffer(&mut self, index: u32, outstanding: usize)

Record a registered buffer’s outstanding count, as crate::RegisteredBuffers::outstanding reports it.

Source

pub fn violations(&self) -> &[Violation]

Violations seen so far, without asking about quiescence.

Source

pub fn check_quiescent(&self) -> Vec<Violation>

Every violation, including operations still outstanding and buffers still in use.

Call once everything is expected to have finished. An empty result is the claim that nothing was lost.

Source

pub fn assert_quiescent(&self)

Panic with every violation if the contract was broken.

The convenience form for a test. Reports all violations rather than the first, because they are usually one cause and seeing only one of them invites fixing a symptom.

§Panics

If RingContract::check_quiescent finds anything.

Trait Implementations§

Source§

impl Debug for RingContract

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for RingContract

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.