Crate minircu

Source
Expand description

Minimal RCU (Read-Copy-Update) implementation

This crate provides a minimal Read-Copy-Update (RCU) synchronization mechanism specifically designed for OpenVMM use cases. RCU is a synchronization technique that allows multiple readers to access shared data concurrently with writers by ensuring that writers create new versions of data while readers continue using old versions.

This is similar to a reader-writer lock except that readers never wait: writers publish the new version of the data and then wait for all readers to finish using the old version before freeing it. This allows for very low overhead on the read side, as readers do not need to acquire locks.

§Usage

Basic usage with the global domain:

// Execute code in a read-side critical section
let result = minircu::global().run(|| {
    // Access shared data safely here.
    42
});

// Wait for all current readers to finish their critical sections.
// This is typically called by writers after updating data.
minircu::global().synchronize_blocking();

§Quiescing

To optimize synchronization, threads can explicitly quiesce when it is not expected to enter a critical section for a while. The RCU domain can skip issuing a memory barrier when all threads are quiesced.

use minircu::global;

// Mark the current thread as quiesced.
global().quiesce();

§Asynchronous Support

The crate provides async-compatible methods for quiescing and synchronization:

use minircu::global;

async fn example() {
    // Quiesce whenever future returns Poll::Pending
    global().quiesce_on_pending(async {
        loop {
            // Async code here.
            global().run(|| {
                // Access shared data safely here.
            });
        }
    }).await;

    // Asynchronous synchronization
    global().synchronize(|duration| async move {
        // This should be a sleep call, e.g. using tokio::time::sleep.
        std::future::pending().await
    }).await;
}

§Gotchas

  • Avoid blocking or long-running operations in critical sections as they can delay writers or cause deadlocks.
  • Never call synchronize or synchronize_blocking from within a critical section (will panic).
  • For best performance, ensure all threads in your process call quiesce when a thread is going to sleep or block.

§Implementation Notes

On Windows and Linux, the read-side critical section avoids any processor memory barriers. It achieves this by having the write side broadcast a memory barrier to all threads in the process when needed for synchronization, via the membarrier syscall on Linux and FlushProcessWriteBuffers on Windows.

On other platforms, which do not support this functionality, the read-side critical section uses a memory fence. This makes the read side more expensive on these platforms, but it is still cheaper than a mutex or reader-writer lock.

Structs§

RcuDomain
An RCU synchronization domain.

Functions§

global
The global RCU domain.