---
# System prepended metadata

title: Rust RCU API

---

# Get familiar with Rust
```rust=
/*
 * struct bar {
 *   unsigned long x;
 * }
 *
 */
struct Bar {
    x: usize, 
}

/*
 * struct foo {
 *   struct bar b;
 *   int c;
 * }
 */
struct Foo {
    b: Bar
    c: i32
}

/* Generic types
 *
 * in C we usuall do
 * 
 * struct foo {
 *   spinlock_t lock;
 *   struct bar b;
 *   int c;
 * }
 */
struct Lock<T> {
    lock: SpinLock,
    data: UnsafeCell<T>,
}

// struct foo foo = ...;
let foo: SpinLock<Foo> = ...;
```

## Notations 

* `T1` -> `T2`: describe a function type, sometimes it's useful to say we want to have a function with a certain type. For example `kzalloc()` is `size_t` -> `void *`


## References and borrows
* `&T`: immutable reference: Read-only, can have multiple immutable references
* `&expr`: immutable borrow: gives an immutable reference.
```rust=
// struct foo *foo = &some_foo;
let foo: &Foo = &some_foo;

let b: &Foo = &some_foo;

// int c = foo->c;
let c: i32 = foo.c;
```

* `&mut T`: mutable reference: Exclusive, can only have one.
* `&mut expr`: mutable borrow: gives a mutable reference.
```rust=
// struct foo *foo = &some_foo;
let foo: &mut Foo = &mut some_foo;

// let b: &i32 = &some_foo; // won't compile
// let b: &mut i32 = &mut some_foo; // won't compile either

// foo->b->x = 1
foo.b.x = 1;

// *foo = struct foo { ... };
*foo = Foo { b: Bar {x : 1}, c: 12};
```

## Pointer and `unsafe`
* `*const T`: const pointer
* `*mut T`: mutable pointer
* `*mut T` <-> `*const T`, can cast to each other freely.
* dereference of a pointer is `unsafe`, since compiler cannot guarantee no-UB.
```rust=
let foo: *const Foo = &some_foo; // borrow expr can also provide a pointer

let c = unsafe { *foo }; // only work if Foo is Copy.

let reborrow: &Foo = unsafe { &*foo };
```

Note that having a `&mut` and `&` reference to the same location is generally considered as undefined behavior (bad bad):
```rust=
let global_ptr: *const i32 = &something;

<thread 1>                <thread 2>
let x = unsafe { &mut *(global_ptr as *mut i32)};
                         
                          let y = unsafe { &*global_ptr };
```

## Method and `&self`/`&mut self`
```rust=
impl Foo {
    // void set_c(struct foo *self, int new)
    pub fn set_c(&mut self, new: i32) {
        self.c = new;
    }
    
    // int get_c(struct foo *self)
    pub fn get_c(&self) -> i32 {
        self.c
    }
}
```

## interior mutable and `UnsafeCell`

How do I design a data type that support accesses from multiple threads?

* Attempt #1
```rust=
impl Foo {
    pub fn set_c(&mut self, new: i32) { ... }
}
```

It doesn't work since previously we said having multiple mutable references is UB.

* Attempt #2

```rust=
impl Foo {
    pub fn set_c(&self, new: i32) {
        self.c = new; // ERROR, we cannot modify self.
    }
}
```

* Building block: interior mutable, for example atomics
```rust=
impl<T> AtomicPtr<T> {
    pub fn load(&self, ...) -> *mut T
    pub fn store(&self, new: *mut T, ...);
}
```
The "read" and "write" to the data must be done via some API taking `&self` (and there is some synchronization behind it)

* Try interior mutable
```rust=
struct Foo {
    lock: SpinLock,
    b: Bar;
    c: i32;
}

impl Foo {
    pub fn set_c(&self, new: i32) { 
        self.lock.lock();
        self.c = new; // STILL not working
        self.lock.unlock();
    }
}
```

* Building block: `UnsafeCell<T>`

`&T` and `&UnsafeCell<T>` are treated differently in the language.

```rust=
impl<T> UnsafeCell<T> {
    fn get(&self) -> *mut T;
}

struct Foo {
    lock: SpinLock,
    b: Bar;
    c: UnsafeCell<i32>;
}

impl Foo {
    pub fn set_c(&self, new: i32) {
        self.lock.lock();
        unsafe { *self.c.get() } = new;
        self.lock.unlock();
    }
}

```
## Lock and Guard
```rust=
struct Lock<T> {
    lock: SpinLock;
    data: UnsafeCell<T>;
}

impl<T> Lock<T> {
    fn lock(&self) -> Guard<'_, T> {
        // spin_lock(&self->lock);
        self.lock.lock();
        
        return Guard { locked: self };
    }
}

struct Guard<'a, T> {
    lock: &'a Lock<T>
}

impl<'a, T> Drop for Guard<'a, T> {
    fn drop(&mut self) {
        // spin_unlock(&self->lock)
        self.locked.unlock();
    }
}

let foo: &'1 Lock<Foo> = ..;

let guard: &'2 Guard<'_, Foo> = foo.lock(); // '1 outlives '2

// use guard to access the locked data; 

drop(guard); // unlock
```

