CVS difference for ais/ai-00354.txt

Differences between 1.7 and version 1.8
Log of other versions for file ais/ai-00354.txt

--- ais/ai-00354.txt	2004/07/27 23:01:05	1.7
+++ ais/ai-00354.txt	2004/11/14 06:37:19	1.8
@@ -1,4 +1,4 @@
-!standard D.14.2 (01)                                 04-06-25  AI95-00354/05
+!standard D.14.2 (01)                                 04-11-12  AI95-00354/06
 !class amendment 03-09-27
 !status Amendment 200Y 04-06-25
 !status ARG Approved 7-0-1  04-06-13
@@ -11,12 +11,11 @@
 !summary
 
 This AI proposes a child package of Ada.Execution_Time
-(the revised AI 00307) to allow more than one task to share an
-execution-time budget.
+to allow more than one task to share an execution-time budget.
 
 !problem
 
-Currently Ada 95 has no mechanisms to allow the implementation of
+Currently Ada has no mechanisms to allow the implementation of
 aperiodic servers such as sporadic servers and deferrable servers.
 This severely limits the language's ability to handle aperiodic activities
 at anything other than a background priority. The fundamental problem
@@ -44,32 +43,33 @@
 package Ada.Execution_Time.Group_Budgets is
   type Group_Budget is limited private;
 
-  type Handler is not null access
+  type Group_Budget_Handler is access
        protected procedure(GB : in out Group_Budget);
 
   type Task_Array is array(Positive range <>) of
                                   Ada.Task_Identification.Task_ID;
 
   Min_Handler_Ceiling : constant System.Any_Priority :=
-    <Implementation Defined>;
+    *implementation-defined*;
 
   procedure Add_Task(GB: in out Group_Budget;
-                       T : Ada.Task_Identification.Task_ID);
+                       T : in Ada.Task_Identification.Task_ID);
   procedure Remove_Task(GB: in out Group_Budget;
-                       T : Ada.Task_Identification.Task_ID);
+                       T : in Ada.Task_Identification.Task_ID);
   function Is_Member(GB: Group_Budget;
              T : Ada.Task_Identification.Task_ID) return Boolean;
   function Is_A_Group_Member(
              T : Ada.Task_Identification.Task_ID) return Boolean;
   function Members(GB: Group_Budget) return Task_Array;
 
-  procedure Replenish (GB: in out Group_Budget; To : Time_Span);
-  procedure Add(GB: in out Group_Budget; Interval : Time_Span);
+  procedure Replenish (GB: in out Group_Budget; To : in Time_Span);
+  procedure Add(GB: in out Group_Budget; Interval : in Time_Span);
   function Budget_Has_Expired(GB: Group_Budget) return Boolean;
   function Budget_Remaining(GB: Group_Budget) return Time_Span;
 
-  procedure Set_Handler(GB: in out Group_Budget; H : Handler);
-  function Current_Handler(GB: Group_Budget) return Handler;
+  procedure Set_Handler(GB: in out Group_Budget;
+                        Handler : in Group_Budget_Handler);
+  function Current_Handler(GB: Group_Budget) return Group_Budget_Handler;
   procedure Cancel_Handler(GB: in out Group_Budget;
                Cancelled : out Boolean);
 
@@ -79,63 +79,70 @@
 end Ada.Execution_Time.Group_Budgets;
 
 The type Group_Budget represents a CPU budget to be used by a
-group of tasks. This type needs finalization (see 7.6).
+group of tasks. This type needs finalization (see 7.6). A task can
+belong to at most one group. Tasks of any priority can be added to a
+group.
+
+An object of type Group_Budget is said to be *set* if it is associated
+with a (non-null) Group_Budget_Handler and *cleared* otherwise.
+All Group_Budget objects are initially cleared.
+
+An object of type Group_Budget has an associated non-negative
+value of type Time_Span known as the *budget*. The Group_Budget_Handler
+identifies a protected procedure to be executed by the implementation when
+the budget is exhausted.
 
-An object of type Group_Budget is said to be set if it has a
-registered Handler. An object is said to be cleared if it has
-no Handler. All Group_Budget objects are initially cleared.
-
 Dynamic Semantics
