CVS difference for ais/ai-00307.txt

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

--- ais/ai-00307.txt	2003/09/25 01:49:13	1.6
+++ ais/ai-00307.txt	2003/09/30 02:01:13	1.7
@@ -1,6 +1,6 @@
-!standard D.14 (01)                                  03-07-02  AI95-00307/04
+!standard D.14 (01)                                  03-09-21  AI95-00307/05
 !class amendment 02-08-28
-!status Amendment 200Y 03-07-02
+!status work item 03-09-21
 !status ARG Approved 12-0-1  03-06-20
 !status work item 02-08-28
 !status received 02-08-28
@@ -26,6 +26,13 @@
 changes requested by the ARG. A discussion of these changes can be
 found at the end of the "Discussion" section.
 
+This revision of the AI was produced by IRTAW 12 in response to the
+requirement to be able to wait for one or more Timers to expire. This
+has required a restructuring of the proposed solution. The consequence
+is that the Timer is no longer a protected object. Timer expirations
+are notified by the system by calling a protected procedure that is
+passed to it by an access parameter in the Timer operations.
+
 !problem
 
 Real-time analysis techniques are always based on the assumption that
@@ -86,6 +93,7 @@
 The following language-defined library package exists:
 
 with Ada.Task_Identification;
+with System;
 package Ada.Real_Time.Execution_Time is
 
    type CPU_Time is private;
@@ -95,7 +103,7 @@
    CPU_Tick : constant Time_Span;
 
    function Clock