## `Deref` and `DerefMut`
Define pointer/reference-like type
```rust=
impl<'a, T> Deref for Guard<'a, T> {
    type Target = T;
    
    fn deref(&self) -> &Self::Target {
        let ptr = self
                    .locked // => &Lock<T>
                    .data // => &UnsafeCell<T>
                    .get(); // *mut T
        // SAFETY: the existence of the Guard means
        // we hold the lock.
        unsafe { &*ptr }
    }
}

impl<'a, T> DerefMut for Guard<'a, T> {
    fn deref_mut(&self) -> &mut Self::Target {
        let ptr = self
                    .locked // => &Lock<T>
                    .data // => &UnsafeCell<T>
                    .get(); // *mut T
        // SAFETY: the existence of the Guard means
        // we hold the lock.
        unsafe { &mut *ptr }
    }
}

let foo: &'1 Lock<Foo> = ..;

let guard: &'2 Guard<'_, Foo> = foo.lock(); // '1 outlives '2

let foo_ref: &'3 Foo = guard.deref();
drop(foo_ref); // '3 ends here

let foo_mut: &'4 Foo = guard.deref_mut();
foo_mut.c = 11;
drop(foo_mut); // '4 ends here

guard.c = 11; // works as well

// use guard to access the locked data; 

drop(guard); // '2 ends here, unlock
```

# Here comes RCU
```rust=

struct RcuReadGuard;

fn read_lock() -> RcuReadGuard {
    // rcu_read_lock()
    rcu_read_lock();
    
    return RcuReadGuard;
}

impl Drop for RcuReadGuard {
    fn drop(&mut self) {
        rcu_read_unlock();
    }
}

let reader: RcuReadGuard = read_lock();
// RCU read-side critical section
//drop(reader);
```

## RCU pointer API
```rust=
/// A RCU protected pointer
/*
 * struct rcu {
 *   void *ptr;
 * }
 */
struct Rcu<T> {
    ptr: AtomicPtr<T>
}

impl<T> Rcu<T> {
    // rcu_dereference()
    fn dereference<'a, 'rcu: 'a>(&'a self, &'rcu RcuReadGuard) -> &'a T {
        unsafe { &*ptr.load(Acquire) };
    }
    
    // rcu_assign_pointer()
    fn swap(&self, new: *mut T) -> RcuOld<T> {
        // xchg_acqrel(self->ptr, new)
        let old_ptr = ptr.swap(new, AcqRel);
        
        return RcuOld { old_ptr };
    }
}

struct RcuOld<T> {
    ptr: *mut T
}

impl<T> Drop for RcuOld<T> {
    fn drop(&mut self) {
        synchronize_rcu();
        // and then we can free the object
    }
}

let r: &Rcu<i32> = ..;

let rcu_guard = read_lock();

let x: &'2 i32 = r.dereference(r, &'1 rcu_guard); // '1 outlives than '2

// drop(rcu_guard); ERROR

let v: i32 = *x;

```

## RCU pointer in a type

```rust=
/*
 * struct foo {
 *   int a;
 *   struct bar __rcu *b;
 *   int __rcu *c;
 * }
 */
struct Foo {
    lock: SpinLock,
    a: i32,
    //a_: AtomicI32,
    b: Rcu<Bar>,
    c: Rcu<i32>,
}

/*
 * struct foo {
 *   spinlock_t lock;
 *   int a;
 *   struct bar __rcu *b;
 *   int __rcu *c;
 * }
 */
Lock<Foo>
NoLock<Foo>
```
We can certainly have a function do
* `Guard<'_, Foo>` -> `&Rcu<Bar>`

but we also want a:
* `&Lock<Foo>` -> `&Rcu<Bar>` for lockless reader.

`Guard<'_, Foo>` can be treated as `&mut Foo`, and `&Lock<Foo>` can be treated as `&Foo`. And the above two functions can run in the same time. Remember `&mut` and `&` at the same time is consider UB?


## Problem recap

* If we have a `Lock<Foo>`, we can get a `Guard<Foo>`
* `Guard<Foo>` can produce a `&mut Foo`, which allows us to access `Foo` freely (read and write)
* However, `&mut Foo` assumes no concurrent access, which is not true for RCU.
* We need to extend Rust Lock types to allow locklessly accesses.

## A magical way

```rust=
struct Foo {
    a: i32,
    // int a;
    b: Rcu<Bar>,
    // struct bar __rcu *b;
    c: Rcu<i32>,
    // int __rcu *c;
    
    // int d; // access locklessly
    d: AtomicU32;
}

let lock: Lock<Foo> = ...;

// struct foo {
//     spinlock_t lock;
//     int a;
//     ...
// }

let rcu = rcu_read_lock();

// We magically get a reference to `b` from lock
let b_ref: &Bar = lock->b. // <= &Rcu<Bar>
                  dereference(&rcu);

let guard = lock.lock();
guard.d //

lock->d // &AtomicU32

let b_ref: &Bar =
    lock.project::<field_of!(Foo, b)>().dereference(&rcu);

```

