!standard C.6(13.3/5) 20-02-05 AI12-0363-1/01 !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 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; -- Legal? (No.) (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: Tucker Taft Sent: Thursday, November 14, 2019 10:22 AM **************************************************************** From: Tucker Taft Sent: Thursday, November 14, 2019 10:22 AM ****************************************************************