pub unsafe trait TryWaitStrategy {
type Error;
// Required method
fn try_wait(
&self,
desired_seq: i64,
barrier: &Barrier,
) -> Result<i64, Self::Error>;
}Expand description
Implement to provide a fallible wait loop which runs as a handle waits for a sequence.
If a wait strategy is not fallible, or does not require either control over loop behaviour, or
carrying state across loop iterations, then prefer implementing Waiting instead, as it
provides a safe interface.
A well-behaved implementation should return as soon as barrier sequence >= desired_seq, but
this is not a safety condition.
§Safety
This trait is unsafe as there is no guard against invalid implementations of
try_wait causing Undefined Behaviour. Valid implementations must
satisfy the following conditions:
try_waitmust not successfully return whilebarrier sequence < desired_seq.try_wait, if successful, must return the last readbarrier sequence.
If try_wait does not abide by these conditions, then writes to the ring buffer may overlap
with other accesses, causing Undefined Behaviour due to mutable aliasing.
Note that no conditions limit when try_wait can return an error.
§Examples
use ansa::{Barrier, wait::TryWaitStrategy};
/// Wait until `max` iterations of the wait loop.
struct MaxIters {
max: usize
}
struct MaxItersError;
// SAFETY: only successful if barrier_seq >= desired_seq; returns barrier_seq
unsafe impl TryWaitStrategy for MaxIters {
type Error = MaxItersError;
fn try_wait(&self, desired_seq: i64, barrier: &Barrier) -> Result<i64, Self::Error> {
let mut iters = 0;
let mut barrier_seq = barrier.sequence();
while barrier_seq < desired_seq {
if iters >= self.max {
return Err(MaxItersError)
}
barrier_seq = barrier.sequence();
iters += 1;
}
Ok(barrier_seq)
}
}Implementing a no wait strategy is also possible (though not necessary if using
Producer::wait_range or
Consumer::wait_range).
use ansa::{Barrier, wait::TryWaitStrategy};
struct NoWait;
struct NoWaitError;
// SAFETY: only successful if barrier_seq >= desired_seq; returns barrier_seq
unsafe impl TryWaitStrategy for NoWait {
type Error = NoWaitError;
fn try_wait(&self, desired_seq: i64, barrier: &Barrier) -> Result<i64, Self::Error> {
match barrier.sequence() {
barrier_seq if barrier_seq < desired_seq => Err(NoWaitError),
barrier_seq => Ok(barrier_seq),
}
}
}The following example shows only some of the possible implementation mistakes that will cause UB.
use ansa::{Barrier, wait::TryWaitStrategy};
struct BadWait;
// ** NOT SAFE **
unsafe impl TryWaitStrategy for BadWait {
type Error = ();
fn try_wait(&self, desired_seq: i64, barrier: &Barrier) -> Result<i64, Self::Error> {
let mut barrier_seq = barrier.sequence();
// VERY BAD: we've changed only one character from `<` to `>`, but this makes
// it possible for waiting to end before the barrier has advanced. Could cause
// mutable aliasing, and thus UB.
while barrier_seq > desired_seq {
barrier_seq = barrier.sequence();
}
// VERY BAD: we return a sequence unrelated to the barrier, possibly leaving
// the disruptor in an inconsistent, non-recoverable state if a handle uses
// the value. Could cause mutable aliasing, and thus UB.
Ok(10)
}
}Required Associated Types§
Required Methods§
Sourcefn try_wait(
&self,
desired_seq: i64,
barrier: &Barrier,
) -> Result<i64, Self::Error>
fn try_wait( &self, desired_seq: i64, barrier: &Barrier, ) -> Result<i64, Self::Error>
Runs the fallible wait loop.
desired_seq represents a value which the barrier must exceed before the wait loop can end.
Call Barrier::sequence to view updates of the barrier’s position.
Well-behaved implementations should return as soon as barrier sequence >= desired_seq.
Implementations must satisfy the following conditions:
- Must not successfully return while
barrier sequence < desired_seq. - If successful, must return the last read
barrier sequence.
No conditions are placed on returning errors.