CVS difference for ais/ai-00354.txt

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

--- ais/ai-00354.txt	2003/10/29 22:54:14	1.2
+++ ais/ai-00354.txt	2003/11/27 02:01:16	1.3
@@ -1,16 +1,16 @@
-!standard D.03 (00)                                   03-09-27  AI95-00354/01
+!standard D.03 (00)                                   03-11-24  AI95-00354/02
 !class amendment 03-09-27
 !status work item 03-09-27
 !status received 03-09-27
 !priority Low
 !difficulty Medium
-!subject Group Execution-Time Timers
+!subject Group Execution-Time Budgets
 
 !summary
 
-This AI proposes an child package of Ada.Real_Time.Execution_Time
+This AI proposes a child package of Ada.Real_Time.Execution_Time
 (the revised AI 00307) to allow more than one task to share an
-execution-time timer.
+execution-time budget.
 
 !problem
 
@@ -23,81 +23,141 @@
 
 !proposal
 
-Add new section: Group Execution Time Timers
+(See wording.)
 
+!wording
+
+Add new section:
+
+D.14.1 Group Execution Time Budgets
+
+This clause specifies a group execution time control package.
+
+Static Semantics
+
+The following language-defined library package exists:
+
+with System;
 with Ada.Task_Identification;
-package Ada.Real_Time.Execution_Time.Group_Timers is
-  type Group_Timer is limited private;
+package Ada.Real_Time.Execution_Time.Group_Budgets is
+  type Group_Budget is limited private;
 
-  type Notify is access protected procedure(GT : in out Group_Timer);
+  type Handler is access protected procedure(GB : in out Group_Budget);
 
-  Min_Notify_Ceiling : constant System.Any_Priority :=
+  type Task_Group is array(Natural range <>) of
+                                  Ada.Task_Identification.Task_ID;
+
+  Min_Handler_Ceiling : constant System.Any_Priority :=
     <Implementation Defined>;
+
+  procedure Set_Handler(GB: in out Group_Budget; H : Handler);
+  function Current_Handler(GB: Group_Budget) return Handler;
 
-  procedure Set_Notify(GT: in out Group_Timer; Signal : Notify);
-  function Get_Notify(GT: Group_Timer) return Notify;
+  procedure Replenish (GB: in out Group_Budget; To : Time_Span);
+  procedure Add(GB: in out Group_Budget; Interval : Time_Span);
 
-  procedure Replenish (GT: in out Group_Timer; Interval : Time_Span);
-  procedure Add(GT: in out Group_Timer; Interval : Time_Span);
+  procedure Add_Task(GB: in out Group_Budget;
+                       T : Ada.Task_Identification.Task_ID);
+  procedure Remove_Task(GB: in out Group_Budget;
+                       T : Ada.Task_Identification.Task_ID);
+  function Is_Member(GB: Group_Budget;
+             T : Ada.Task_Identification.Task_ID) return Boolean;
+  function Is_Member(
+             T : Ada.Task_Identification.Task_ID) return Boolean;
 
-  procedure Add_Task(GT: in out Group_Timer;
-                       Tid : Ada.Task_Identification.Task_ID);
-  procedure Remove_Task(GT: in out Group_Timer;
-                       Tid : Ada.Task_Identification.Task_ID);
-  function Is_Member(GT: Group_Timer;
-             Tid : Ada.Task_Identification.Task_ID) return Boolean;
+  function Budget_Has_Expired(GB: Group_Budget) return Boolean;
+  function Budget_Remaining(GB: Group_Budget) return Time_Span;
 
-  function Budget_Has_Expired(GT: Group_Timer) return Boolean;
-  function Budget_Remaining(GT: Group_Timer) return Time_Span;
+  function Members(GB: Group_Budget) return Task_Group;
 
-  Group_Timer_Error : exception;
+  Group_Budget_Error : exception;
 private
     --  not specified by the language