+
+The procedure Add_Task adds a task to a group if the task is not a member
+of a group. Otherwise, Group_Budget_Error is raised.
 
-Tasks of any priority are added to a group by calling Add_Task.
-Tasks are members of at most one group. Group_Budget_Error
-is raised by a call to Add_Task if the task is already a member
-of any group.
-
-Tasks are removed from a group by calling Remove_Task.
-An attempt to remove a task that has not been added to the
-group will cause Group_Budget_Error to be raised.
+The procedure Remove_Task removes a task from a group. If the task is not
+a member of the group Group_Budget_Error is raised; otherwise the task is no
+longer a member of any group.
 
-The Is_Member function will return True if the task parameter is
-a member of the specified group. The Is_A_Group_Member function returns
+The function Is_Member returns True if the task T is a member of the
+specified group. The function Is_A_Group_Member returns
 True if the task is a member of any group. Both return False otherwise.
 
-The Members function returns the task IDs of the members of the group.
+The function Members returns an array of the task IDs of the members of the
+group. The order of the components of the array is not specified.
 
-When a call to Replenish is made, the Group_Budget is loaded with the
-Time_Span value passed as a parameter. Any execution of the group of
-tasks results in the Group_Budget counting down. When the budget is
-exhausted (goes to Time_Span_Zero) the handler, if set, is called; the tasks
-continue to execute. A Group_Budget is initially loaded with zero budget.
-
-A call to Budget_Remaining returns the remaining budget. If the budget
-is exhausted it will return Time_Span_Zero. This is the minimum value
-for the budget. A call to Budget_Has_Expired will return True if the
+The procedure Replenish loads a Group_Budget with the Time_Span value
+passed as a parameter. Any execution of any member of the group of
+tasks results in the budget counting down. When the budget becomes
+exhausted (goes to Time_Span_Zero), the associated handler is called if
+the Group_Budget is set; the tasks continue to execute. A Group_Budget is
+initially loaded with zero budget.
+
+The function Budget_Remaining returns the remaining budget. If the budget
+is exhausted it returns Time_Span_Zero. This is the minimum value
+for a budget. The function Budget_Has_Expired returns True if the
 budget is exhausted (equal to Time_Span_Zero), otherwise it returns False.
 
-A Group_Budget can have its budget increased by calling Add. A negative
-value for the parameter will reduce the budget, but never below
-Time_Span_Zero.
-
-A call of Replenish with a non positive value of To will causes exception
-Group_Budget_Error to be raised. A call to Add that results in the value
-of the budget going to Time_Span_Zero will cause the handler, if set,
-to be executed.
-
-A call to Set_Handler registers the Handler and returns when GB is set.
-A call to Set_Handler for a Group_Budget that is already set, initially
-clears the Group_Budget then registers the new Handler.
-
-A call to Current_Handler returns with the current Handler.
-If the Group_Budget denoted by GB is not set, exception Group_Budget_Error
-is raised.
-
-A call to Cancel_Handler returns after the Group_Budget denoted by GB
-is cleared. Cancelled is assigned True if GB was set prior to it
-being cleared; otherwise the parameter is assigned False.
+The procedure Add can be used to increase a budget. A negative
+value for the parameter reduces the budget, but never below
+Time_Span_Zero. A zero value for the parameter has no effect.
+
+A call of procedure Replenish with a non-positive Time_Span value causes
+Group_Budget_Error to be raised. A call of procedure Add that results in
+the value of the budget going to Time_Span_Zero causes the associated
+handler to be called if the Group_Budget is set.
+
+The procedure Set_Handler associates a Group_Budget_Handler with a
+Group_Budget and thereby sets the Group_Budget. A call of Set_Handler for a
+Group_Budget that is already set replaces the handler and the Group_Budget
+remains set. A call with a null value of Handler clears the Group_Budget.
+
+The function Current_Handler returns the Group_Budget_Handler associated
+with the Group Budget if it is set, otherwise it returns null.
+
+The procedure Cancel_Handler clears the Group_Budget if it was set.
+Cancelled is assigned True if the Group_Budget was set prior to it being
+cleared, otherwise it is assigned False.
 
