!standard C.7.1(4/3) 19-02-22 AI12-0316-1/01 !standard D.2.6(9/5) !standard D.2.6(29/2) !standard D.5.1(4) !standard D.5.1(5) !standard D.5.1(9) !standard D.11(3/5) !standard D.11(9) !standard D.14(5/2) !standard D.14(17/2) !class Amendment 19-02-22 !status work item 19-02-22 !status received 19-02-007 !priority Low !difficulty Easy !subject Preconditions for checking Task_Ids !summary Preconditions, rather than wording, is used to check Task_Ids in various Annex D subprograms. !problem Ada 2020 is attempting to use preconditions and postconditions as much as possible. The following rule appears in a number of places in Annex D: For all the operations defined in <>, Tasking_Error is raised if the task identified by T has terminated. Program_Error is raised if the value of T is Null_Task_Id. This would be better described by a precondition. !proposal Add function Valid_Task to Ada.Task_Identification, and then use that in preconditions in Annex D. !wording Split C.7.1(4/3) before "private", and add between the existing paragraphs: function Valid_Task (T : in Task_Id) return Boolean is (if T = Null_Task_Id then raise Program_Error elsif Terminated(T) then raise Tasking_Error); Add: with Pre => Ada.Task_Identification.Valid_Task (T); to Set_Deadline, Get_Deadline, Set_Relative_Deadline, Get_Relative_Deadline, Get_Last_Release_Time in D.2.6(9/5); to Set_Priority in D.5.1(4); to Get_Priority in D.5.1(5); to Hold, Continue, and Is_Held in D.11(3/5); and to Clock in D.14(5/2). Replace in AARM D.5.1(12.a) "the above rule saying" with "the precondition". Delete D.2.6(29/2), D.5.1(9), D.11(8). Modify D.14(17/2): The function Clock returns the current execution time of the task identified by T[; Tasking_Error is raised if that task has terminated; Program_Error is raised if the value of T is Task_Identification.Null_Task_Id]. !discussion !ASIS [Not sure. It seems like some new capabilities might be needed, but I didn't check - Editor.] !ACATS test ACATS B- and C-Tests are needed to check that the new capabilities are supported. !appendix From: Randy Brukardt Sent: Thursday, February 7, 2019 11:42 PM AI12-0230-1 completely replaces the existing definition of package Ada.Dispatching.EDF. It also has the following paragraph: For all the operations defined in Dispatching.EDF, Tasking_Error is raised if the task identified by T has terminated. Program_Error is raised if the value of T is Null_Task_Id. (which is pretty much the only unchanged paragraph, but I digress). This seems to be a (and backwards, IMHO, you have to test null before termination) way to write: Pre => (if T = Ada.Task_Identification.Null_Task_Id then raise Program_Error elsif Ada.Task_Identification.Terminated(T) then raise Tasking_Error); Would the real-time folks freak out like they did when we replaced all of their pragmas with aspects if we put these on each subprogram (there are 5, I think)? Or if these are too large, declaring an expression function: function Valid_Task (T : in Ada.Task_Identification.Task_Id) return Boolean is (if T = Ada.Task_Identification.Null_Task_Id then raise Program_Error elsif Ada.Task_Identification.Terminated(T) then raise Tasking_Error); in the package and then putting Pre => Valid_Task (T); on each subprogram?? Since we're changing this package and the subclause it lives in anyway, we probably ought to bring it up to current standards for new packages (and that means no English-language preconditions). Note that manay of the packages in Annex D have a similar rule; we're not going to change them all now, but ultimately that would be a good idea. Thoughts? Brickbats? **************************************************************** From: Arnaud Charlet Sent: Friday, February 8, 2019 3:22 AM I guess this makes sense from a language point of view. From a pragmatic point of view this will have zero impact on users since this package (Ada.Dispatching.EDF) isn't supported by any Ada compiler. **************************************************************** From: Tucker Taft Sent: Friday, February 8, 2019 10:25 AM Your suggestion seems fine. I would create Valid_Task only if it is needed several times (e.g. 4 or more times). I would think Valid_Task might want to be defined in Task_Identification, if we define it. **************************************************************** From: Tullio Vardanega Sent: Friday, February 8, 2019 10:44 AM As one of the "real-time folks", I am with Tuck in liking your suggestion, including his advice to create Valid_Task only if it warrants factoring enough instances. On the whole, using the Pre aspect fits the case and also makes sense pedagogically. **************************************************************** From: Randy Brukardt Sent: Friday, February 8, 2019 4:25 PM > Your suggestion seems fine. I would create Valid_Task only if it is > needed several times (e.g. 4 or more times). There are 5 uses in EDF alone. Many other packages in Annex D have the same rule (pretty much every one that takes a Task_Id as a parameter). > I would think Valid_Task might want to be defined in > Task_Identification, if we define it. That sounds like a good idea, I was trying to figure out how to generalize that since it is clearly not limited to EDF. (Specifically, Execution_Time has one such routine; Asynchronous_Task_Control has three such routines; and Dynamic_Priorities has three such routines.) I'll write up an AI for this for the March meeting (past the deadline for Monday's meeting). **************************************************************** From: Steve Baird Sent: Friday, February 8, 2019 5:43 PM > There are 5 uses in EDF alone. Many other packages in Annex D have the > same rule (pretty much every one that takes a Task_Id as a parameter). This amount of repetition suggests that it would be better to define a subtype with a predicate (and a Predicate_Failure aspect) and then use that subtype as needed. The problem with that approach is that conceivably there could be a compatibility issue. Changing the subtype of a parameter or a function result can affect subtype conformance, whereas adding a precondition or postcondition won't. If it weren't for this issue, I would certainly argue for a subtype. And I would ignore compatibility issues if we were only talking about EDF because, as Arno pointed out, EDF isn't supported by any Ada compiler. But, as Randy pointed out, this issue comes up elsewhere and we probably should address the problem uniformly. For compatibility reasons, we certainly would not want to consider changing the subtype of the Task_Id parameter mentioned in the access-to-protected-procedure type Ada.Task_Termination.Termination_Handler. Interestingly, invoking Asynchronous_Task_Control.Is_Held with a null task id appears to be erroneous (as opposed to raising an exception). These are examples of the cases that would need to be looked at. **************************************************************** From: Randy Brukardt Sent: Friday, February 8, 2019 5:43 PM ... > Interestingly, invoking Asynchronous_Task_Control.Is_Held with a null > task id appears to be erroneous (as opposed to raising an exception). D.11(8) seems to apply to Is_Held as well as Hold and Continue, so I don't know why you say that. One could ask if we really want it to do so (typically, with boolean functions you just want to return False for nonsense parameters rather than raising an exception), but in any case I would not be looking to change any semantics in this AI. > These are examples of the cases that would need to be looked at. > > Thoughts? I think Tucker's suggestion is best, because these are existing subprograms. I don't think these are likely to be used in 'Access or one of the other 11 places that subtype conformance is required (according to the index), but it seems possible enough that I'd avoid the predicate. I'd only use a subtype predicate on a new subprogram/package, since there isn't enough benefit to writing these as contracts to take any incompatibility whatsoever. **************************************************************** From: Steve Baird Sent: Friday, February 8, 2019 6:18 PM My mistake - I was misremembering the error condition in D.11(9) as something more like "does not specify an existing task" . And I agree with you on the larger point of avoiding incompatibilities when we are talking about existing code. ****************************************************************