#fifo #synchronization #await #future #sync

nightly nb-sync

Non-blocking synchronization structures for bare-metal environments

2 unstable releases

Uses old Rust 2015

0.2.0 Jul 1, 2018
0.1.0 May 13, 2018

#2129 in Asynchronous

APSL-2.0 OR MIT

26KB
318 lines

Non-Blocking Lightweight Synchronization Structures

Build Status Docs Status

Provides lightweight synchronization structures based on the nb crate. Meant for Rust on embedded systems. This is a no_std crate and does not require heap allocations.

License

This crate is licensed under one of the following, at your discretion:

  • Apache 2.0
  • MIT

lib.rs:

Nonblocking synchronization structures

This crate is designed for no_std applications where heap allocation is not possible. As such, there is no dependency on the standard library and all allocations are the responsibility of the caller.

The Mutex

The Mutex provided here can be used to provide exclusive access to a value. Because of this library's non-blocking nature, care must be exercised to avoid resource starvation. The lock method requires a bare_metal::CriticalSection.

The Channel

The fifo::Channel provides a single-producer single-consumer queue which is Sync and can be optionally split into a fifo::Sender and fifo::Receiver which are both Send. A key difference between using the Channel by itself vs the Sender and Receiver together is that the Channel requires a bare_metal::CriticalSection for several of its methods in order to provide safety. The Sender and Receiver can be used without this requirement.

Channel Examples

There are two ways a fifo::Channel can be used:

Direct usage

Direct usage requires passing an object that implements fifo::NonReentrant.

extern crate bare_metal;
extern crate nb_sync;

use nb_sync::fifo::Channel;

//In an actual program this would be obtained safely
let cs = unsafe { bare_metal::CriticalSection::new() };

let mut buffer: [Option<u8>; 4] = [None; 4];
let channel = Channel::new(&mut buffer);

channel.send(10, &cs).unwrap();
channel.recv(&cs).unwrap();

Split into a sender and receiver

This uses similar send and recv methods to the previous example, but does not require a bare_metal::CriticalSection.

Method 1: Basic "send" with a clonable

For clonable types, the fifo::Sender::send method can be used inside an await! directly.

extern crate nb;
extern crate nb_sync;

use nb_sync::fifo::Channel;

let mut buffer: [Option<u8>; 4] = [None; 4];
let mut channel = Channel::new(&mut buffer);

let (mut receiver, mut sender) = channel.split();

let clonable = 5;
// this loop is "await!(sender.send(clonable)).unwrap()"
loop {
    match sender.send(clonable) {
        Ok(()) => break Ok(()),
        Err(nb::Error::WouldBlock) => {},
        Err(nb::Error::Other(e)) => break Err(e),
    }
}.unwrap();

// recv is also compatible with nb's await! macro
receiver.recv().unwrap();

Method 2: Sending with a completion

Non-clonable types can be sent using the fifo::Sender::send_with_completion method. This is based on the fifo::Sender::send_lossless method. A fifo::SendCompletion is used to make this more directly usable with the await! macro. It takes ownership of the Sender and the passed value for the duration of the sending process. When fifo::SendCompletion::done is called the Sender will be returned along with an Option which contains the original value if it was not ultimately sent.

extern crate nb;
extern crate nb_sync;

use nb_sync::fifo::Channel;

struct NonClone {
    _0: (),
}
impl NonClone {
    fn new() -> Self { NonClone { _0: () } }
}

let mut buffer: [Option<NonClone>; 4] = [None, None, None, None];
let mut channel = Channel::new(&mut buffer);

let (mut receiver, mut sender) = channel.split();

let value = NonClone::new();
let completion = sender.send_with_completion(value);
// Completions can be aborted.
let (s, v) = completion.done();
sender = s;
let value = v.unwrap(); //the original, unsent value is returned here

let mut completion = sender.send_with_completion(value);
// This loop is "await!(completion.poll()).unwrap()"
loop {
    match completion.poll() {
        Ok(()) => break Ok(()),
        Err(nb::Error::WouldBlock) => {},
        Err(nb::Error::Other(e)) => break Err(e),
    }
}.unwrap();

let (s, v) = completion.done();
sender = s;
assert!(v.is_none()); //the value has been sent.

receiver.recv().unwrap();

Dependencies

~42KB