-The constant Min_Handler_Ceiling is the priority value that will insure that
-no ceiling violation will occur when a handler is executed.
+The constant Min_Handler_Ceiling is the priority value that will ensure
+that no ceiling violation will occur when a handler is executed.
 
 The precision of the accounting of task execution time to a Group_Budget
 is the same as that defined for execution-time clocks from the parent
@@ -155,7 +162,24 @@
 
 For a given Group_Budget object, the implementation shall perform the
 operations declared in this package atomically with respect to any
-of these operations on the same Group_Budget object.
+of these operations on the same Group_Budget object. The replacement of
+a handler, by a call of Set_Handler, shall be performed atomically with
+respect to the execution of the Group_Budget_Handler.
+
+AARM note:
+This prevents various race conditions. In particular it ensures that
+if the budget is exhausted when Set_Handler is changing the handler
+then either the new or old handler is executed and the exhausting event
+is not lost.
+End AARM note
+
+Notes
+
+Clearing or setting of a handler does not change the current value of
+the budget. Exhaustion or loading of a budget does not change whether the
+handler is set or cleared.
+
+A Group_Budget_Handler can be associated with several Group_Budget objects.
 
 !example
 
@@ -177,7 +201,7 @@
 
 private
   protected type Controller(DS : access Deferrable_Server) is
-    procedure Budget_Has_Expired(GB: in Group_Budget);
+    procedure Budget_Has_Expired(GB: in out Group_Budget);
     procedure Replenish_Due(TE : in out Timing_Event);
     pragma Priority(Priority'Last);
   end Controller;
@@ -211,7 +235,7 @@
     DS.Period := Period;
     DS.Next_Replenishment_Time := First;
     Group_Budgets.Set_Handler(DS.Budget_Control,
-                              DS.Server_Control.Budget_Expired'Access);
+                              DS.Server_Control.Budget_Has_Expired'Access);
     Timing_Events.Set_Handler(DS.Replenish_Control,
                               DS.Next_Replenishment_Time,
                               DS.Server_Control.Replenish_Due'Access);
@@ -223,7 +247,7 @@
   end Add;
 
   protected body Controller is
-    procedure Budget_Has_Expired(GB : in Group_Budget) is
+    procedure Budget_Has_Expired(GB : in out Group_Budget) is
       TA : Task_Array := Members(GB);
     begin
       for ID in TA'Range loop
@@ -253,12 +277,9 @@
 
 !discussion
 
-Should the Add_Task, Remove_Task have a default task_ID of the current task?
-
-
 Various alternative models were considered including:
 
-a) Passing the Notify protected procedure as an access discriminant
+a) Passing the protected procedure as an access discriminant
 to the Group_Budget type.
 
 This was rejected in favour of explicit get and set methods mainly for ease
@@ -274,7 +295,7 @@
 
 c) Having the Group_Budget type as a tagged type.
 
-This was rejected as the Workshop as unclear on whether the benefit was worth
+This was rejected by the IRTAW as unclear on whether the benefit was worth
 the added complexity and overhead.
 
 d) Having the package automatically suspend the group of tasks when the
@@ -283,6 +304,9 @@
 This was rejected because not all Aperiodic Server approaches
 suspend the tasks, some set the tasks' priorities to a background priority.
 
+e) Making the handler a non null access type. This was eventually rejected
+in favor of unifying the approach used with that in AI-297 on single timers.
+
 !corrigendum D.14.2(01)
 
 @dinsc
@@ -298,7 +322,7 @@
 @b<package> Ada.Execution_Time.Group_Budgets @b<is>
   @b<type> Group_Budget @b<is limited private>;
 
-  @b<type> Handler @b<is not null access>
+  @b<type> Group_Budget_Handler @b<is access>
        @b<protected procedure>(GB : @b<in out> Group_Budget);
 
   @b<type> Task_Array @b<is array>(Positive @b<range> <@>) @b<of>
