Skip to main content

Completion

Struct Completion 

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

One popped completion (M3.7): the operation’s identity, from IORING_CQE::UserData, and its result.

Implementations§

Source§

impl Completion

Source

pub fn user_data(&self) -> usize

The UserData identity this completion reports – match it against a held crate::Token via crate::Token::claim_if.

Source

pub fn result(&self) -> Result<usize>

This op’s result: the transferred byte count (read/write) or other op-specific value in IORING_CQE::Information, once ResultCode says success.

§Errors

Returns the wrapped crate::IoRingError if ResultCode is a failure – for example ERROR_NOT_FOUND when a cancel target was not actually outstanding.

Source

pub fn with_injected_failure(self, failure: InjectedFailure) -> Self

Report failure from Completion::result instead of what this operation actually returned (M16.3).

§What this is for

Failure paths that are otherwise unreachable in a test. Most of what a consumer must handle – a write that fails partway, a flush the device rejects, a registration the kernel refuses – cannot be provoked on demand from a healthy machine, so that code is typically written once and never executed again. This crate shipped a defect of exactly that shape: a claim path that returned early on a failed write and leaked its registered-buffer slot permanently, on a branch no test had ever taken.

§Why this is sound, where fabricating a completion would not be

crate::Token::claim_if’s safety argument is that a Completion for some UserData existing at all proves the kernel has finished with that operation, and therefore that handing its buffer back is sound.

This method consumes a completion the ring genuinely popped and returns one carrying the same UserData and the same ring identity. The operation really did finish; the only thing that changes is what Completion::result says about it. So the argument above is untouched, and claiming against the result is exactly as sound as claiming against the original.

Completion::synthetic is the opposite, and is why it is not reachable from here. A fabricated completion can name an operation that is still in flight, and claiming a token against one hands a buffer back to the caller while the kernel is still writing through it – the precise use-after-free this crate exists to prevent. That is a test-only, crate-only tool and stays one.

§What it cannot do

Only failure can be injected, never success. Turning a real failure into an apparent success would let a test conceal a genuine defect, which is the wrong affordance for a tool whose whole purpose is exercising error handling. That is enforced rather than merely stated: a non-failing HRESULT panics.

§Panics

If failure does not resolve to a failing HRESULT. Only InjectedFailure::Hresult can express that at all.

§Prefer a real failure when one is reachable

A genuine kernel error – writing through a read-only handle, cancelling something that is not outstanding – tests the real path and confirms the crate’s own error translation. Reach for this only where no such route exists.

§The one place injection is not inert: registration completions

The soundness argument above is about crate::Token::claim_if, where a failed completion changes nothing the caller does with memory: the buffer comes back either way. A registration claim is different. crate::PendingBufferRegistration::claim_if treats a failed completion as proof the kernel did not retain the addresses, and so drops the buffers. Inject a failure there and it frees memory the kernel genuinely does hold registered – leaving the ring with a registration pointing at freed pages.

That is inert only while nothing uses it. A test doing this must not push any registered-buffer operation on that ring afterwards, and should tear the ring down immediately.

This is a limitation of what a failed registration means, not something the seam can check: a Completion does not carry which operation produced it, so this cannot be refused at the call. Prefer a genuine failure for registration paths wherever one can be provoked.

§Example
ⓘ
let completion = completion.with_injected_failure(
    InjectedFailure::Win32(ERROR_ACCESS_DENIED),
);
assert!(completion.result().is_err());
// The token still claims it: the operation did complete.
let buffer = token.claim_if(&completion).expect("claims its own");

Trait Implementations§

Source§

impl Clone for Completion

Source§

fn clone(&self) -> Completion

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for Completion

Source§

impl Debug for Completion

Source§

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

Formats the value using the given formatter. 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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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, <T as TryFrom<U>>::Error>

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.