!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; -- Legal? (Yes.) P : access Integer := Z.X'Access -- Legal? (No.) 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. ****************************************************************