-end Ada.Real_Time.Execution_Time.Group_Timers;
+end Ada.Real_Time.Execution_Time.Group_Budgets;
+
+The type Group_Budget represents a CPU budget to be
+used by a group of tasks.
+
+Dynamic Semantics
+
+Tasks of any priority can be added to a group by calling Add_Task.
+Tasks can be the member 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 can be 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 type Group_Timer represents a timer (decrementer) which measures the
-CPU time used by a group of tasks. Tasks of any priority can be added to
-a group by calling Add_Task.  Tasks can be subtracted from the
-group by calls to Remove_Task. An attempt to remove a task that has
-not been added to the Group_Timer will cause Group_Timer_Error to
-be raised.
-
-When the Group_Timer goes to zero a call
-is made to a protected procedure. This procedure can be set by the
-Set_Notify subprogram. The subprogram Get_Notify allows the current
-procedure to be obtained. A call to Set_Notify for a Group_Timer that
-is already set resets the Group_Timer.
+The first Is_Member function will return True if the task parameter is
+a member of the specified group. The other Is_Member function returns
+True if the task is a member of any group. Both return False otherwise.
 
-The constant Min_Notify_Ceiling indicates the minimum ceiling
+When the Group_Budget is exhausted a call is made to a protected
+procedure. This procedure can be set by the Set_Handler subprogram.
+The subprogram Current_Handler allows the current procedure to be obtained.
+A call to Set_Handler for a Group_Budget that is already set, resets
+the handler.
+
+The constant Min_Handler_Ceiling indicates the minimum ceiling
 priority that must be assigned to any protected object associated with
-the Notify protected procedure.
+the Handler protected procedure.
 
-A Group_Timer is initially without budget. The Notify protected
+A Group_Budget is initially without budget. The Handler protected
 procedure is initially null.
 
-When a call to Replenish is made, the Group_Timer is loaded with the interval
+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 result in the Group_Timer counting down. When the budget is exhausted,
-Signal is called but the tasks continue to execute.
+tasks results in the Group_Budget counting down. When the budget is
+exhausted (goes to Time_Span_Zero), the handler is called; the tasks
+continue to execute.
 
-A Group_Timer can have its budget increased by calling Add.
+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
+budget is exhausted (equal to Time_Span_Zero), otherwise it returns False.
 
-The precision of the the Group_Timer is the same as that of Timers
-from the parent package.
+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 to be executed.
 
-!wording
+The Members function returns the task IDs of the members of the group.
+
+The precision of the accounting of task execution time to a Group_Budget
+is the same as that of Timers from the parent package.
+
+As part of the finalization of an object of type Group_Budget all
+tasks are removed from the group identified by the object.
+
+If restriction No_Nested_Finalization is in effect Group_Budget objects
+can only be defined at the library level.
+
+If a task is a member of a Group_Budget when it terminates then as part of
+the finalization of the task it is removed from the group.
 
+For all the operations and types defined in this package, 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.
 
+
+Implementation Requirements
+
+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.
+
 !example
 
-One common bandwidth preserving is the deferrable server.
-The code for a simple deferrable server is given
-below:
+One common bandwidth preserving technique is the deferrable server.
+The code for a simple deferrable server is given below:
 
 with Ada.Timing_Events; use Ada.Timing_Events;
-with Ada.Execution_Time.Group_Timers;
-use Ada.Execution_Time.Group_Timers;
+with Ada.Real_Time.Execution_Time.Group_Budgets;
+use Ada.Real_Rime.Execution_Time.Group_Budgets;
 with Ada.Task_Identification; use Ada.Task_Identification;
 with Ada.Real_Time; use Ada.Real_Time;
 with System; use System;
@@ -110,7 +170,7 @@
 
 private
   protected type Controller(DS : access Deferrable_Server) is
-    procedure Budget_Expired(T: in out Group_Timer);
+    procedure Budget_Expired(GB: in out Group_Budget);
     procedure Replenish_Due(TE : in out Timing_Event);
     pragma Priority(Priority'Last);
   end Controller;
@@ -120,21 +180,21 @@
     Period : Time_Span;
     Next_Replenishment_Time : Time;
     Replenish_Control : Timing_Event;
-    Budget_Control : Group_Timer;
+    Budget_Control : Group_Budget;
     Server_Control : Controller(Deferrable_Server'Access);
   end record;
 end Deferrable_Servers;
 
 A deferrable server can be represented by a type which encapsulated
 the Budget, the replenishment period, the next replenishment time,
-a Timing_Event to signal the next replenishment time, a Group_Timer
+a Timing_Event to signal the next replenishment time, a Group_Budget
 to monitor the execution time consumed by the controlled tasks,
 and a controller to perform the required suspension and resumption
 of the tasks.
 
 The body of the package is given below.
 
-with Ada.Asynchronous_Control; use Ada.Asynchronous_Control;
+with Ada.Asynchronous_Task_Control; use Ada.Asynchronous_Task_Control;
 package body Deferrable_Servers is
 
   procedure Create(DS : in out Deferrable_Server; First : Time;
@@ -143,8 +203,8 @@
     DS.Budget := Budget;
     DS.Period := Period;
     DS.Next_Replenishment_Time := First;
-    Set_Notify_Procedure(DS.Budget_Control,
-                         DS.Server_Control.Budget_Expired'Access);
+    Group_Budgets.Set_Handler(DS.Budget_Control,
+                              DS.Server_Control.Budget_Expired'Access);
     Timing_Events.Set_Handler(DS.Replenish_Control,
                               DS.Next_Replenishment_Time,
                               DS.Server_Control.Replenish_Due'Access);
@@ -153,14 +213,14 @@
   procedure Add(DS : in out Deferrable_Server; T : Task_Id) is
   begin
     Add_Task(DS.Budget_Control,T);
-    -- add T to a task list (T_List)
   end Add;
 
   protected body Controller is
-    procedure Budget_Expired(T : in out Group_Timer) is
+    procedure Budget_Expired(GB : in out Group_Budget) is
     begin
-      -- iterate over the T_List suspending
-      -- (Ada.Asynchronous_Control.Hold) the task
+      for T in Members(GB)'Range loop
+        Ada.Asynchronous_Control.Hold(T);
+      end loop;
     end Budget_Expired;
 
     procedure Replenish_Due(TE : in out Timing_Event) is
@@ -170,9 +230,9 @@
       Timing_Events.Set_Handler(DS.Replenish_Control,
                               DS.Next_Replenishment_Time,
                               DS.Server_Control.Replenish_Due'Access);
-
-      -- iterate over T_List resuming
-      -- (Ada.Asynchronous_Control.Continue) the tasks
+      for T in Members(GB)'Range loop
+        Ada.Asynchronous_Control.Continue(T);
+      end loop;
     end Replenish_Due;
 
   end Controller;
@@ -183,30 +243,33 @@
 
 !discussion
 
+Should the Add_Task, Remove_Task and the two Is_Member functions 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
-to the Group_Timer type.
+to the Group_Budget type.
 
 This was rejected in favour of explicit get and set methods mainly for ease
-of use when combining an object of the Group_Timer type and the required
+of use when combining an object of the Group_Budget type and the required
 protected object into a single record type.
 
 b) Passing an unconstrained array of task identifiers as a parameter to
-the Notify protected procedure.
+the Handler protected procedure.
 
 The argument for such a facility is that the user of the package is probably
 going to want to know the group of tasks whose Timer has expired.
-It was decided by the Workshop that this complicated the interface
-and that it was better to have a simpler interface as possible.
+This can now be done with the Members function.
 
-c) Having the Group_Timer type as a tagged type.
+c) Having the Group_Budget type as a tagged type.
 
 This was rejected as the Workshop 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
-associated Group_Timer expired.
+associated Group_Budget expired.
 
 This was rejected because not all Aperiodic Server approaches
 suspend the tasks, some set the tasks' priorities to a background priority.

Questions? Ask the ACAA Technical Agent