tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: __{read,write}_once



On Wed, 6 Nov 2019 at 18:08, Maxime Villard <max%m00nbsd.net@localhost> wrote:
>
> Le 06/11/2019 à 17:37, Marco Elver a écrit :
> > On Wed, 6 Nov 2019 at 16:51, Kamil Rytarowski <n54%gmx.com@localhost> wrote:
> >>
> >> On 06.11.2019 16:44, Kamil Rytarowski wrote:
> >>> On 06.11.2019 15:57, Jason Thorpe wrote:
> >>>>
> >>>>
> >>>>> On Nov 6, 2019, at 5:41 AM, Kamil Rytarowski <n54%gmx.com@localhost> wrote:
> >>>>>
> >>>>> On 06.11.2019 14:37, Jason Thorpe wrote:
> >>>>>>
> >>>>>>
> >>>>>>> On Nov 6, 2019, at 4:45 AM, Kamil Rytarowski <n54%gmx.com@localhost> wrote:
> >>>>>>>
> >>>>>>> I propose __write_relaxed() / __read_relaxed().
> >>>>>>
> >>>>>> ...except that seems to imply the opposite of what these do.
> >>>>>>
> >>>>>> -- thorpej
> >>>>>>
> >>>>>
> >>>>> Rationale?
> >>>>>
> >>>>> This matches atomic_load_relaxed() / atomic_write_relaxed(), but we do
> >>>>> not deal with atomics here.
> >>>>
> >>>> Fair enough.  To me, the names suggest "compiler is allowed to apply relaxed constraints and tear the access if it wants".... But apparently the common meaning is "relax, bro, I know what I'm doing".  If that's the case, I can roll with it.
> >
> > See below.
> >
> >>>> -- thorpej
> >>>>
> >>>
> >>> Unless I mean something this is exactly about relaxed constraints.
> >>
> >> miss*
> >>
> >>>
> >>> "Relaxed operation: there are no synchronization or ordering constraints
> >>> imposed on other reads or writes" and without "operation's atomicity is
> >>> guaranteed".
> >
> > In the memory consistency model world, "relaxed" has a very specific
> > meaning for loads/stores. It simply means that the compiler and
> > architecture is free to reorder the memory operation with respect to
> > previous or following memory operations in program order. But the
> > load/store still happens as one atomic operation.
> >
> > For programming-language memory models, "relaxed" appears in the
> > context of atomic memory operations, to define their ordering w.r.t.
> > other operations in program order. There is a distinction between
> > "relaxed atomic" and plain (unannotated) memory operations at the
> > programming language level.
> >
> > For plain operations, the compiler, in addition to the target
> > architecture, is free to reorder operations or even apply
> > optimizations that turn single plain operations into multiple
> > loads/stores [1, 2].
> > [1] https://lwn.net/Articles/793253/
> > [2] https://lwn.net/Articles/799218/
> >
> > In the Linux kernel READ_ONCE/WRITE_ONCE are one way to specify
> > "relaxed atomic read/write" for accesses that fit in a word (_ONCE
> > also works on things larger than a word, but probably aren't atomic
> > anymore). For most architectures the implementation is the same, and
> > merely avoids compiler optimizations; the exception is Alpha, where
> > READ_ONCE adds a memory barrier [3].
> > [3] https://www.kernel.org/doc/Documentation/memory-barriers.txt
> >
> >>> This is also similar to what suggested Google to apply to NetBSD in our
> >>> internal thread, but with a bit different naming.
> >
> > What you call the ops is entirely up to you. I would not use
> > '{read,write}_relaxed', since as you pointed out above, is probably
> > more confusing. This is why I suggested 'atomic_{read,write}_relaxed'.
> > If you do not like the 'atomic' in there, the next best thing is
> > probably '{read,write}_once'.
> >
> > Just note that you're now defining your own memory consistency model.
> > This is a complex topic that spans decades of work. The safest thing
> > is to stick as closely to the C11/C++11 memory model as possible [4].
> > The Linux kernel also has a memory model [5], but is significantly
> > more complex since it was defined after various primitives had been
> > introduced.
> > [4] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1479.htm
> > [5] https://github.com/torvalds/linux/blob/master/tools/memory-model/Documentation/explanation.txt
> >
> > Best Wishes,
> > -- Marco
>
> Thanks for the details.
>
> I must say I still have a doubt about the instructions actually emited
> by the compiler.
>
> Let's take READ_ONCE for example. What it does is basically just casting
> the pointer to volatile and doing the access. Two points of confusion:
>
>   - Is 'volatile' a guarantee that the compiler will emit only one
>     instruction to fetch the value?

No, it depends on the access size among other things. 'volatile' just
communicates to the compiler that every access is a potentially
visible side-effect and avoid optimizations. 'volatile' on its own is
not at all sufficient for writing correct concurrent code.

READ_ONCE is not perfect in that sense, but it has been around for a
long time so it's pretty hard to change.

>   - Assuming there is only one instruction, strictly speaking the fetch is
>     not guaranteed to be atomic, is that correct? Because the address may
>     not be naturally aligned; or the cpu may not be x86 and thus may not
>     provide automatic atomicity in such case.

Yes, this depends on the architecture. That's why C11/C++11 provide
special types for atomics that should always do the "right thing".

If you want to be certain about the instructions emitted, then (as
mentioned) the safest thing is to adopt what is actually supported by
the language already (or look at the builtins that are used to
implement atomics
https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html).


-- Marco



Home | Main Index | Thread Index | Old Index