Version 1.3 of ai12s/ai12-0363-1.txt
!standard 3.10.2(26/3) 20-04-27 AI12-0363-1/03
!standard 9.10(1/5)
!standard C.6(13.3/5)
!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 disallows marking such a type atomic.
This doesn't make much sense. (We should remove the last two sentences of this
paragraph.)
(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"? (We should remove the last two sentences of this paragraph.)
(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. (It should be clarified that they are treated as
two sequential actions.)
!proposal
(See Summary.)
!wording
Modify 3.10.2 (26/3):
* The view shall not be a subcomponent that depends on discriminants
of an object unless the object is known to be constrained{;
* The view shall not be a nonatomic subcomponent of an atomic object
(see C.6)}.
Modify 9.10 (1/5):
If two different objects, including nonoverlapping parts of the same
object, are independently addressable, they can be manipulated
concurrently by two different logical threads of control without
synchronization{, unless both are subcomponents of the same atomic
object, and either is nonatomic}.
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 shall not be aliased. A nonatomic subcomponent of an
atomic type or object shall not have components that are specified to
be independently addressable.]
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; --
P : access Integer := Z.X'access --
We permit the type declaration, but disallow the 'Access. This is necessary in
general to avoid breaking privacy, since we might actually have an aliased
component of a component of R, where the component of R is of a private type.
(2) We remove this sentence, and change the rules associated with independent
addressibility in 9.10 to say that threads can safely manipulate independently
addressible components, unless they are subcomponents of the same atomic object,
and either is nonatomic. This also prevents breaking privacy. The existing
sentence could require breaking privacy in certain cases.
(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.
****************************************************************
From: Randy Brukardt
Sent: Monday, April 27, 2020 10:00 PM
AI12-0128-1 enhanced the rules for Atomic such that it can be used to
guarentee that only exact size access is used to access subcomponents of an
atomic composite object.
Recently, a request was made to eliminate some of the requirements of that AI
in order to allow more uses of atomic subcomponents. These can be seen in the
attached AI.
I believe that the changes suggested introduce a major maintenance hazard for
anyone that requires exact size access to some hardware. I'm posting here in
order to give people who are more likely to have that sort of requirement
than me to weigh in on this issue.
The problem as I see it is that to get exact size access to a hardware
register, one has to ensure that no subcomponent has an atomic subtype or is
directly declared atomic. If all of the types involved are declared together,
that's not hard to ensure, but anyone can change a declaration and break the
property. The compiler will not care, since there is no legality rule that is
broken -- just the generated code will change. But of course the generated
code will not work if some smaller access is generated.
If of course some of the types are declared in other units (even something as
simple as a status enumeration), then the verification gets even harder.
Even though the AI worries about breaking privacy, that is irrelevant here as
representation aspects always break privacy (and Atomic is a representation
aspect).
Of course, a need for exact size access is fairly rare, and having rules that
prevent certain types of subcomponents are likely to get in the way of
particular uses. Thus, it might be better to have an aspect to require only
exact size access, and reject any declaration that would violate that.
Otherwise, it seems to me that any exact size requirement is only going to be
followed until the first ham-handed maintainer.
Anyone have any informed thoughts on this topic?
P.S. The next ARG meeting is Wednesday, so a quick response would be
appreciated. If it needs more discussion we can remove it from the agenda of
that meeting.
****************************************************************
Questions? Ask the ACAA Technical Agent