TryWaitStrategy

Trait TryWaitStrategy 

Source
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:

  1. try_wait must not successfully return while barrier sequence < desired_seq.
  2. try_wait, if successful, must return the last read barrier 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§

Source

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:

  1. Must not successfully return while barrier sequence < desired_seq.
  2. If successful, must return the last read barrier sequence.

No conditions are placed on returning errors.

Implementors§