Version 1.2 of ai12s/ai12-0363-1.txt
!standard C.6(13.3/5) 20-03-11 AI12-0363-1/02
!standard C.6(19.1/5)
!class Amendment 20-02-05
!status work item 20-02-05
!status received 19-11-12
!priority Low
!difficulty Medium
!subject Fixes for Atomic
!summary
We clarify the wording associated with AI12-0128-1.
!problem
(1) C.6(13.3/5) allows an object of a type that has a (non-atomic) aliased
(sub)component to be marked atomic, but not marking such a type atomic. This
doesn't make much sense.
(2) C.6(13.3/5) bans independently addressable components of nonatomic
subcomponents of an atomic type. This seems unnecessary. And shouldn't this
say "subcomponents"? (No.)
(3) It is not completely clear whether, in Ada 202X, an assignment to a nonatomic
subcomponent of an atomic object is considered to be a single "action," or a
sequence of two (sequential) actions, the first an atomic read and the second
an atomic write.
!proposal
(See Summary.)
!wording
Modify C.6(13.3/5):
If a nonatomic subcomponent of an atomic object is passed as the actual
parameter in a call then the formal parameter shall allow pass by copy (and,
at run time, the parameter shall be passed by copy). A nonatomic subcomponent
of an atomic object shall not be used as an actual for a generic formal of
mode in out. A nonatomic subcomponent of an atomic type {or object} shall not
be aliased. A nonatomic subcomponent of an atomic type or object shall not
have components that are specified to be independently addressable.
{AARM Ramification: A subcomponent that is specified to be atomic is
considered to also specify that it is independently addressable. Thus one
cannot have atomic components of nonatomic subcomponents of an atomic type or
object. We don't allow independent addressability as we've effectively
required nonatomic subcomponents of an atomic type to not be independently
addressable, and the enclosing object of an independently addressable
component also has to be independently addressable. Since no component can
be both at the same time, we make anything that conflicts this way illegal.}
Add after AARM C.6(19.1.c/5):
AARM Discussion: The atomic reads and writes associated with accesses to
nonatomic components of an atomic object are normal atomic operations -- all
of the rules that apply to other atomic operations apply to these as well. In
particular, these atomic reads and writes are sequential if they apply to the
same object.
!discussion
(1) This can happen in cases like:
type R is record
X : aliased Integer;
end record;
Z : R with Atomic; --
(2) A nonatomic subcomponent of an atomic object is mandated to not be
independently addressable. For a component of any object to be independently
addressable, the enclosing object itself must be independently addressable.
That's the point of this rule. This is the only case where we can "turn off"
independent addressability, thus a separate rule is needed.
An atomic component is defined to be independently addressable, so we cannot
allow those in this case -- otherwise we have a contradiction. Note that an
atomic component (or for that matter, anything that is required to be
independently addressable) is allowed in another atomic component, so there is
an easy fix if this happens in practice.
Note that we have a maintenance reason for this requirement: we want it to be
easy to determine if a particular atomic object is going to always be written
indivisibly (when this is necessary, typically major problems occur if it is
true). Requiring a programmer to read every type declaration for every
subcomponent of a type would make verifying this property hard. As such, we
require it to be visible in the components of the atomic type (it's always
indivisible unless there is an atomic component in the type).
We don't need "subcomponent" twice in this rule, as that would effectively
require rechecking the same thing at every level of the type. Since we're
talking about "nonatomic SUBcomponents", we are already visiting every
subcomponent. So, if a component passes the check, we're going to look inside
the component anyway to see if any if its components fail the check. Using
"subcomponents" in both sides of the rule requires visiting the lowest level
subcomponents many times, without any chance of changing the result.
[Perhaps this is too pedantic, but it certainly seems like the sort of thing
that Steve would worry about. - Editor.]
(3) The AARM note C.6(19.1.c/5) describes the intent that a read-modify-write
cycle is expected and that these are separate atomic reads and writes. As such,
there are two operations and these are sequential with respect to any other
operations on the same object.
!ASIS
No changes needed.
!ACATS test
ACATS B-Tests for Annex C might need some changes to add or remove
cases, but the changes aren't enough to need new tests.
!appendix
From: Tucker Taft
Sent: Tuesday, November 12, 2019 3:39 PM
It is not completely clear whether, in Ada 202X, an assignment to a nonatomic
subcomponent of an atomic object is considered to be a single "action," or a
sequence of two (sequential) actions, the first an atomic read and the second
an atomic write. In other words, when two separate, concurrent tasks each
update a nonatomic subcomponent of the same object, is the execution erroneous?
Task1: Atom.X := 1;
Task2: Atom.Y := 3;
There is certainly a race condition, but a race condition between atomic
actions is not erroneous. Another way to think about this, is should this be
treated as equivalent to:
Task1: Atom2 := Atom2 + 3;
Task2: Atom2 := Atom2 - 5;
The above is not erroneous, as it is a sequence of atomic (sequential) actions.
My instinct would be to consider an update to a nonatomic subcomponent of an
atomic object to be a sequence of two atomic actions, since we have now
defined the semantics that way. As with the example of concurrent updates to
an atomic object, there are a well-defined set of possible outcomes, so the
situation is not unbounded. We could declare it to be a bounded error, but we
haven't declared the second example to be a bounded error, so I would rather
not burden the programmer with a concern that a Program_Error might come
flying out some of the time.
Thoughts?
****************************************************************
From: Randy Brukardt
Sent: Tuesday, November 26, 2019 8:52 PM
> It is not completely clear whether, in Ada 202X, an assignment to a
> nonatomic subcomponent of an atomic object is considered to be a
> single "action," or a sequence of two
> (sequential) actions, the first an atomic read and the second
> an atomic write. In other words, when two separate,
> concurrent tasks each update a nonatomic subcomponent of the same
> object, is the execution erroneous?
Could you explain why you say this?
...
> My instinct would be to consider an update to a nonatomic subcomponent
> of an atomic object to be a sequence of two atomic actions, since we
> have now defined the semantics that way.
This seems to me to be the answer: we have defined the semantics to be two
atomic actions. I can hardly imagine atomic actions that aren't sequential,
so I don't understand the question.
> As with the example of concurrent updates to an atomic object, there
> are a well-defined set of possible outcomes, so the situation is not
> unbounded. We could declare it to be a bounded error, but we haven't
> declared the second example to be a bounded error, so I would rather
> not burden the programmer with a concern that a Program_Error might
> come flying out some of the time.
>
> Thoughts?
I don't know why you think the semantics aren't clear here. I don't know how
much clearer C.6(19.1/5) could be. The rewrite of C.6(20/5) and the associated
AARM note 20.j/5 make it clear that read-modify-write code is intended. And C.6
has no atomic update operations (that's the Brad library routines in Ada 202x).
What other semantics could there be?
As you noted, Atomic updates are never safe in Ada (outside of the new
libraries), and they need to be avoided if multiple writers are possible.
No reason for components to be different.
****************************************************************
From: Tucker Taft
Sent: Wednesday, November 27, 2019 7:55 AM
> This seems to me to be the answer: we have defined the semantics to be two
> atomic actions. I can hardly imagine atomic actions that aren't sequential,
> so I don't understand the question.
Fair enough. I just think we should clarify this somewhere -- AARM note to
clarify the intent might be adequate.
****************************************************************
From: Tucker Taft
Sent: Thursday, November 14, 2019 10:22 AM
Eric Botcazou, the AdaCore engineer implementing AI12-0128, suggested some
refinements to the wording. In particular, given this paragraph from
C.6 (13.3/5):
"If a nonatomic subcomponent of an atomic object is passed as the actual
parameter in a call then the formal parameter shall allow pass by copy
(and, at run time, the parameter shall be passed by copy). A nonatomic
subcomponent of an atomic object shall not be used as an actual for a generic
formal of mode in out. A nonatomic subcomponent of an atomic type shall not
be aliased. A nonatomic subcomponent of an atomic type or object shall not
have components that are specified to be independently addressable."
He suggests the following additions (in {...}).
"If a nonatomic subcomponent of an atomic object is passed as the actual
parameter in a call then the formal parameter shall allow pass by copy (and,
at run time, the parameter shall be passed by copy). A nonatomic subcomponent
of an atomic object shall not be used as an actual for a generic formal of
mode in out. A nonatomic subcomponent of an atomic type {or object} shall not
be aliased. A nonatomic subcomponent of an atomic type or object shall not
have {nonatomic} {sub}components that are specified to be independently
addressable."
I am unsure why we didn't say "type or object" systematically in the above,
nor why we didn't say "subcomponents" rather than "components" systematically.
And in the last sentence, specifying something to be atomic is effectively
specifying it to be independently addressable, so it seems better to only
worry about nonatomic subcomponents.
Any comments or rationale for some of the subtle differences between the four
rules?
> Begin forwarded message:
>
> From: Eric Botcazou
> Subject: Re: [SB07-048] - Ada2020: AI12-0128 Exact size access to
> parts of composite atomic objects #999
> Date: November 14, 2019 at 8:09:14 AM EST
> To: "Tucker Taft @ adacore"
> Cc: Bob Duff
>
>> Interesting. The author of the AI (I believe Steve Baird) was
>> clearly making a distinction, but I agree that if a type has a
>> (non-atomic) aliased (sub)component, you probably don't want to allow
>> an object of the type to be marked atomic.
>
> Right, so I'm going to implement this in the compiler:
>
> "A nonatomic subcomponent of an atomic type or object shall not be aliased."
>
>>> The fourth rule seems a bit too strong since, as per C.6 (8 1/3),
>>> atomic objects are considered to be specified as independently
>>> addressable, but atomic components of a nonatomic subcomponent of an
>>> atomic type or object don't seem to be problematic for the new semantics
>>> since nothing changes.
>>
>> Good point -- the fourth rule should probably say:
>> A nonatomic subcomponent of an atomic type or object shall not have
>> *nonatomic* components that are specified to be independently addressable.
>
> In the end, I think that it's essentially equivalent to:
>
> "A nonatomic subcomponent of an atomic type or object shall not be
> specified to be independently addressable."
>
> and I'm going to implement this in the compiler.
****************************************************************
From: Randy Brukardt
Sent: Thursday, November 14, 2019 2:32 PM
A nonatomic subcomponent of an atomic object is necessarily Volatile (unlike
atomicity, volatility applies to components, and all atomic components), so
the rules in C.6(12/5) apply to such components. C.6(13.3/5) is just a
tightening of the rules for nonatomic subcomponents; not everything needs to
be covered.
Specific comments:
"A nonatomic subcomponent of an atomic type {or object} shall not be aliased."
How would a subcomponent of an atomic object be aliased if the type doesn't
declare it that way?? This is a check on a type definition, exclusively. (It
seems to be a privacy breaking check, however, which is annoying, but that
doesn't seem important given the unlikelyness of nonatomic components of a
private type -- these things tend to be integers or enumerations.)
"A nonatomic subcomponent of an atomic type or object shall not have
{nonatomic} {sub}components that are specified to be independently
addressable."
I think this rule is (implicitly) banning any atomic (sub)components of a
nonatomic subcomponent; how would that work? The nonatomic subcomponents would
prevent the inner things from being treated as atomic in some contexts, so
that is nonsense. If some component is atomic, then the enclosing type also
has to be atomic, and so on.
The proposed change would allow that sort of nonsense.
The AI discussion makes it clear that no nonatomic component of an atomic
object should *ever* be independently addressable. It makes no sense for some
subcomponent of a non-independently addressable object to be itself
independently addressable. Ergo, this second change is certainly a bad idea.
****************************************************************
From: Tucker Taft
Sent: Thursday, November 14, 2019 2:43 PM
...
> How would a subcomponent of an atomic object be aliased if the type
> doesn't declare it that way?? This is a check on a type definition,
> exclusively. (It seems to be a privacy breaking check, however, which
> is annoying, but that doesn't seem important given the unlikelyness of
> nonatomic components of a private type -- these things tend to be
> integers or enumerations.)
But what about:
type R is record
X : aliased Integer;
end record;
Z : R with Atomic; -- Is this legal?
> "A nonatomic subcomponent of an atomic type or object shall not have
> {nonatomic} {sub}components that are specified to be independently
> addressable."
>
> I think this rule is (implicitly) banning any atomic (sub)components
> of a nonatomic subcomponent; how would that work?
I don't follow. Perhaps the existing rule implied that, but with the addition
of "nonatomic" here, we are removing any restriction on atomic subcomponents.
Or am I missing your point?
> The nonatomic subcomponents
> would prevent the inner things from being treated as atomic in some
> contexts, so that is nonsense. If some component is atomic, then the
> enclosing type also has to be atomic, and so on.
>
> The proposed change would allow that sort of nonsense.
Sorry, I have lost you. Can you give an example.
> The AI discussion makes it clear that no nonatomic component of an
> atomic object should *ever* be independently addressable. It makes no
> sense for some subcomponent of a non-independently addressable object
> to be itself independently addressable. Ergo, this second change is
> certainly a bad idea.
I have really lost you now. Hopefully an example will clarify...
****************************************************************
From: Randy Brukardt
Sent: Thursday, November 14, 2019 3:13 PM
> But what about:
>
> type R is record
> X : aliased Integer;
> end record;
>
> Z : R with Atomic; -- Is this legal?
I forgot that is legal. (Not really sure *why* it should be legal to have
an atomic object of a nonatomic type, but never mind.)
The privacy breaking implied here bothers me in any case. No fix seems
possible, however (short of banning nonatomic components of partial views).
> > "A nonatomic subcomponent of an atomic type or object shall not have
> > {nonatomic} {sub}components that are specified to be independently
> > addressable."
> >
> > I think this rule is (implicitly) banning any atomic (sub)components
> > of a nonatomic subcomponent; how would that work?
>
> I don't follow. Perhaps the existing rule implied that, but with the
> addition of "nonatomic" here, we are removing any restriction on
> atomic subcomponents. Or am I missing your point?
My point is that we WANT to ban such components. They don't make any sense.
> > The nonatomic subcomponents
> > would prevent the inner things from being treated as atomic in some
> > contexts, so that is nonsense. If some component is atomic, then the
> > enclosing type also has to be atomic, and so on.
> >
> > The proposed change would allow that sort of nonsense.
>
> Sorry, I have lost you. Can you give an example.
Sure. See below.
> > The AI discussion makes it clear that no nonatomic component of an
> > atomic object should *ever* be independently addressable. It makes
> > no sense for some subcomponent of a non-independently addressable
> > object to be itself independently addressable. Ergo, this second
> > change is certainly a bad idea.
>
> I have really lost you now. Hopefully an example will clarify...
For something to be independently addressable, the thing it is a component
of has to be independently addressable. Otherwise, one runs into nonsense.
In this case, a nonatomic component is explicitly NOT independently
addressable. So consider the case you are trying to allow:
type Byte_Array is (1..2) of Byte with Atomic_Components;
-- Byte_Array is not atomic itself.
type Dev_Reg is record
Status : Flags;
Data : Byte_Array;
Padding : Byte;
end record with Atomic;
-- Rep. clause here, not relevant to the point.
My_Reg : Dev_Reg;
Here, we've said that the nonatomic components Status, Data, and Padding of
an atomic type/object are not independently addressable. For instance,
My_Reg.Status := Status;
does an atomic access to the entire My_Reg object.
That clearly applies to:
My_Reg.Data := (2, 2);
But the declaration of Data implies that:
My_Reg.Data(1) := 2;
My_Reg.Data(2) := 2;
*is* independently addressable. That is, each of these components is written
atomically.
But for that to be the case, Data itself has to also be independently
addressable. We have a contradiction, and in particular the guarantee
provided by making the type Dev_Reg atomic is violated.
Again, it's nonsense to say that some component is independently addressable
when the enclosing type is not independently addressable. Usually, we simply
propagate that information upwards (the enclosing type is automatically
independently addressable if any components require that). But in this case,
we can't do that. So far as I'm aware, this is the only case where one can
turn *off* independent addressability, thus we need a special rule in that
case.
****************************************************************
From: Randy Brukardt
Sent: Thursday, November 14, 2019 7:37 PM
Note that independent addressability itself is a guarantee; compilers are
usually free to provide it anywhere. But C.6(19.1/5) says not in this case,
so you get the contradiction.
I note that there also is a usability concern in allowing "deep" atomic
subcomponents. If someone is writing a type for which they are depending on
C.6(19.1/5) for correct operation, they don't want to have to check the entire
text of their program to ensure that it is true.
That is, any atomic components should be visible in the declaration of the
composite type, so that reading the type declaration and at most the
declarations of the component types (to see if any are declared Atomic) can
ensure that every read and write uses the entire hardware register. If one
allows Atomic subcomponents in nonatomic components of an atomic type, then
one has to read the details of every involved type to ensure this property.
That's a maintenance hazard waiting to happen (there's too many places that
would need a comment that "this type must not be declared atomic").
Note that you can still have atomic subcomponents, it's just necessary for
Byte_Array itself to be declared atomic in order for that to be allowed (in
which case C.6(19.1/5) clearly does not apply to the component, so no one
would be surprised when it does not apply to some part of the component).
****************************************************************
From: Tucker Taft
Sent: Thursday, November 14, 2019 10:13 PM
I'll admit to have lost track of what you are trying to say. I had suggested
we alter the fourth rule from:
A nonatomic subcomponent of an atomic type or object shall not have
components that are specified to be independently addressable.
to:
A nonatomic subcomponent of an atomic type or object shall not have
nonatomic subcomponents that are specified to be independently
addressable.
What are you proposing the rule should be?
****************************************************************
From: Randy Brukardt
Sent: Thursday, November 14, 2019 10:27 PM
Either the original wording, or perhaps better:
A nonatomic subcomponent of an atomic type or object shall not have
{sub}components that are specified to be independently addressable.
AARM Ramification: a subcomponent that is specified to be atomic is considered
to also specify that is independently addressable. [This follows from
C.6(8.1/4), which says this literally.]
A nonatomic component should not be allowed to have atomic or independently
addressable subcomponents, as that is a contradiction (the nonatomic component
is defined to be *not* independently addressable, and that has to apply to any
subparts as well).
If you do not believe the above, then you should simply suggest deleting the
rule entirely (whether something is declared atomic has no bearing on whether
it can be independently addressable).
Note that there is no problem having atomic components of atomic
types/objects; it just doesn't make sense to have nonatomic components
sandwiched in between.
****************************************************************
From: Brad Moore
Sent: Wednesday, March 11, 2020 1:12 PM
[Part of a larger message, just the relevant part here - Editor.]
Also, I had a typo in AI12-0363-1, that I didn't mention in our phone meeting.
AARM Ramification: 1st sentence,
"a subcomponent that is specified to be atomic is considered to also specify
that {it} is independently addressable."
****************************************************************
From: Tucker Taft
Sent: Wednesday, March 11, 2020 4:37 PM
[Part of a larger message, just the relevant part here - Editor.]
...
> Also, I had a typo in AI12-0363-1, that I didn't mention in our phone meeting.
>
> AARM Ramification: 1st sentence,
> "a subcomponent that is specified to be atomic is considered to also
> specify that {it} is independently addressable."
Good catch.
****************************************************************
Questions? Ask the ACAA Technical Agent