Skip to content

RCU API Usage

Overview

Read-Copy-Update (RCU) is a synchronization mechanism optimized for read-mostly workloads.

Unlike mutexes and rwlocks, RCU focuses on:

  • Object publication
  • Reader-side protection
  • Grace period detection
  • Deferred reclamation

RCU does not provide mutual exclusion.

Instead, it allows readers to access shared objects without blocking while writers publish new versions and reclaim old versions after a grace period.


Core Concepts

RCU separates object lifetime management into three phases:

Publish
Grace Period
Reclaim

A writer may publish a new object immediately, but reclamation of the old object must be deferred until all readers that could still reference it have exited their read-side critical sections.


RCU Read-Side APIs

rcu_read_lock()

Marks the beginning of an RCU read-side critical section.

rcu_read_lock();

obj = rcu_dereference(g_ptr);

...

rcu_read_unlock();

Conceptually:

I am now accessing an RCU-protected object.

rcu_read_unlock()

Marks the end of an RCU read-side critical section.

Conceptually:

I am no longer accessing the RCU-protected object.

Pointer Access APIs

rcu_dereference()

Safely loads an RCU-protected pointer.

obj = rcu_dereference(g_ptr);

Conceptually:

obj = acquire_load(g_ptr);

Provides acquire semantics.

This guarantees that once a reader observes the published pointer, it also observes the object initialization performed before publication.


Why Not Use a Normal Pointer Load?

Using:

obj = g_ptr;

does not provide the required ordering guarantees.

Without acquire semantics, a reader could observe:

pointer is visible
object initialization is not yet visible

which may result in partially initialized data being accessed.


Pointer Publication APIs

rcu_assign_pointer()

Safely publishes an RCU-protected pointer.

rcu_assign_pointer(g_ptr, new_obj);

Conceptually:

release_store(g_ptr, new_obj);

Provides release semantics.

This guarantees:

object initialization
pointer publication

and prevents publication from occurring before initialization.


Why Not Use a Normal Pointer Store?

Using:

g_ptr = new_obj;

does not guarantee ordering.

Compiler or CPU reordering could allow readers to observe a pointer before all object fields are fully initialized.


Grace Period APIs

synchronize_rcu()

Waits until all current readers have exited their read-side critical sections.

rcu_assign_pointer(g_ptr, new_obj);

synchronize_rcu();

free(old_obj);

Conceptually:

publish new object
wait for existing readers
reclaim old object

This is a blocking operation.

The caller cannot continue until the grace period completes.


Deferred Reclamation APIs

call_rcu()

Schedules a callback to execute after a grace period.

call_rcu(&obj->rcu,
         rcu_object_free_cb);

Conceptually:

enqueue callback
return immediately
grace period completes
execute callback

Unlike synchronize_rcu(), this does not block the caller.


struct rcu_head

RCU uses callback descriptors to track deferred reclamation requests.

struct rcu_head {
    struct rcu_head *next;
    void (*func)(struct rcu_head *head);
};

Typically embedded inside reclaimable objects:

struct my_object {
    ...
    struct rcu_head rcu;
};

This allows the callback to recover the containing object and perform cleanup.


Publication vs Reclamation

One of the most important RCU principles is:

Publication
Reclamation

Publishing a new object:

rcu_assign_pointer(g_ptr, new_obj);

does not mean the old object can be reclaimed immediately.

Readers that entered before publication may still hold references to the old object.

The old object must remain valid until the grace period completes.


synchronize_rcu() vs call_rcu()

API Behavior
synchronize_rcu() Blocking reclamation
call_rcu() Asynchronous reclamation

Example:

synchronize_rcu()
wait
free

versus:

call_rcu()
enqueue
return
callback later

Relationship to Mini RCU

A simplified educational implementation may look like:

reader_count++;

...

reader_count--;

with:

while (reader_count != 0)
    ;

This is useful for understanding grace periods, but it is not how Linux RCU scales.

Linux RCU avoids global reader counters and instead relies on:

  • Per-CPU state
  • Quiescent state tracking
  • Grace period detection mechanisms

These topics are part of RCU internals and are discussed separately.


Summary

RCU is a framework for safe object publication and reclamation.

The fundamental workflow is:

Reader
rcu_read_lock()
rcu_dereference()
rcu_read_unlock()

Writer
rcu_assign_pointer()

Reclaimer
synchronize_rcu()
or
call_rcu()

This separation allows readers to execute with minimal overhead while writers safely replace and eventually reclaim old objects.