-     (T : Ada.Task_Identification.Task_ID
+     (Tid : Ada.Task_Identification.Task_ID
           := Ada.Task_Identification.Current_Task)
      return CPU_Time;
 
@@ -114,19 +122,20 @@
 
    function Time_Of (SC : Seconds_Count; TS : Time_Span) return CPU_Time;
 
-   protected type Timer
-     (T : access Ada.Task_Identification.Task_ID)
-   is
-      procedure Arm (Interval : Time_Span);
-      procedure Arm (Abs_Time : CPU_Time);
-      procedure Disarm;
-      entry Timer_Expired;
-      function Timer_Has_Expired return Boolean;
-      function Time_Remaining return Time_Span;
-   private
-      ... --  not specified by the language
-   end Timer;
+   type Timer (Tid : access Ada.Task_Identification.Task_ID) is
+      limited private;
+
+   Min_Announce_Ceiling : constant System.Any_Priority :=
+    <Implementation Defined>;
 
+   type Announce is access protected procedure (T : in out Timer);
+
+   procedure Arm (T: in out Timer; Interval : Time_Span; Handler : Announce);
+   procedure Arm (T: in out Timer; Abs_Time : CPU_Time;  Handler : Announce);
+   procedure Disarm(T : in out Timer);
+   function Timer_Has_Expired(T : Timer) return Boolean;
+   function Time_Remaining(T : Timer) return Time_Span;
+
    Timer_Error : exception;
 
    Timer_Resource_Error : exception;
@@ -179,17 +188,20 @@
 returned by Time_Of(SC,TS) is the execution-time value T such that
 T*CPU_Time_Unit=SC*1.0 + TS*CPU_Time_Unit.
 
-Package Execution_Time contains a protected object type called Timer,
-which represents a software object that is capable of detecting
-execution time overruns. Each timer is attached to a specific execution
-time clock, which is the clock of the task specified by the access
-discriminant T. This protected object type has visible operations for
-the application tasks to arm or disarm a timer, and to determine
-whether a timer has expired or not (Timer_Has_Expired). In addition,
-Timer has an entry (Timer_Expired) that can be used by application
-tasks to block until an execution time budget is exhausted, or as an
-event that triggers the abortion of the instructions of a select
-statement with an abortable part.
+Package Execution_Time contains a type called Timer, which represents a
+software object that is capable of detecting execution time overruns. Each
+timer is attached to a specific execution time clock, which is the clock of the
+task specified by the access discriminant T. This type has operations for the
+application tasks to arm or disarm a timer, and to determine whether a timer
+has expired or not (Timer_Has_Expired). In addition, when arming the timer, an
+access to a protected procedure (type Announce) can be passed. This procedure
+will be called by the implementation when the timer expires. This can be used
+by the application (for example) to trigger the abortion of the instructions of
+a select statement with an abortable part.
+
+The constant Min_Announce_Ceiling indicates the minimum ceiling
+priority that must be assigned to any protected object associated with
+the Announce protected procedure.
 
 When a Timer object is created, or upon the first call to one of its Arm
 procedures, the resources required to operate a CPU-time timer based on
@@ -198,46 +210,46 @@
 in the system, the Timer_Resource_Error exception is raised. The timer
 is initialized in the disarmed state.
 
-The Arm protected procedure that takes a Time_Span parameter
-loads the associated timer with the relative value specified by
-Interval and sets it to the armed state. In this state the timer
-counts execution time and, when the CPU clock associated with the
-timer measures the passage of Interval, it is said to have expired. If
-the timer was already armed, it is rearmed.
-
-The Arm protected procedure that takes a CPU_Time parameter
-loads the associated timer with the absolute value specified by
-Abs_Time and sets it to the armed state. In this state the timer
-monitors execution time and, when the CPU clock associated with the
-timer reaches the value Abs_Time, it is said to have expired. If the
-value of Abs_Time had already been reached by the clock at the time of
-the call, the timer is set to the armed state and is said to have
+The Arm procedure that takes a Time_Span parameter loads the associated timer
+with the relative value specified by Interval and sets it to the armed state.
+In this state the timer counts execution time and, when the CPU clock
+associated with the timer measures the passage of Interval, it is said to have
 expired. If the timer was already armed, it is rearmed.
 
-The Disarm protected procedure sets the timer to the disarmed
-state. In this state no timer expirations occur.
+The Arm procedure that takes a CPU_Time parameter loads the associated timer
+with the absolute value specified by Abs_Time and sets it to the armed state.
+In this state the timer monitors execution time and, when the CPU clock
+associated with the timer reaches the value Abs_Time, it is said to have
+expired. If the value of Abs_Time had already been reached by the clock at the
+time of the call, the timer is set to the armed state and is said to have
+expired. If the timer was already armed, it is rearmed.
 
-The Timer_Expired protected entry suspends the calling task until
-the timer expires if the timer is in the armed state; if the timer has
-already expired, then the calling task proceeds. If the timer is in the
-disarmed state, the Timer_Error exception is raised.
-
-The Time_Has_Expired protected function returns True if the
-timer is in the armed state and has expired, and returns False if the
-timer is in the armed state but has not yet expired. If the timer is
-in the disarmed state, the Timer_Error exception is raised.
-
-The Time_Remaining protected function returns, when the timer is
-in the armed state, the CPU time interval that remains until the timer
-will expire, or a value representing zero if the timer has expired. If
-the timer is in the disarmed state, the Timer_Error exception is raised.
-
-The Timer_Error exception is raised by Timer_Expired,
-Timer_Has_Expired, or Time_Remaining if an attempt is made
-to use a timer that is in the disarmed state.
+For any of the Arm procedures, when the timer expires, the protected
+procedure Handler is invoked by the system with a parameter equal to
+the Timer.
+
+The Disarm procedure sets the timer to the disarmed state. In this
+state no timer expirations occur.
+
+The Time_Has_Expired function returns True if the timer is in the
+armed state and has expired, and returns False if the timer is in the
+armed state but has not yet expired. If the timer is in the disarmed
+state, the Timer_Error exception is raised.
+
+The Time_Remaining function returns, when the timer is in the armed state, the
+CPU time interval that remains until the timer will expire, or a value
+representing zero if the timer has expired. If the timer is in the disarmed
+state, the Timer_Error exception is raised.
+
+The Timer_Error exception is raised by Timer_Has_Expired, or
+Time_Remaining if an attempt is made to use a timer that is in the
+disarmed state.
 
 Implementation Requirements
 
+The implementation shall ensure that the operations of this package
+can be called concurrently.
+
 When an object of type Timer is finalized, the system resources used by
 the timer shall be deallocated.
 
@@ -287,14 +299,13 @@
 mechanisms to change the value of CPU_Tick.
 
 !discussion
+
+A prototype implementations was developed for the initial proposal, using the
+MaRTE operating system that provides a POSIX.13 interface and includes
+execution-time clocks and timers.
 
-A prototype implementations was developed for the initial
-proposal, using the MaRTE operating system that provides a POSIX.13
-interface and includes execution-time clocks and timers.
-
-The implementation of the proposal is very simple,
-because it does not require modifications to the compiler nor to the
-runtime system.
+The implementation of the proposal is very simple, because it does not require
+modifications to the compiler nor to the runtime system.
 
 Implementations on bare machines or systems without POSIX
 execution-time clocks and timers would be a bit more complex because
@@ -306,7 +317,6 @@
 
 The overhead of the implementation is small.
 
-
 The original proposal included Time_Of taking a Task_Id
 parameter. This was included so that an implementation could
 choose to have the Task_Id as part of an Execution_Time value, in case
@@ -314,7 +324,6 @@
 tasks. Since we allow operations between CPU_Time values from different tasks,
 the Task_Id is not needed.
 
-
 The initial proposal left the initial value of the execution time
 clock of each task unspecified. However, it is valuable to be
 able to determine a task's absolute execution time, and thus the value
@@ -327,7 +336,6 @@
 some unspecified point between the task creation and the end of the
 task's activation.
 
-
 The initial proposal had two protected operations inside the Timer:
 Initialize and Finalize. Initialize took a parameter that identified
 the execution time clock to be used. These operations appeared unnecessary
@@ -344,20 +352,18 @@
 either case, the overhead is small and bounded.
 
 Given that it is forecasted that most implementations of package
-Ada.Real_Time.Execution_Time will be made on top of the POSIX
-execution-time services, the
-parameter that identifies the clock should be an access discriminant,
-and *not* a parameter to Arm. The reason is that in the POSIX API
+Ada.Real_Time.Execution_Time will be made on top of the POSIX execution-time
+services, the parameter that identifies the clock should be an access
+discriminant, and *not* a parameter to Arm. The reason is that in the POSIX API
 Execution-Time timers are system objects that require allocation and
-deallocation of resources, and therefore it is not reasonable to
-allocate these resources each time a Timer is being used. The common
-use is to allocate the resources once, and then use the timer many
-times. It is also necessary to take into account that an application
-may want to establish more than one timer per task, and therefore the
-resources cannot be preallocated: for example, a system may be
-implementing a sporadic server for a given task using a CPU-Time
-Timer, but that task itself may use another timer to finish some
-particular any-time algorithm that it may be executing.
+deallocation of resources, and therefore it is not reasonable to allocate these
+resources each time a Timer is being used. The common use is to allocate the
+resources once, and then use the timer many times. It is also necessary to take
+into account that an application may want to establish more than one timer per
+task, and therefore the resources cannot be preallocated: for example, a system
+may be implementing a sporadic server for a given task using a CPU-Time Timer,
+but that task itself may use another timer to finish some particular any-time
+algorithm that it may be executing.
 
 
 !example
@@ -376,27 +382,53 @@
 
 ...
 
+   task Periodic_Stopped;
+
+   protected Control is
+     entry Wait_Budget_Expiry;
+     procedure Budget_Expired(T : in out Ada.Real_Time.Execution_Time.Timer);
+     pragma Priority(Ada.Execution_Time.Min_Announce_Ceiling);
+   private
+     Expired : Boolean := False;
+   end Control;
+
+   protected body Control is
+     entry Wait_Budget_Expiry when Expired is
+     begin
+       Expired := False;
+     end Wait_Budget_Expiry;
+
+     procedure Budget_Expired(T : in out Ada.Real_Time.Execution_Time.Timer) is
+     begin
+       Expired := True;
+     end Budget_Expired;
+   end Control;
+
    task body Periodic_Stopped is
       My_Id : aliased Task_Identification.Task_Id:=
          Periodic_Stopped'Identity;
       The_Timer : Ada.Real_Time.Execution_Time.Timer(My_Id'Access);
+
       Next_Start : Real_Time.Time:=Real_Time.Clock;
       WCET : constant Duration:=1.0E-3;
       Period : constant Duration:=1.0E-2;
    begin
       loop
-         The_Timer.Arm(Real_Time.To_Time_Span(WCET));
+         Ada.Real_Time.Execution_Time.Arm
+            (The_Timer, Real_Time.To_Time_Span(WCET),
+             Control.Budget_Expired'Access);
          select
-            The_Timer.Timer_Expired; -- Execution-time overrun detection
-            Handle_the_error;
+            Control.Wait_Budget_Expiry; -- Execution-time overrun detection
+            -- Handle_the_error;
          then abort
-            Do_useful_work;
+            null; -- Do_useful_work;
          end select;
-         The_Timer.Disarm;
+         Ada.Real_Time.Execution_Time.Disarm(The_Timer);
          Next_Start := Next_Start + Real_Time.To_Time_Span(Period);
          delay until Next_Start;
       end loop;
    end Periodic_Stopped;
+
 ...
 
 Example 2: Lowered task
@@ -419,8 +451,30 @@
 use Ada;
 
 ...
+
+   protected Control is
+     entry Wait_Budget_Expiry;
+     procedure Budget_Expired(T : in out Ada.Real_Time.Execution_Time.Timer);
+     pragma Priority(Ada.Real_Time.Execution_Time.Min_Announce_Ceiling);
+   private
+     Expired : Boolean := False;
+   end Control;
+
+   protected body Control is
+     entry Wait_Budget_Expiry when Expired is
+     begin
+       Expired := False;
+     end Wait_Budget_Expiry;
+
+     procedure Budget_Expired(T : in out Ada.Real_Time.Execution_Time.Timer) is
+     begin
+       Expired := True;
+     end Budget_Expired;
+   end Control;
+
+  task Worker;
 
-   task body Worker is
+  task body Worker is
       task Supervisor is
          pragma Priority(System.Priority'Last);
       end Supervisor;
@@ -431,12 +485,14 @@
          The_Timer : Ada.Real_Time.Execution_Time.Timer(My_Id'Access);
          Low_Prio : System.Priority:=System.Priority'First;
       begin
-         The_Timer.Arm(Real_Time.To_Time_Span(WCET));
-         The_Timer.Timer_Expired; -- wait for timer overrun
+         Ada.Real_Time.Execution_Time.Arm
+           (The_Timer, Real_Time.To_Time_Span(WCET),
+            Control.Budget_Expired'Access);
+         Control.Wait_Budget_Expiry; -- wait for timer overrun
          Dynamic_Priorities.Set_Priority(Low_Prio,Worker'Identity);
       end Supervisor;
    begin
-      Do_useful_work;
+      -- Do_useful_work;
       abort Supervisor;
    end Worker;
 

Questions? Ask the ACAA Technical Agent