@@ -308,22 +332,24 @@
     @ft<@i<implementation-defined>>;
 
   @b<procedure> Add_Task(GB: @b<in out> Group_Budget;
-                       T : Ada.Task_Identification.Task_ID);
+                       T : @b<in> Ada.Task_Identification.Task_ID);
   @b<procedure> Remove_Task(GB: @b<in out> Group_Budget;
-                       T : Ada.Task_Identification.Task_ID);
+                       T : @b<in> Ada.Task_Identification.Task_ID);
   @b<function> Is_Member(GB: Group_Budget;
              T : Ada.Task_Identification.Task_ID) @b<return> Boolean;
   @b<function> Is_A_Group_Member(
              T : Ada.Task_Identification.Task_ID) @b<return> Boolean;
   @b<function> Members(GB: Group_Budget) @b<return> Task_Array;
 
-  @b<procedure> Replenish (GB: @b<in out> Group_Budget; To : Time_Span);
-  @b<procedure> Add(GB: @b<in out> Group_Budget; Interval : Time_Span);
+  @b<procedure> Replenish (GB: @b<in out> Group_Budget; To : @b<in> Time_Span);
+  @b<procedure> Add(GB: @b<in out> Group_Budget; Interval : @b<in> Time_Span);
   @b<function> Budget_Has_Expired(GB: Group_Budget) @b<return> Boolean;
   @b<function> Budget_Remaining(GB: Group_Budget) @b<return> Time_Span;
 
-  @b<procedure> Set_Handler(GB: @b<in out> Group_Budget; H : Handler);
-  @b<function> Current_Handler(GB: Group_Budget) @b<return> Handler;
+  @b<procedure> Set_Handler(GB: @b<in out> Group_Budget;
+                         Handler : @b<in> Group_Budget_Handler);
+  @b<function> Current_Handler(GB: Group_Budget)
+                                    @b<return> Group_Budget_Handler;
   @b<procedure> Cancel_Handler(GB: @b<in out> Group_Budget;
                Cancelled : @b<out> Boolean);
 
@@ -333,63 +359,70 @@
 @b<end> Ada.Execution_Time.Group_Budgets;>
 
 The type Group_Budget represents a CPU budget to be used by a
-group of tasks. This type needs finalization (see 7.6).
-
-An object of type Group_Budget is said to be set if it has a
-registered Handler. An object is said to be cleared if it has
-no Handler. All Group_Budget objects are initially cleared.
+group of tasks. This type needs finalization (see 7.6). A task can
+belong to at most one group. Tasks of any priority can be added to a
+group.
+
+An object of type Group_Budget is said to be @i<set> if it is associated
+with a (non-null) Group_Budget_Handler and @i<cleared> otherwise.
+All Group_Budget objects are initially cleared.
+
+An object of type Group_Budget has an associated non-negative
+value of type Time_Span known as the @i<budget>. The Group_Budget_Handler
+identifies a protected procedure to be executed by the implementation when
+the budget is exhausted.
 
 @i<@s8<Dynamic Semantics>>
 
-Tasks of any priority are added to a group by calling Add_Task.
-Tasks are members of at most one group. Group_Budget_Error
-is raised by a call to Add_Task if the task is already a member
-of any group.
-
-Tasks are removed from a group by calling Remove_Task.
-An attempt to remove a task that has not been added to the
-group will cause Group_Budget_Error to be raised.
+The procedure Add_Task adds a task to a group if the task is not a member
+of a group. Otherwise, Group_Budget_Error is raised.
 
-The Is_Member function will return True if the task parameter is
-a member of the specified group. The Is_A_Group_Member function returns
+The procedure Remove_Task removes a task from a group. If the task is not
+a member of the group Group_Budget_Error is raised; otherwise the task is no
+longer a member of any group.
+
+The function Is_Member returns True if the task T is a member of the
+specified group. The function Is_A_Group_Member returns
 True if the task is a member of any group. Both return False otherwise.
 
-The Members function returns the task IDs of the members of the group.
+The function Members returns an array of the task IDs of the members of the
+group. The order of the components of the array is not specified.
 
