Reader-Writer Spinlocks (rwlock_t) in the Linux Kernel-Free Linux Device Driver Training in Hyderabad

« Previous Lecture | Next Lecture »

Reader-Writer Spinlocks (rwlock_t) in the Linux Kernel
Free Linux Kernel Programming Course • Kernel Synchronization Part 2 • Kernel 6.x
Level: Intermediate
Kernel: 6.x
Reading Time: 11 min

Free linux kernel development course: a plain spinlock treats every accessor the same way, even when most of them only want to read shared data. This lecture in our free linux device drivers course introduces the reader-writer spinlock, a locking construct built for exactly that read-heavy access pattern.

What you will learn:

  • Why a plain spinlock over-serializes read-mostly data structures
  • The reader-writer spinlock model: concurrent readers, exclusive writer
  • The rwlock_t type and how it relates to spinlock_t
  • When a reader-writer spinlock helps — and when it does not
  • Where kernel 6.x steers you instead (seqlock, RCU) for many read-mostly cases

Prerequisites: a solid understanding of the plain spinlock, covered earlier in this free embedded systems course.

reader writer spinlock linux kernel rwlock_t free kernel programming course free linux device drivers course

The Problem: A Plain Spinlock Over-Serializes Readers

Picture a large, global, doubly linked list with a few thousand nodes that many threads search but only occasionally modify. Because the list is shared and writable, every access — even a read — is a critical section: without protection, a reader could walk a node that a writer is mid-way through unlinking, producing a dirty or torn read. The obvious fix is a plain spinlock around every traversal.

spin_lock(&mylist_lock);
list_for_each(pos, &my_list_head) {
	/* search for something */
}
spin_unlock(&mylist_lock);

This is correct, but it is also needlessly slow when reads vastly outnumber writes. A plain spinlock only ever allows one CPU into the critical section at a time, so if ten threads are all just reading the list simultaneously on a multicore box, nine of them sit spinning even though none of them would ever conflict with each other — only a concurrent writer would be a real problem.

The Fix: Reader-Writer Spinlocks

A reader-writer spinlock separates the two kinds of access. Any thread that only needs to read acquires a read lock; any thread that needs to modify the data acquires an exclusive write lock. The rules are:

  • A read lock is granted immediately to any thread that asks, as long as no writer currently holds the write lock.
  • Multiple readers can hold the read lock at the same time — in effect, no real serialization happens between readers.
  • The moment a writer requests the write lock, it must wait for every current reader to release its read lock first.
  • Once the writer acquires the exclusive write lock, any new readers or writers that show up must wait for the writer to finish.

This construct pays off specifically when the access pattern is read-heavy, writes are rare, and the critical section is long enough that serializing every access (as a plain spinlock does) would waste real CPU time.

Plain Spinlock vs Reader-Writer Spinlock
Plain spinlock (mylist_lock): Reader A — LOCK — read — UNLOCK Reader B waits the whole time Reader C waits the whole time Reader-writer spinlock (rwlock_t): Reader A — read_lock — read — read_unlock Reader B — read_lock — read — read_unlock } all run together Reader C — read_lock — read — read_unlock Writer — write_lock (waits for A, B, C to finish) — modify — write_unlock (new readers/writers now wait for the writer)

The rwlock_t Type

Having already used spinlock_t, the reader-writer variant will feel familiar: the lock is abstracted as an rwlock_t structure, declared from <linux/rwlock.h>, and the API names simply substitute “read” or “write” in place of “spin”:

#include <linux/rwlock.h>

rwlock_t my_list_lock;
rwlock_init(&my_list_lock);

Just as with spinlock_t, you can also declare and initialize a static reader-writer lock in one step using DEFINE_RWLOCK(my_list_lock);. We will cover the full read_lock()/read_unlock()/write_lock()/write_unlock() API, along with the interrupt-safe variants, in detail in the next lecture — this one is focused purely on the concept and when it is the right tool.

A Modern Caveat: Prefer seqlock or RCU For Many Read-Mostly Cases

One thing worth flagging clearly on kernel 6.x: reader-writer spinlocks are still present and supported, but the kernel community generally steers new read-mostly data structures toward seqlock_t or RCU (Read-Copy-Update) instead. The reason is writer starvation — if readers keep arriving in a steady stream, a waiting writer can be delayed indefinitely, because the lock only checks “are there readers holding it right now,” not “how long has a writer been waiting.” seqlock_t and RCU solve read-mostly access patterns without that starvation risk, and RCU in particular is the dominant technique for read-mostly kernel data today. We mention this now so you build the right instinct: know how rwlock_t works because you will still meet it in older and simpler code paths, but reach for RCU when you are designing new read-mostly data structures for a modern kernel.

Lock TypeConcurrent ReadersWriter Starvation RiskTypical Modern Use
Plain spinlock_tNoN/AShort critical sections, any access pattern
rwlock_tYesYes, under heavy read loadSimple read-mostly data, legacy code paths
seqlock_t / RCUYes (lock-free for readers)NoNew read-mostly kernel data structures

Frequently Asked Questions

Q1. Can a thread hold a read lock and a write lock on the same rwlock_t at the same time?
No — the lock only tracks one state at a time (some number of readers, or one writer), never both.

Q2. Is rwlock_t interrupt-safe by default?
No, just like plain spinlocks, you need the interrupt-safe variants when the lock might also be taken from interrupt context; we cover those in the next lecture.

Q3. Does a reader-writer spinlock help if writes are frequent?
Not much — if writers show up often, readers spend most of their time waiting anyway, and you lose the benefit of concurrent reads.

Q4. Why does the kernel community prefer RCU over rwlock_t for new code?
RCU readers proceed without taking any lock at all, so there is no writer-starvation problem and no read-side lock contention, which scales better on modern many-core systems.

Q5. Is rwlock_t deprecated?
No, it is still a fully supported kernel API and appears throughout the tree; it is simply no longer the default first choice for brand-new read-mostly data structures.

Q6. What header declares rwlock_t?
<linux/rwlock.h>, alongside DEFINE_RWLOCK() and rwlock_init().

Practice Exercises

  1. Sketch (in comments only, no need to compile) how you would convert the plain-spinlock list search shown above to use rwlock_t.
  2. List two data structures in a driver you have written where reads clearly outnumber writes.
  3. Research, in the kernel source tree on your own machine, one real subsystem that still uses rwlock_t today.

This lecture is part of EmbeddedPathashala’s free linux kernel development course, free linux device drivers course and free embedded systems course.

More Free Lectures Join the Community

« Previous Lecture | Next Lecture »

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *