Linux Kernel Architecture

(Jacob Rumans) #1

Chapter 5: Locking and Interprocess Communication


<list.h>
static inline void list_add_rcu(struct list_head *new, struct list_head *head)
static inline void list_add_tail_rcu(struct list_head *new,
struct list_head *head)
static inline void list_del_rcu(struct list_head *entry)
static inline void list_replace_rcu(struct list_head *old,
struct list_head *new)

❑ list_add_rcuadds a new elementnewto the beginning of a list headed byhead, while
list_add_tail_rcuadds it to the end.
❑ list_replace_rcureplaces the list elementoldwithnew.
❑ list_del_rcuremoves the elemententryfrom its list.

Most importantly,list_for_each_rcuallows for iterating over all elements of a list. The variant
list_for_each_rcu_safeis even safe against element removal.

Both operations must be enclosed in arcu_read_lock() ... rcu_read_unlock()pair.

Notice that the kernel provides a large amount of documentation about RCU by the creator of the mecha-
nism. It is located inDocumentation/RCUand makes for a very interesting read — especially because it is
not outdated like many other texts included in the kernel. The documents not only provide information
about how RCU is implemented, but additionally introduce some further standard functions not covered
here because their use in the kernel is not so common.

5.2.5 Memory and Optimization Barriers


Modern compilers and processors will try to squeeze every bit of performance out of code, and readers
will certainly agree that this is a good thing. However, as with every good thing, there is also a drawback
to consider (maybe you’ve heard this before in this chapter). One particular technique to achieve better
performance is toreorderinstructions. This can be perfectly fine, as long as the result is identical. How-
ever, it can be hard to decide for a compiler or processorifthe result of a reordering will really match
the intended purpose, especially if side effects need to be considered — a thing at which machines are
naturally suboptimal compared to humans. Side effects are, however, a common and necessary effect
when data are written to I/O registers.

While locks are sufficient to ensureatomicity, they cannot always guaranteetime orderingof code that is
subjected to optimizations by compilers and processors. And, in contrast to race conditions, this problem
not only affects SMP systems, but also uniprocessor machines.

The kernel provides several functions to prevent both the processor and the compiler from reordering
code:

❑ mb(),rmb(),andwmb()insert hardware memory barriers into the code flow.rmb()is aread mem-
ory barrier. It guarantees that all read operations issuedbeforethe barrier are completed before
any read operationsafterthe barrier are carried out.wmbdoes the same thing, but this time for
write accesses. And, as you have guessed,mb()combines both effects.
❑ barrierinserts anoptimizationbarrier. This instructs the compiler to assume that all memory
locations in RAM stored in CPU registers that were valid before the barrier are invalid
after the barrier. Essentially, this means that thecompilerdoes not process any read or write
Free download pdf