If `->` is possible, it can solve half of our problem. The other half is

* `Guard<Foo>` shouldn't be able to generate `&mut Foo`, but
* `Guard<Foo>` should provide a way to modify `Foo::a`, i.e.

projection just gives us a way to access a field without holding lock.

`Container<T>`, we cannot get a reference to `T`, and projection provides a way to get a reference to a field of `T` through the `Container<T>`.

`Pin<&mut T>`: a poitner to T, the it cannot be moved, and you cannot directly get a `Pin<&mut Bar>` 

```rust=
let guard: Guard<Foo> = lock.lock();

let a_ref: &mut i32 = guard->a;
```

Another magic operator `->` for `Guard<Foo>`.

Actualy let's rename `Guard` to `Updater` since it make more sense for RCU

```rust=
struct Updater<T> {
    lock: &Lock<T>
}
```

## Projections
Let's first try to implement `->b`

```rust=
impl Lock<Foo> {
    pub fn project_b(&self) -> &Rcu<Bar> {
        // struct Lock<T> {
        //  lock: SpinLock;
        //  data: UnsafeCell<T>;
        // }
        let ptr = self.lock.data.get(); // the address of `Foo`.
        
        // return foo->b;
        unsafe { & (*ptr).b }
    }
}
```

This is not hard, right? We can also do that for `->c`

```rust=
impl Lock<Foo> {
    pub fn project_c(&self) -> &Rcu<i32> {
        // struct Lock<T> {
        //  lock: SpinLock;
        //  data: UnsafeCell<T>;
        // }
        let ptr = self.data.get(); // the address of `Foo`.
        
        // return foo->c;
        unsafe { & (*ptr).c }
    }
}
```

Generify this

```rust=
impl<T> Lock<T> {
    pub fn project<???>(&self) -> &Rcu<???> {
        let ptr = self.data.get();
        
        unsafe { & (*ptr).??? }
    }
}
```

Introduce `Field` trait

```rust=
/// Describe a `Base` type has a field whose name is `name`
// and type is `Type`
// struct Base {
//   ...
//   name: Type
//   ...
// }
pub trait Field<Base> {
    type Type;
    const name: &'static str;
    
    fn field_of(base: *const Base) -> *const Self::Type;
}
```

Figure out the `???` above:


```rust=
impl<T> Lock<T> {
    pub fn project<S, F: Field<T, Type=Rcu<S>>>(&self) -> &Rcu<S> {
        let ptr = self.data.get();
        
        unsafe { &* F::field_of(ptr) }
    }
}
```

And we impl a type for `foo->b`
```rust=
struct FooB; // need to define an empty struct

impl Field<Foo> for FooB {
    type Type = Bar;
    const name: &'static str = "b";
    
    fn field_of(base: *const Foo) -> *const Self::Type {
        unsafe { core::ptr::addr_of!((*base).b) }
    }
}

#[rcu_project]
struct Foo {
    a: i32,
    b: Rcu<Bar>
    next: Rcu<Foo>,
    ...
}

let b_ref: &Bar =
    lock.project::<field_of!(Foo, b)>().dereference(&rcu);
```

We can generate all `impl` for `Field<Foo>` with macros.

## The other half

```rust=
impl<T> Updater<T> {
    pub fn project_mut<S, F: Field<T, Type=S>>(&self) -> &mut S {
        let ptr = self.lock.data.get();
        
        unsafe { &* F::field_of(ptr) }
    }   
}
```

## Rest of the API

```rust=
impl<T> Updater<T> {
    // similar as
    // spin_lock(&foo->lock);
    // struct bar* b = foo->b;
    // int x = b->x;
    // spin_unlock(&foo->lock);
    pub fn rcu_read<S, F: Field<T, Type=Rcu<S>>>(&self) -> &S {
        let ptr = self.lock.data.get();
        
        let rcu_ptr: &Rcu<S> = unsafe { &* F::field_of(ptr) };
        
        &* rcu_ptr.load(Relaxed); // since we hold the lock
    }
    
    // similar as
    // spin_lock(&foo->lock);
    // 
    // struct bar *old = rcu_replace_pointer(foo->b, new);
    // spin_unlock(&foo->lock);
    // synchronze_rcu();
    // kfree(old);
    pub fn update<S, F: Field<T, Type=Rcu<S>>>(&self, new: Rcu<S>) -> RcuOld<S> {
        let ptr = self.lock.data.get();
        
        let rcu_ptr: &Rcu<S> = unsafe { &* F::field_of(ptr) };
        
        rcu_ptr.swap(new) // swap can be non-atomic since we hold the lock.
    } 
}


impl Field<T> {
    type Type = RcuHead<>;
    
}
```