!standard 9.5(9) 08-02-25 AI05-0030-2/03 !standard 9.5.4(2) !standard 9.5.4(3) !standard 9.5.4(5) !standard 9.5.4(6) !standard 9.5.4(7) !standard 9.5.4(12) !class Binding Interpretation 06-10-13 !status ARG Approved 6-0-2 08-02-09 !status work item 06-10-13 !status received 06-10-13 !priority Medium !difficulty medium !subject Requeue on synchronized interfaces !summary Requeue is permitted to a synchronized, task, or protected interface if it is known that the operation is an entry. A new pragma is provided to accomplish this. !problem The inability to requeue to a synchronized, task or protected interface is a serious drawback when trying to produce general-purpose real-time utilities. Its inclusion would further the integration of the OO and concurrency features of the language. !proposal The proposal is to allow requeue to procedures defined in synchronized, task, or protected interfaces provided that the pragma Implemented specifies that the procedure is implemented by an entry. !wording Add after 9.5(9) Syntax The form of a pragma Implemented is as follows pragma Implemented(*procedure_*local_name, implementation_kind); implementation_kind ::= By_Entry | By_Protected_Procedure | By_Any Legality Rules The *procedure_*local_name of a pragma Implemented shall denote a primitive procedure of a synchronized tagged type. AARM Ramification: The *procedure_*local_name can denote more than one such procedure if there are several overloaded routines. No functions can be denoted, even if one or more procedures are also denoted. A pragma Implemented with implementation_kind By_Protected shall not be applied to a primitive procedure of a task interface. A procedure for which the implementation_kind is specified as By_Entry shall be implemented by an entry. A procedure for which the implementation_kind is specified as By_Protected_Procedure shall be implemented by a protected procedure. If a primitive procedure overrides an inherited operation to which a pragma Implemented applies then any pragma Implemented applied to the overriding operation shall have the same implementation_kind or the inherited implementation_kind shall be By_Any. In addition to the places where Legality Rules normally apply (see 12.3), these rules apply also in the private part of an instance of a generic unit. Static Semantics A pragma Implemented is said to *apply* to the procedure denoted by its *procedure_*local_name. If an overriding operation does not have a pragma Implemented then any pragma Implemented applying to the inherited operation applies to the overriding operation. NOTE 18 The implementation_kind By_Protected_Procedure implies that the operation will not block. Replace 9.5.4(2-3): requeue_statement ::= requeue *procedure_or_entry_*name [with abort]; Name Resolution Rules The *procedure_or_entry_*name of a requeue_statement shall resolve to denote a procedure or an entry (the requeue target) that either has no parameters, or that has a profile that is type conformant (see 6.3.1) with the profile of the innermost enclosing entry_body or accept_statement. Replace 9.5.4(5): If the requeue target has parameters, then its profile shall be subtype conformant with the profile of the innermost enclosing callable construct. If the target is a procedure, the name shall denote a rename of an entry, or shall denote a prefixed view of a primitive subprogram of a synchronized interface, where the first parameter of the unprefixed view of the primitive subprogram shall be a controlling parameter, and a pragma Implemented with implementation_kind By_Entry shall apply to the primitive subprogram. Modify 9.5.4(6) as follows: "...entry_declaration {for the entry_body}." Modify 9.5.4(7) as follows: The execution of a requeue_statement proceeds by first evaluating the [*entry_*name]{*procedure_or_entry_*name} ... Modify 9.5.4(12) as follows: If the [new entry]{requeue target} named in the requeue_statement has parameters, then during the execution of an accept_statement or entry_body corresponding to a new entry ... !discussion A previous alternative of this AI (0030-1) regarding this problem permitted the requeue syntactically and then had to resolve what would happen if the target turned out to be implemented by a procedure and not by an entry. This introduced bounded errors and looked difficult to implement. Accordingly, this version takes a more static view. We need to ensure that the requeue will always turn out to be on an entry and not on a procedure or protected procedure. Ideally, this should be done by new syntax which introduces entry into the profile of the interface. For example type Server is synchronized interface; entry Q(S: in out Server; X: Item); However, this approach could not be classed as a binding interpretation but would have to be an Amendment. Accordingly a pragma is proposed which can be used thus type Server is synchronized interface; procedure Q(S: in out Server; X: Item); pragma Implemented(Q, By_Entry); For completeness, the pragma can also take parameters, By_Protected_Procedure or By_Any. By_Protected_Procedure means that it has to be implemented by a protected procedure and By_Any means it can be implemented by a normal procedure, a protected procedure or by an entry (these might be useful documentation aids). In particular, if it is known that an operation is implemented by a protected procedure then it can be deduced that the operation will not block under normal circumstances (eg on a monoprocessor). The pragma can also be applied to task and protected interfaces. In the former case By_Protected_Procedure is not permitted. If an interface inherits an operation from another interface and the inherited operation is subject to a pragma Implemented then that property is inherited. It can be specified again but must not conflict. By_Any can be overridden by By_Entry or By_Protected_Procedure but in other cases the parameter must match. And of course a task interface cannot inherit operations to which By_Protected_Procedure applies. For example if we have type Server is synchronized interface; procedure Q(S: in out Server; X: Item); pragma Implemented(Q, By_Protected_Procedure); then it is illegal to write type T_Server is task interface and Server; -- illegal Since it is statically determined we now permit a requeue on an entry renamed as a procedure. The boilerplate for checking in the private part of a generic is necessary so that derivations from formal interfaces and from formal derived types do not violate these rules. For example: generic type Sync is synchronized interface; package Gen is ... private type New_Sync is new Sync with ...; procedure Flub (Obj : in New_Sync; ...); pragma Implemented(Flub, By_Entry); -- OK. end Gen; type Gag is synchonized interface; procedure Flub (Obj : in Gag; ...); pragma Implemented(Flub, By_Protected_Procedure); package Inst is new Gen (Gag); -- Error: In this case, procedure Flub in the instance has conflicting pragma Implemented that apply to it; this must be detected. We don't need assume-the-worst rules for generic bodies because derivation from formal tagged types is illegal in bodies by 3.9.1(4/2). When discussed at the IRTAW the need to requeue via interface procedures implemented by entries was strongly supported. However there was no wish to have requeue to a procedure so the proposal of this present AI covers the perceived need. !example See the paper 'Integrating OOP and Tasking - the missing requeue' by Wellings and Burns (IRTAW2007), previously circulated. Find it at http://www.ada-auth.org/ai-files/grab_bag/requeue.pdf. !corrigendum 9.5(9) @dinsa Any call on a protected procedure or entry of a target protected object is defined to be an update to the object, as is a requeue on such an entry. @dinss @s8<@i> The form of a @fa Implemented is as follows @b Implemented(@i@fa, @fa); @fa ::= By_Entry | By_Protected_Procedure | By_Any @s8<@i> The @i@fa of a pragma Implemented shall denote a primitive procedure of a synchronized tagged type. A @fa Implemented with @fa By_Protected shall not be applied to a primitive procedure of a task interface. A procedure for which the @fa is specified as By_Entry shall be implemented by an entry. A procedure for which the @fa is specified as By_Protected_Procedure shall be implemented by a protected procedure. If a primitive procedure overrides an inherited operation to which a @fa Implemented applies then any @fa Implemented applied to the overriding operation shall have the same @fa or the inherited @fa shall be By_Any. In addition to the places where Legality Rules normally apply (see 12.3), these rules apply also in the private part of an instance of a generic unit. @s8<@i> A @fa Implemented is said to @i to the procedure denoted by its @i@fa. If an overriding operation does not have a @fa Implemented then any @fa Implemented applying to the inherited operation applies to the overriding operation. NOTE @s9<18 The @fa By_Protected_Procedure implies that the operation will not block.> !corrigendum 9.5.4(2) @drepl @xcode<@fa@ft<@b entry_>@fa@ft<@b>@fa<];>> @dby @xcode<@fa@ft<@b procedure_or_entry_>@fa@ft<@b>@fa<];>> !corrigendum 9.5.4(3) @drepl The @i@fa of a @fa shall resolve to denote an entry (the @i) that either has no parameters, or that has a profile that is type conformant (see 6.3.1) with the profile of the innermost enclosing @fa or @fa. @dby The @i@fa of a @fa shall resolve to denote a procedure or an entry (the @i) that either has no parameters, or that has a profile that is type conformant (see 6.3.1) with the profile of the innermost enclosing @fa or @fa. !corrigendum 9.5.4(5) @drepl If the target entry has parameters, then its profile shall be subtype conformant with the profile of the innermost enclosing callable construct. @dby If the requeue target has parameters, then its profile shall be subtype conformant with the profile of the innermost enclosing callable construct. If the target is a procedure, the name shall denote a rename of an entry, or shall denote a prefixed view of a primitive subprogram of a synchronized interface, where the first parameter of the unprefixed view of the primitive subprogram shall be a controlling parameter, and a pragma Implemented with @fa By_Entry shall apply to the primitive subprogram. !corrigendum 9.5.4(6) @drepl In a @fa of an @fa of some task unit, either the target object shall be a part of a formal parameter of the @fa, or the accessibility level of the target object shall not be equal to or statically deeper than any enclosing @fa of the task unit. In a @fa of an @fa of some protected unit, either the target object shall be a part of a formal parameter of the @fa, or the accessibility level of the target object shall not be statically deeper than that of the @fa. @dby In a @fa of an @fa of some task unit, either the target object shall be a part of a formal parameter of the @fa, or the accessibility level of the target object shall not be equal to or statically deeper than any enclosing @fa of the task unit. In a @fa of an @fa of some protected unit, either the target object shall be a part of a formal parameter of the @fa, or the accessibility level of the target object shall not be statically deeper than that of the @fa for the @fa. !corrigendum 9.5.4(7) @drepl The execution of a @fa proceeds by first evaluating the @i@fa, including the @fa identifying the target task or protected object and the @fa identifying the entry within an entry family, if any. The @fa or @fa enclosing the @fa is then completed, finalized, and left (see 7.6.1). @dby The execution of a @fa proceeds by first evaluating the @i@fa, including the @fa identifying the target task or protected object and the @fa identifying the entry within an entry family, if any. The @fa or @fa enclosing the @fa is then completed, finalized, and left (see 7.6.1). !corrigendum 9.5.4(12) @drepl If the new entry named in the @fa has formal parameters, then during the execution of the @fa or @fa corresponding to the new entry, the formal parameters denote the same objects as did the corresponding formal parameters of the callable construct completed by the requeue. In any case, no parameters are specified in a @fa; any parameter passing is implicit. @dby If the requeue target named in the @fa has formal parameters, then during the execution of the @fa or @fa corresponding to the new entry, the formal parameters denote the same objects as did the corresponding formal parameters of the callable construct completed by the requeue. In any case, no parameters are specified in a @fa; any parameter passing is implicit. !ACATS test Create ACATS tests to check that the above changes work. B-Tests are needed for the legality rules and C-Tests for actual dispatching requeuing. !appendix From: Randy Brukardt Sent: Friday, January 4, 2008 6:42 PM John writes: > Attached is the AI on requeue. It has been reviewed by Tucker and Alan so > has a fair chance of being reasonable. The basic idea seems OK, but it seems to have some issues in the details. (Oooo, and it is such fun to play editor with someone else's creation for a change. :-) It's always disappointing to have people pick apart your carefully crafted text...even if they're right.) You have: > Legality Rules > > The *procedure_*local_name of a pragma Implemented shall denote a > dispatching operation of a synchronized interface. > The dispatching operation shall not be a function. It could denote more than one such operation if there is overloading. Is that intended/allowed? Do we need to say something about it? I'd think that there should be at least an AARM note or some discussion on this topic (it is one of the main reasons that syntax is *so* much better.) > Static Semantics > > An operation for which the implementation_kind is specified as By_Entry > shall be implemented by an entry. An operation for which the > implementation_kind is specified as By_Protected_Procedure shall be > implemented by a protected procedure. > > If a dispatching operation overrides an inherited operation to which a > pragma Implemented applies then any pragma Implemented applied to the > overriding operation shall not conflict with regard to the > implementation_kind. Both implementation_kinds shall be the same or the > inherited implementation_kind shall be By_Any. If an overriding operation > does not have a pragma Implemented then any pragma Implemented applying to > the inherited operation shall apply to the overriding operation. Most of this seems to be Legality Rules, not Static Semantics. Surely, if you have a rule that says that a Blah shall be a Glorp, that's a legality rule. It surely needs an ACATS test to check that violations are detected. Only the very last sentence seems to be a Static Semantics rule, so it probably should be in a separate paragraph. And I'd keep "shall" out of it. This pragma is fairly similar in semantics to No_Return, so I'd probably try to copy that wording. (And, indeed, this is fairly similar to No_Return's wording.) I'm not certain that what it means for a pragma to "apply" is clearly defined anywhere other than in the inheritance case. We probably need a sentence like "The pragma Implemented applies to the subprograms denoted by the procedure_local_name". The first two sentences of the second paragraph say the same thing (the latter probably being the formal definition. I wonder if they can be combined (dropping the part about "shall not conflict" -- that's for your book!) > NOTE > > 18 The implementation_kinds By_Protected_Procedure and By_Any may be used > as documentation aids. Does this note tell the reader something interesting? It does not seem so to me (we don't need a note in the RM to help justify the AI, nor to say something obvious). It would make more sense for the note to say something similar to what the discussion does: "In particular, if it is known that an operation is implemented by a protected procedure then it can be deduced that the operation will not block under normal circumstances (eg on a monoprocessor)." ...which seems like a useful statement. In the change to 9.5.4(2-5): > ...and the pragma Implement with implementation_kind By_Entry > shall apply to the primitive subprogram. I think this ought to be "pragma Implemented"; there is no pragma Implement. I don't see any change to 9.5.4(4); probably it shouldn't be in the changed text because it is a real time-waster to look at it over and over trying to see what is different. (That is, the changes to 9.5.4(2-3) and 9.5.4(5) should be given separately.) Annex L is automatically created, and we rarely talk about it in AIs (the notion that it and Annex K get updated is just assumed). So I'd just drop that sentence. The first paragraph of the discussion has "bounded errora". Baird-type question: You say in the discussion that "...then it is illegal to write type T_Server is task interface and Server; -- illegal Since it is statically determined we now permit a requeue on an entry renamed as a procedure." This seems like it could be a contract issue for formal interfaces and formal derived types. It seems like we would want assume-the-best + recheck rules for occurrences in a generic specification. (Luckily, deriving from these things is illegal in a body.) At a very minimum, we need the boilerplate line about the legality rules being checked in the private part. (Indeed, that needs to be considered for all of these new legality rules.) One example would be something like: generic type Sync is synchronized interface; package Gen is ... private type New_Sync is new Sync with ...; procedure Flub (Obj : in New_Sync; ...); pragma Implemented(Flub, By_Entry); -- OK (I hope so). end Gen; type Garg is synchonized interface; procedure Flub (Obj : in Garg; ...); pragma Implemented(Flub, By_Protected_Procedure); package Inst is new Gen (Garg); -- !! There better be an error here (because of the Implemented mismatch in the derived type), and there won't be without the boilerplate. There is also the other way to consider - is there a problem requeuing onto an inherited operation of a generic formal derived type? (I don't think so.) > Javier Miranda has indicated that he is prepared > to develop a prototype implementation to evaluate the impact of > such a proposal.) There is at least a stray ")" here. But I wonder if this is true. This seems to have been copied from the original AI, and it was talking only about the requeue itself (and the impact on the runtime system). Are we sure that anyone is planning to evaluate the impact of the pragmas (which seem to be as much work to implement as the actual requeue, and are in a very different part of the compiler)? If not, this should say something different to restrict it to what the actual promise was. Finally, the !appendix is copied from the original alternative. It should be empty (other than this note!) - mail only appears once. ****************************************************************