tools/memory-model/Documentation/recipes.txt

Source file repositories/reference/linux-study-clean/tools/memory-model/Documentation/recipes.txt

File Facts

System
Linux kernel
Corpus path
tools/memory-model/Documentation/recipes.txt
Extension
.txt
Size
18772 bytes
Lines
575
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: documentation
Status
atlas-only

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

*   if (LOAD ->data_tail) {		LOAD ->data_head
	 *			(A)		smp_rmb()	(C)
	 *	STORE $data			LOAD $data
	 *	smp_wmb()	(B)		smp_mb()	(D)
	 *	STORE ->data_head		STORE ->data_tail
	 *   }

The B/C pairing is an example of the MP pattern using smp_wmb() on the
write side and smp_rmb() on the read side.

Of course, given that smp_mb() is strictly stronger than either smp_wmb()
or smp_rmb(), any code fragment that would work with smp_rmb() and
smp_wmb() would also work with smp_mb() replacing either or both of the
weaker barriers.


Load buffering (LB)
-------------------

The LB pattern has one CPU load from one variable and then store to a
second, while another CPU loads from the second variable and then stores
to the first.  The goal is to avoid the counter-intuitive situation where
each load reads the value written by the other CPU's store.  In the
absence of any ordering it is quite possible that this may happen, as
can be seen in the LB+poonceonces.litmus litmus test.

One way of avoiding the counter-intuitive outcome is through the use of a
control dependency paired with a full memory barrier:

	/* See LB+fencembonceonce+ctrlonceonce.litmus. */
	void CPU0(void)
	{
		r0 = READ_ONCE(x);
		if (r0)
			WRITE_ONCE(y, 1);
	}

	void CPU1(void)
	{
		r1 = READ_ONCE(y);
		smp_mb();
		WRITE_ONCE(x, 1);
	}

This pairing of a control dependency in CPU0() with a full memory
barrier in CPU1() prevents r0 and r1 from both ending up equal to 1.

The A/D pairing from the ring-buffer use case shown earlier also
illustrates LB.  Here is a repeat of the comment in
perf_output_put_handle() in kernel/events/ring_buffer.c, showing a
control dependency on the kernel side and a full memory barrier on
the user side:

	 *   kernel				user
	 *
	 *   if (LOAD ->data_tail) {		LOAD ->data_head
	 *			(A)		smp_rmb()	(C)
	 *	STORE $data			LOAD $data
	 *	smp_wmb()	(B)		smp_mb()	(D)
	 *	STORE ->data_head		STORE ->data_tail
	 *   }
	 *
	 * Where A pairs with D, and B pairs with C.

The kernel's control dependency between the load from ->data_tail
and the store to data combined with the user's full memory barrier
between the load from data and the store to ->data_tail prevents
the counter-intuitive outcome where the kernel overwrites the data
before the user gets done loading it.

Annotation

Implementation Notes