Re: Internal vs. external barriers (was: Re: Interesting LKMM litmus test)

From: Jonas Oberhauser
Date: Tue Jan 17 2023 - 14:26:17 EST





On 1/17/2023 6:43 PM, Paul E. McKenney wrote:
On Tue, Jan 17, 2023 at 10:56:34AM -0500, Alan Stern wrote:
On Tue, Jan 17, 2023 at 07:14:16AM -0800, Paul E. McKenney wrote:
On Tue, Jan 17, 2023 at 12:46:28PM +0100, Andrea Parri wrote:
This was reminiscent of old discussions, in fact, we do have:

[tools/memory-model/Documentation/litmus-tests.txt]

e. Although sleepable RCU (SRCU) is now modeled, there
are some subtle differences between its semantics and
those in the Linux kernel. For example, the kernel
might interpret the following sequence as two partially
overlapping SRCU read-side critical sections:

1 r1 = srcu_read_lock(&my_srcu);
2 do_something_1();
3 r2 = srcu_read_lock(&my_srcu);
4 do_something_2();
5 srcu_read_unlock(&my_srcu, r1);
6 do_something_3();
7 srcu_read_unlock(&my_srcu, r2);

In contrast, LKMM will interpret this as a nested pair of
SRCU read-side critical sections, with the outer critical
section spanning lines 1-7 and the inner critical section
spanning lines 3-5.

This difference would be more of a concern had anyone
identified a reasonable use case for partially overlapping
SRCU read-side critical sections. For more information
on the trickiness of such overlapping, please see:
https://paulmck.livejournal.com/40593.html
Good point, if we do change the definition, we also need to update
this documentation.

More recently/related,

https://lore.kernel.org/lkml/20220421230848.GA194034@paulmck-ThinkPad-P17-Gen-1/T/#m2a8701c7c377ccb27190a6679e58b0929b0b0ad9
It would not be a bad thing for LKMM to be able to show people the
error of their ways when they try non-nested partially overlapping SRCU
read-side critical sections. Or, should they find some valid use case,
to help them prove their point. ;-)
Isn't it true that the current code will flag srcu-bad-nesting if a
litmus test has non-nested overlapping SRCU read-side critical sections?
Now that you mention it, it does indeed, flagging srcu-bad-nesting.

Just to see if I understand, different-values yields true if the set
contains multiple elements with the same value mapping to different
values. Or, to put it another way, if the relation does not correspond
to a function.

Or am I still missing something?

based on https://lkml.org/lkml/2019/1/10/155:
I think different-values(r) is the same as r \ same-values, where same-values links all reads and writes that have the same value (e.g., "write 5 to x" and "read 5 from y").

With this in mind, I think the idea is to 1) forbid partial overlap, and using the different-values to 2) force them to provide the appropriate value.
This works because apparently srcu-lock is a read and srcu-unlock is a write, so in case of
int r1 = srcu-lock(&ss);   ==>  Read(&ss, x), r1 := x
...
srcu-unlock(&ss, r1);  ==> Write(&ss, r1), which is Write(&ss, x)

This guarantees that the read and write have the same value, hence different-values(...) will be the empty relation, and so no flag.


And if it is true, is there any need to change the memory model at this
point?

(And if it's not true, that's most likely due to a bug in herd7.)
Agreed, changes must wait for SRCU support in herd7.

At which point something roughly similar to this might work?

let srcu-rscs = return_value(Srcu-lock) ; (dep | rfi)* ;
parameter(Srcu-unlock, 2)

I would like instead to be able to give names to the arguments of events that become dependency relations, like
   event srcu_unlock(struct srcu_struct *srcu_addr, struct srcu_token *srcu_data)
and then
    let srcu-rscs = [Srcu-lock] ; srcu_data ; (data; rfi)*

Personally I would also like to not have Linux-specific primitives in herd7/cat, that means that to understand LKMM you also need to understand the herd7 tool, and sounds quite brittle.

I would prefer if herd7 had some means to define custom events/instructions and uninterpreted relations between them, like

relation rf : [write] x [read]
[read] <= range(rf)
empty rf ;rf^-1 \ id

and some way to say
[read] ; .return <= rf^-1 ; .data
(where .return is a functional relation relating every event to the value it returns, and .xyz is the functional relation relating every event to the value of its argument xyz).