Skip to content

rsevents 0.3.1

Latest
Compare
Choose a tag to compare
@mqudsi mqudsi released this 29 Aug 18:03
· 1 commit to master since this release

rsevents 0.3.x is a complete behind-the-scenes rewrite of the events primitives
to unlock additional performance gains and further reduce the cost of signalling
events. The consumer-side API (as exposed via the Awaitable trait) remains
backwards compatible, although the Awaitable trait itself has been
supercharged to support fallible waits (where waiting on an event can generate
an error other than just a timeout) and awaitable results (where awaiting
non-event Awaitable impls can return something other than just the () void
type). Only users implementing their own custom Awaitable types need to make
any changes to their code to upgrade from rsevents version 0.2.x to 0.3.x
– and the changes are minimal at that (read on).

  • AutoResetEvent and ManualResetEvent are now implemented as two-bit mutexes
    on top of the parking_lot_core crate/futex abstraction. This results in much
    more complicated logic in rsevents itself to correctly handle race
    conditions between setting and awaiting an event, but allows setting,
    resetting, and awaiting/obtaining events to be wait-free and lock-free in the
    case of no contention.
  • The Awaitable trait has been extended with associated type Awaitable::T,
    which is the result of a successful Awaitable::wait() call, allowing
    Awaitable to be used as an abstraction for any type that yields an object or
    instance of a type as a result of a wait operation.
  • Awaitable is also extended with associated type Awaitable::Error
    implementing AwaitableError, which is the result of a bounded wait call like
    Awaitable::wait_for(Duration) or Awaitable::wait0(), with its own
    associated type AwaitableError::UnboundedError, which specifies the
    (possibly different) error type for unbounded waits via Awaitable::wait()
    (which blocks indefinitely until the Awaitable type yields).
  • These changes to Awaitable make it possible to use Awaitable as an
    abstraction for non-event synchronization objects, like std's own Mutex,
    which return a Result<,> that isn't Result<(), TimeoutError>.
  • Despite all these changes, Awaitable remains backwards-compatible and
    exposes the same error-free, bool-returning wait(), wait_for(), and
    wait0() methods by special-casing situations where
    AwaitableError::UnboundedError = () (as is the case with ManualResetEvent
    and AutoResetEvent) to unlock access to the old wait functions with their
    boolean-denominated return types.
  • The type TimeoutError has been introduced as the default AwaitableError
    for ManualResetEvent, AutoResetEvent, and any other Awaitable types that
    offer infallible wait operations (with a timeout being the only possible
    error).
  • Downstream crates using the Awaitable trait to provide their own
    synchronization objects need to modify their implementations to implement
    Awaitable::try_xxx() instead of Awaitable::xxx() - for all existing cases,
    this is just a straight-forward rename, plus definining Awaitable::T = ();
    and Awaitable::Error = TimeoutError; (if rust's default associated types
    feature were complete and available, not even that would be necessary).
  • The Awaitable trait now provides Awaitable::wait0() by default; for cases
    where there is no faster alternative to Awaitable::wait_for(Duration::ZERO)
    – types that can provide a faster (and preferably lock-free/wait-free)
    alternative are encouraged to override Awaitable::try_wait0() (there is no
    need to override Awaitable::wait0() itself as it is routed via try_wait0()
    where it exists.

rsevents 0.3.0 was yanked in favor of the just-published 0.3.1, as it turns out
the overhauled Awaitable trait was not sufficiently generic (it was missing a
lifetime) as to enable returning non-static instances of Awaitable::T, which
was a scenario that the 0.3.x releases were meant to support.