---
# System prepended metadata

title: RCU usage

---

# RCU usage

## Simple
```clike=
struct myconfig { int a, b;} *curconfig;

/* Returns true if the global is not NULL */
bool get(int *cur_a, int *cur_b)
{
    struct myconfig *mcp;
    
    rcu_read_lock();
    mcp = rcu_dereference(curconfig);
    if (mcp) {
        if (cur_a)
            *cur_a = mcp->a;
        if (cur_b)
            *cur_b = mcp->b;
    }
    rcu_read_unlock();
    return mcp != NULL;
    
}

// Typical Writer

bool set(int cur_a, int cur_b)
{
    struct myconfig *mcp = kmalloc(...);
    struct myconfig *oldmcp;
    
    if (!mcp)
        return false;
    mcp->a = cur_a;
    mcp->b = cur_b;
    spin_lock(&mylock);
    oldmcp = rcu_dereference_protected(curconfig, lockdep_is_held(&mylock));
    rcu_assign_pointer(curconfig, mcp);
    spin_unlock(&mylock);
    synchronize_rcu();
    kfree(oldmcp);
    return true;
}

// Atomic Writer

bool set(int cur_a, int cur_b)
{
    struct myconfig *mcp = kmalloc(...);
    
    if (mcp)
        return false;
    
    mcp->a = cur_a;
    mcp->b = cur_b;
    
    mcp = xchg(&curconfig, mcp);
    synchronize_rcu();
    kfree(mcp);
    return tru e;
}
```

## Rust version:

```rust=
/// RCU read-side critical section guards.
struct RcuGuard<'a> {
    phantom: PhantomData<&'a>
}

fn rcu_read_lock<'a>() -> RcuGuard<'a> {
    unsafe {
        bindings::rcu_read_lock();
    }
    
    RcuGuard {
        phantom: PhantomData
    }
}

/// RAII: RcuGuard drop == unlock.
impl<'a> Drop for RcuGuard<'a> {
    fn drop(&mut self) {
        unsafe {
            bindings::rcu_read_unlock();
        }
    }
} 



/// A pointer to RCU-protected data.
struct RcuPtr<P: ForeignOwnable> {
    ptr: AtomicPtr,
    phantom: PhantomData<P>
}

struct RcuPtrOld<P: ForeignOwnable> {
    ptr: *mut (),
    phantom: PhantomData<P>
}

impl<P: ForeignOwnable> Drop for RcuPtrOld<P> {
    fn drop(&mut self) {
        // SAFETY: Always?
        unsafe {
            bindings::synchronize_rcu();
        }
        
        <P as ForeignOwnable>::from_foreign(self.ptr);
    }
}

impl<P: ForeignOwnable> Drop for RcuPtr<P> {
    fn drop(&mut self) {
        // SAFETY: Always?
        unsafe {
            bindings::synchronize_rcu();
        }
        
        <P as ForeignOwnable>::from_foreign(self.ptr.load(Relaxed));
    }
}

impl<P: ForeignOwnable> RcuPtr<P> {
    pub fn new(p: P) -> Self {
        RcuBox {
            // INVARIANTS: Sets `self.ptr` to a pointer to boxed objects.
            ptr: AtomicPtr::new(P::into_foreign(p)),
            phantom: PhantomData
        }
    }
    
    /// Update but not atomic
    pub fn swap(&mut self, new: P) -> RcuBoxOld<T> {
        // SAFETY: Per INVARIANTS
        let old_ptr = self.ptr.load(Relaxed);
        
        // INVARIANTS: Sets `self.ptr` to a pointer to boxed objects.
        self.ptr.store(P::into_foreign(new), Release);
        
        RcuBoxOld { 
            ptr: old_ptr,
            phantom: PhantomData
        }
    }
    
    /// Atomic update.
    pub fn atomic_swap(&self, new: P) -> RcuBoxOld<T> {
        // INVARIANTS: `new_ptr` always points to a boxed object.
        let new_ptr = P::into_foreign(new);
        
        let old_ptr = self.ptr.swap(new_ptr, Release);
        
        // SAFETY: Per INVARIANTS
        RcuBoxOld {
            ptr: old_ptr,
            phantom: PhantomData
        }
    }
    
    /// rcu_dereference(), gets a immutable reference to the object.
    ///
    /// Lifetime/borrow checking guarantee the reference cannot outlive RCU
    /// read-side locks.
    pub fn get<'a>(&self, guard: &RcuGuard<'a>) -> P::Borrowed<'a> {
        let ptr = self.ptr.load(Acqure); // Need `Consume` but not available.
        
        // SAFETY: Per INVARIANTS, `ptr` is a valid pointer,
        // and RCU guarantees no data race.
        unsafe {
            P::borrow(ptr)
        }
    }
}

struct Global {
    config: RcuBox<Config> // "struct config *", i.e. a pointer to the heap.
}

impl Global {
    fn get(&self) -> (i32, i32) {
        // "&self" is a reference to "Global"
        // struct global *self = .. ;
        let guard = rcu_read_lock();
        let c = self.config.get(guard);
        // struct config *c = self->config;
    
        (c.a, c.b)
    
        // implicit `drop(guard)` here
        // `c` will not live longer then `guard`, so `c` cannot be used
        // afer `guard` dropped.
    }
    
    fn atomic_set(&self, a: i32, b: i32) {
        let new = Box::new(Config {a, b});
        
        self.config.atomic_swap(new); // implicit drop the return value.
    }
}


struct Config {
    a: i32,
    b: i32,
}
```

## List (TODO)

## Phased state change
```clike=
bool be_careful;

// Common-Case Operation
void cco(void)
{
    rcu_read_lock();
    if (READ_ONCE(be_careful))
        cco_carefully();
    else
        cco_quickly();
    rcu_read_unlock();
}

// Maintenance Operation
void maint(void)
{
    WRITE_ONCE(be_careful, true);
    synchronize_rcu();
    do_maint();
    synchronize_rcu();
    WRITE_ONCE(be_careful, false);
}
```