-When a call to Replenish is made, the Group_Budget is loaded with the
-Time_Span value passed as a parameter. Any execution of the group of
-tasks results in the Group_Budget counting down. When the budget is
-exhausted (goes to Time_Span_Zero) the handler, if set, is called; the tasks
-continue to execute. A Group_Budget is initially loaded with zero budget.
-
-A call to Budget_Remaining returns the remaining budget. If the budget
-is exhausted it will return Time_Span_Zero. This is the minimum value
-for the budget. A call to Budget_Has_Expired will return True if the
+The procedure Replenish loads a Group_Budget with the Time_Span value
+passed as a parameter. Any execution of any member of the group of
+tasks results in the budget counting down. When the budget becomes
+exhausted (goes to Time_Span_Zero), the associated handler is called if
+the Group_Budget is set; the tasks continue to execute. A Group_Budget is
+initially loaded with zero budget.
+
+The function Budget_Remaining returns the remaining budget. If the budget
+is exhausted it returns Time_Span_Zero. This is the minimum value
+for a budget. The function Budget_Has_Expired returns True if the
 budget is exhausted (equal to Time_Span_Zero), otherwise it returns False.
 
-A Group_Budget can have its budget increased by calling Add. A negative
-value for the parameter will reduce the budget, but never below
-Time_Span_Zero.
-
-A call of Replenish with a non positive value of To will causes exception
-Group_Budget_Error to be raised. A call to Add that results in the value
-of the budget going to Time_Span_Zero will cause the handler, if set,
-to be executed.
-
-A call to Set_Handler registers the Handler and returns when GB is set.
-A call to Set_Handler for a Group_Budget that is already set, initially
-clears the Group_Budget then registers the new Handler.
-
-A call to Current_Handler returns with the current Handler.
-If the Group_Budget denoted by GB is not set, exception Group_Budget_Error
-is raised.
-
-A call to Cancel_Handler returns after the Group_Budget denoted by GB
-is cleared. Cancelled is assigned True if GB was set prior to it
-being cleared; otherwise the parameter is assigned False.
+The procedure Add can be used to increase a budget. A negative
+value for the parameter reduces the budget, but never below
+Time_Span_Zero. A zero value for the parameter has no effect.
+
+A call of procedure Replenish with a non-positive Time_Span value causes
+Group_Budget_Error to be raised. A call of procedure Add that results in
+the value of the budget going to Time_Span_Zero causes the associated
+handler to be called if the Group_Budget is set.
+
+The procedure Set_Handler associates a Group_Budget_Handler with a
+Group_Budget and thereby sets the Group_Budget. A call of Set_Handler for a
+Group_Budget that is already set replaces the handler and the Group_Budget
+remains set. A call with a null value of Handler clears the Group_Budget.
+
+The function Current_Handler returns the Group_Budget_Handler associated
+with the Group Budget if it is set, otherwise it returns null.
+
+The procedure Cancel_Handler clears the Group_Budget if it was set.
+Cancelled is assigned True if the Group_Budget was set prior to it being
+cleared, otherwise it is assigned False.
 
-The constant Min_Handler_Ceiling is the priority value that will insure that
-no ceiling violation will occur when a handler is executed.
+The constant Min_Handler_Ceiling is the priority value that will ensure
+that no ceiling violation will occur when a handler is executed.
 
 The precision of the accounting of task execution time to a Group_Budget
 is the same as that defined for execution-time clocks from the parent
@@ -409,7 +442,17 @@
 
 For a given Group_Budget object, the implementation shall perform the
 operations declared in this package atomically with respect to any
-of these operations on the same Group_Budget object.
+of these operations on the same Group_Budget object. The replacement of
+a handler, by a call of Set_Handler, shall be performed atomically with
+respect to the execution of the Group_Budget_Handler.
+
+@xindent<@s9<NOTES@hr
+Clearing or setting of a handler does not change the current value of
+the budget. Exhaustion or loading of a budget does not change whether the
+handler is set or cleared.>>
+
+@xindent<@s9<A Group_Budget_Handler can be associated with several
+Group_Budget objects.>>
 
 
 !ACATS test

Questions? Ask the ACAA Technical Agent