Skip to content

synchronize_rcu()

Purpose

synchronize_rcu() waits for an RCU grace period to complete.

When this function returns, all RCU readers that existed before the call have exited their read-side critical sections.

This allows old RCU-protected objects to be safely reclaimed.


Prototype

void synchronize_rcu(void);

#include <linux/rcupdate.h>

Usage Pattern

old = rcu_dereference_protected(g_obj, 1);

rcu_assign_pointer(g_obj, new);

synchronize_rcu();

kfree(old);

Concept

RCU updates consist of three phases:

Publication
Grace Period
Reclamation

synchronize_rcu() implements:

Grace Period

What Does It Wait For?

Assume:

Reader-1
Reader-2
Reader-3

are currently executing:

rcu_read_lock();
...
rcu_read_unlock();

A writer publishes a new object:

rcu_assign_pointer(g_obj, new);

The writer then calls:

synchronize_rcu();

The function waits until:

Reader-1 exits
Reader-2 exits
Reader-3 exits

After that:

Grace Period Complete

What It Does Not Wait For

Readers that start after publication are not part of the grace period.

Example:

Reader-A
Grace Period Starts
Reader-B Starts

The grace period only waits for:

Reader-A

It does not wait for:

Reader-B

because Reader-B can only observe the newly published object.


Blocking Behavior

synchronize_rcu() blocks the caller until the grace period completes.

Conceptually:

Writer
Publish New Object
Wait
Grace Period Complete
Continue

Typical Use Case

Simple object replacement:

struct my_object *old;
struct my_object *new;

new = kmalloc(sizeof(*new), GFP_KERNEL);

old = rcu_dereference_protected(g_obj, 1);

*new = *old;

new->value = 123;

rcu_assign_pointer(g_obj, new);

synchronize_rcu();

kfree(old);

Advantages

Simple

The update flow is easy to understand:

Publish
Wait
Free

Safe

The old object is guaranteed not to be referenced by any pre-existing readers.


Disadvantages

Writer Blocks

The caller cannot continue until the grace period completes.

Writer Waits

This may increase update latency.


Not Suitable for Frequent Updates

If updates occur frequently:

Publish
Wait
Publish
Wait
Publish
Wait

the blocking cost becomes significant.

In such cases:

call_rcu()

is often preferred.


synchronize_rcu() vs call_rcu()

synchronize_rcu()

Writer waits.

Example:

rcu_assign_pointer(g_obj, new);

synchronize_rcu();

kfree(old);

call_rcu()

Writer continues immediately.

Example:

rcu_assign_pointer(g_obj, new);

call_rcu(&old->rcu, free_callback);

Memory reclamation occurs later through a callback.


Common Mistake

Incorrect:

rcu_assign_pointer(g_obj, new);

kfree(old);

Readers may still reference:

old

leading to use-after-free bugs.

Correct:

rcu_assign_pointer(g_obj, new);

synchronize_rcu();

kfree(old);