pub struct OperationId { /* private fields */ }Expand description
An identity for an in-flight operation: the address of its OVERLAPPED
together with the generation stamped on it at submission.
The address must not be dereferenced or freed; the kernel owns the storage until the completion is claimed. The generation is what makes the identity durable: addresses are recycled when operations are reclaimed, but a given (address, generation) pair names exactly one submission for the life of the process. Retaining an identity past its operation’s completion is therefore harmless – the backend will reject it rather than act on whatever operation currently occupies that address.
Implementations§
Source§impl OperationId
impl OperationId
Sourcepub fn mint(overlapped: *mut OVERLAPPED) -> Self
pub fn mint(overlapped: *mut OVERLAPPED) -> Self
Mint a new identity for an operation being submitted.
Takes the next generation from the process-wide sequence, so every call
yields a distinct identity even when overlapped repeats an address used
by an earlier, already-reclaimed operation. A backend calls this exactly
once per submission, at the moment it hands the storage to the kernel.
§Panics
Panics if the process-wide generation sequence is exhausted, rather than
wrapping and reissuing generations already in use. A u64 takes
centuries to exhaust at one submission per nanosecond, so this is a
guard on the type’s uniqueness invariant rather than a reachable case.
Sourcepub unsafe fn forge(overlapped: *mut OVERLAPPED, generation: u64) -> Self
pub unsafe fn forge(overlapped: *mut OVERLAPPED, generation: u64) -> Self
Assemble an identity from an address and a generation chosen by the caller, without checking that they belong together.
Backends do not need this: OperationRegistry::remove and
OperationRegistry::identify hand back a whole OperationId,
assembled from the pair the registry itself recorded, so the normal path
from a completion to its identity never supplies a generation.
This exists for tests that must synthesize an identity the registry never issued – a stale one, or one from a generation ahead of the current – in order to prove such an identity is rejected.
§Safety
The caller must have observed overlapped and generation together as
one operation’s identity, or must be deliberately forging an identity in
order to assert that it is refused.
Forging is not memory-unsafe – cancelling a live operation is
well-defined and no storage can be reclaimed twice by it – but it defeats
the isolation the generation exists to provide. A caller holding (p, g)
could otherwise construct (p, g + 1) and, if the next submission reusing
p were stamped with that generation, cancel an operation it never
submitted. That is why this is not a safe constructor:
fn forge_the_next_one(observed: OperationId) -> OperationId {
OperationId::forge(observed.as_ptr(), observed.generation() + 1)
}The same call compiles once the caller takes on the obligation, so what
the example above rejects is the missing unsafe rather than anything
else about the code:
fn rebuild(observed: OperationId) -> OperationId {
// SAFETY: both halves came from one identity, so they were observed
// together by construction.
unsafe { OperationId::forge(observed.as_ptr(), observed.generation()) }
}Sourcepub fn generation(self) -> u64
pub fn generation(self) -> u64
The generation stamped on this identity at submission.
Trait Implementations§
Source§impl Clone for OperationId
impl Clone for OperationId
Source§fn clone(&self) -> OperationId
fn clone(&self) -> OperationId
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more