Version 1.1 of ais/ai-00307.txt

Unformatted version of ais/ai-00307.txt version 1.1
Other versions for file ais/ai-00307.txt

!standard 9.6 (00)          02-08-28 AI95-00307/01
!standard D.9 (00)
!class amendment 02-08-28
!status work item 02-08-28
!status received 02-08-28
!priority High
!difficulty Hard
!subject Execution-Time Clocks
!summary
Modern real-time scheduling policies require that applications have the ability to measure execution time of tasks, and to detect execution time overruns. Two mechanisms are proposed here to achieve these requirements. Prototype implementations exist for both. Their advantages and disadvantages are discussed, so that one of them can be chosen.
!problem
Real-time analysis techniques are always based on the assumption that the application developer can accurately measure the worst-case execution time (WCET) of each task. This measurement is always very difficult, because, with effects like cache misses, pipelined and superscalar processor architectures, etc., the execution time is highly unpredictable. There are models that allow calculation of WCET's for some architectures, but they are generally very complex and not widely available for all architectures.
In hard real-time systems it is essential to monitor the execution times of all tasks and detect situations in which the estimated WCET is exceeded. This detection was usually available in systems scheduled with cyclic executives, because the periodic nature of its cycle allowed checking that all initiated work had been completed at each cycle. In event-driven concurrent systems the same capability should be available, and this can be accomplished with execution time clocks and timers.
Moreover, many flexible real-time scheduling algorithms require the capability to measure execution time and be able to perform scheduling actions when a certain amount of execution time has been consumed (for example, sporadic servers in fixed priority systems, or the constant bandwidth server in EDF-scheduled systems). Support for execution time clocks and timers would ease implementation of such flexible scheduling algorithms in Ada 95.
Ada 95 does not have any support for execution time monitoring and overrun detection. If we want Ada 95 to continue to be the best language in the environment of real-time systems, we need to include this essential functionality into the language. Java is looking to support this feature.
!proposal
Two proposals are presented here:
- Execution time fully integrated into the language - Execution time provided as a library package
A discussion of both is provided in the "discussion" section.
Proposal A: Execution time fully integrated into the language -------------------------------------------------------------
The following additions are proposed for sections 9.6, D.X (new section in annex D), and D.9:
Section 9.6: Delay Statements, Duration, and Time -------------------------------------------------
In paragraph #6, add a reference to the new section D.X (Execution Time).
In paragraph #28, add a reference to the new section D.X (Execution Time).
D.X Execution Time ------------------
This clause specifies an execution-time clock package.
Static Semantics
The following language-defined library package exists:
with Ada.Task_Identification; package Ada.CPU_Time is type Clock_ID is private;
type Time is private; Time_First : constant Time; Time_Last : constant Time; Time_Unit : constant := implementation-defined-real-number;
type Time_Span is private; Time_Span_First : constant Time_Span; Time_Span_Last : constant Time_Span; Time_Span_Zero : constant Time_Span; Time_Span_Unit : constant Time_Span;
Tick : constant Time_Span;
function CPU_Clock (T : Ada.Task_Identification.Task_Id := Ada.Task_Identification.Current_Task) return Clock_Id;
function Clock (C : Clock_Id) return Time; function Clock_Id_Of (T : Time) return Clock_Id;
function "+" (Left : Time; Right : Time_Span) return Time; function "+" (Left : Time_Span; Right : Time) return Time; function "-" (Left : Time; Right : Time_Span) return Time; function "-" (Left : Time; Right : Time) return Time_Span;
function "<" (Left, Right : Time) return Boolean; function "<=" (Left, Right : Time) return Boolean; function ">" (Left, Right : Time) return Boolean; function ">=" (Left, Right : Time) return Boolean;
function "+" (Left, Right : Time_Span) return Time_Span; function "-" (Left, Right : Time_Span) return Time_Span; function "-" (Right : Time_Span) return Time_Span; function "*" (Left : Time_Span; Right : Integer) return Time_Span; function "*" (Left : Integer; Right : Time_Span) return Time_Span; function "/" (Left, Right : Time_Span) return Integer; function "/" (Left : Time_Span; Right : Integer) return Time_Span;
function "abs" (Right : Time_Span) return Time_Span;
function "<" (Left, Right : Time_Span) return Boolean; function "<=" (Left, Right : Time_Span) return Boolean; function ">" (Left, Right : Time_Span) return Boolean; function ">=" (Left, Right : Time_Span) return Boolean;
function To_Duration (TS : Time_Span) return Duration; function To_Time_Span (D : Duration) return Time_Span;
function Nanoseconds (NS : Integer) return Time_Span; function Microseconds (US : Integer) return Time_Span; function Milliseconds (MS : Integer) return Time_Span;
type Seconds_Count is range implementation-defined;
procedure Split (T : Time; SC : out Seconds_Count; TS : out Time_Span);
function Time_Of (SC : Seconds_Count; TS : Time_Span; C : Clock_Id) return Time;
Time_Error : exception; Incompatible_Times : exception;
private . . . -- not specified by the language end Ada.CPU_Time;
In this Annex, execution time or cpu time of a given task is defined as the time spent by the system executing that task, including the time spent executing run-time or system services on behalf of it. The mechanism used to measure execution time is implementation defined. The implementation shall also define to whom will be charged the execution time that is consumed by interrupt handlers and run-time services on behalf of the system.
The type Clock_ID represents the execution-time clock of a given Ada task.
The type Time is a time type as defined by ARM95, section 9.6; values of this type may be used in a delay_until_statement. The set of the type Time corresponds one-to-one with an implementation-defined range of mathematical integers. Once initialized, a value of the type Time is associated with a given execution-Time Clock, and thus with a given task.
The Time value I represents the half-open execution-time interval that starts with E+ITime_Unit and is limited by E + (I+1)Time_Unit, where Time_Unit is an implementation-defined real number and E is an unspecified origin point, which may be different for each task, but is the same for all the values of the type Time that are relative to a given task. The initial time may, for example, be set to zero at the task's activation time.
Values of the type Time_Span represent length of execution time duration, and are not dependent upon any particular execution-time clock (or task). The set of values of this type corresponds one-to-one with an implementation-defined range of mathematical integers. The Time_Span value corresponding to the integer I represents the execution-time duration I*Time_Unit.
Time_First and Time_Last are the smallest and largest values of the Time type, respectively. Similarly, Time_Span_First and Time_Span_Last are the smallest and largest values of the Time_Span type, respectively.
Time_Unit is the smallest amount of execution time representable by the Time type; it is expressed in seconds. Time_Span_Unit is the difference between two succesive values of the Time type. It is also the smallest positive value of type Time_Span. Time_Unit and Time_Span_Unit represent the same execution time duration. A clock tick is an execution time interval during which the clock value (as observed by calling the Clock function) remains constant. Tick is the average length of such intervals.
The function To_Duration converts the value TS to a value of type Duration. Similarly, the function To_Time_Span converts the value D to a value of type Time_Span. For both operations, the result is rounded to the nearest exactly representable value (away from zero if exactly halfway between two exactly representable values).
To_Duration (Time_Span_Zero) returns 0.0 and To_Time_Span (0.0) returns Time_Span_Zero.
The functions Nanoseconds, Microseconds, and Miliseconds convert the input parameter to a value of the type Time_Span. NS, US, and MS are interpreted as a number of nanoseconds, microseconds, and milliseconds respectively. The result is rounded to the nearest exactly representable value (away from zero if exactly halfway between two exactly representable values).
The effects of the operators on Time and Time_Span are as for the operators defined for integer values.
The function CPU_Clock returns the identifier of the execution-time clock associated to a given Ada task. By default, if no task is specified, the execution-time clock identifier associated to the caller task is returned.
The function Clock returns the amount of execution time of the task associated with the execution-time clock specified by C.
The funcion Clock_Id_Of returns the identifier of the execution-time clock associated to the Time parameter T.
The effects of the Split and Time_Of operations are defined as follows, treating values of type Time, Time_Span, and Seconds_Count as mathematical integers. The effect of Split (T, SC, TS) is to set SC and TS to values such that T*Time_Unit = SC*1.0 + TS*Time_Unit, and 0.0 <= TS*Time_Unit < 1.0. The value returned by Time_Of(SC,TS,C) is the value T of the execution-time clock C such that TTime_Unit=SC1.0 + TS*Time_Unit.
The exception Time_Error is raised by the function Clock if the Clock_Id parameter is not valid. This exception is also raised by operators "+" and "-", and the function Clock_Id_Of, if an execution time parameter is not valid (for example, if it is not initialized). The exception Time_Error is also raised by a delay_until_statement if an invalid execution time parameter is used (see section D.8).
The exception Incompatible_Times is raised by operator "-" if the execution time parameters correspond to different execution-time clocks.
Implementation Requirements
The range of Time values shall be sufficient to uniquely represent the range of execution times from the task start-up to 50 years of execution time later. Tick shall be no greater than 1 millisecond.
Time_Span_First shall be no greater than -3600 seconds, and Time_Span_Last shall be no less than 3600 seconds.
Documentation Requirements
The implementation shall document the values of Time_First, Time_Last, Time_Span_First, Time_Span_Last, Time_Span_Unit, and Tick.
The implementation shall document the properties of the underlying mechanism used to measure execution times, such as the range of values supported and any relevant aspects of the underlying hardware or operating system facilities used.
Metrics
The implementation shall document the following metrics:
- An upper bound on the execution-time duration of a clock
tick. This is a value D such that if t1 and t2 are any execution times of a given task such that t1<t2 and Clock[t1]=Clock[t2] then t2-t1 <= D.
- An upper bound on the size of a clock jump. A clock jump is the
difference between two successive distinct values of an execution -time clock (as observed by calling the Clock function with the same Clock_Id)
- An upper bound on the execution time of a call to the Clock
function, in processor clock cycles.
- Upper bounds on the execution times of the operators of the types
Time and Time_Span, in processor clock cycles.
Implementation Permissions
Implementations targeted to machines with word size smaller than 32 bits need not support the full range and granularity of the Time and Time_Span types.
Implementation Advice
When appropriate, implementations should provide configuration mechanisms to change the value of Tick.
D.9 Delay Accuracy ------------------
Dynamic Semantics
Add the following after paragraph #4
The effect of the delay_statement for CPU_Time.Time is defined in terms of CPU_Time.Clock:
If C is a value of the execution-time clock, Clk, of a given task read after a (possibly different) task resumes execution following a delay_until_statement with a CPU_Time.Time value T associated to the Clk execution-time Clock), then C >= T.
Add the following after paragraph #5:
A simple delay_until_statement with a CPU_Time.Time value T associated to the execution-time clock of the calling task raises the predefined exception Program_Error (there is a deadlock condition because the calling task becomes blocked until its execution time reaches the value T and its execution-time clock can not advance because the calling task is blocked).
A delay_until_statement with an invalid CPU_Time.Time value (for example, an uninitialized value) raises CPU_Time.Time_Error.
Proposal B: Execution time provided as a library package --------------------------------------------------------
A new section D.X is proposed for Annex D:
D.X Execution Time ------------------
This clause specifies an execution-time clock package.
Static Semantics
The following language-defined library package exists:
with Ada.Task_Identification; package Ada.Real_Time.Execution_Time is
type Clock_ID is private;
type CPU_Time is private; CPU_Time_First : constant CPU_Time; CPU_Time_Last : constant CPU_Time; CPU_Time_Unit : constant := implementation-defined-real-number; CPU_Tick : constant Time_Span;
function CPU_Clock (T : Ada.Task_Identification.Task_ID := Ada.Task_Identification.Current_Task) return Clock_ID;
function Clock(C : Clock_ID) return CPU_Time;
function "+" (Left : CPU_Time; Right : Time_Span) return CPU_Time; function "+" (Left : Time_Span; Right : CPU_Time) return CPU_Time; function "-" (Left : CPU_Time; Right : Time_Span) return CPU_Time; function "-" (Left : CPU_Time; Right : CPU_Time) return Time_Span;
function "<" (Left, Right : CPU_Time) return Boolean; function "<=" (Left, Right : CPU_Time) return Boolean; function ">" (Left, Right : CPU_Time) return Boolean; function ">=" (Left, Right : CPU_Time) return Boolean;
procedure Split (T : CPU_Time; SC : out Seconds_Count; TS : out Time_Span);
function Time_Of (SC : Seconds_Count; TS : Time_Span; C : Clock_Id) return Time;
protected type Timer is procedure Initialize (C : Clock_ID); procedure Finalize; procedure Arm (Interval : Time_Span); procedure Disarm; entry Time_Exceeded; function Time_Was_Exceeded return Boolean; function Time_Remaining return Time_Span; private ... -- not specified by the language end Timer;
Time_Error : exception; -- may be raised by Timer.Time_Exceeded, Timer.Time_Was_exceeded, -- and Timer.Time_Remaining
private ... -- not specified by the language end Ada.Real_Time.Execution_Time;
In this Annex, execution time or cpu time of a given task is defined as the time spent by the system executing that task, including the time spent executing run-time or system services on behalf of it. The mechanism used to measure execution time is implementation defined. The implementation shall also define to whom will be charged the execution time that is consumed by interrupt handlers and run-time services on behalf of the system.
The type Clock_ID represents the execution-time clock of a given Ada task.
The type CPU_Time represents the execution time of a task. The set of the type CPU_Time corresponds one-to-one with an implementation-defined range of mathematical integers.
The CPU_Time value I represents the half-open execution-time interval that starts with E+I*CPU_Time_Unit and is limited by E + (I+1)*CPU_Time_Unit, where CPU_Time_Unit is an implementation-defined real number and E is an unspecified origin point, which may be different for each task, but is the same for all the values of the type CPU_Time that are relative to a given task. The initial time may, for example, be set to zero at the task's activation time.
CPU_Time_First and CPU_Time_Last are the smallest and largest values of the Time type, respectively.
CPU_Time_Unit is the smallest amount of execution time representable by the CPU_Time type; it is expressed in seconds. A CPU clock tick is an execution time interval during which the clock value (as observed by calling the Clock function) remains constant. CPU_Tick is the average length of such intervals.
The effects of the operators on Time and Time_Span are as for the operators defined for integer values.
The function CPU_Clock returns the identifier of the execution-time clock associated to a given Ada task. By default, if no task is specified, the execution-time clock identifier associated to the caller task is returned.
The function Clock returns the amount of execution time of the task associated with the execution-time clock specified by C.
The effects of the Split and Time_Of operations are defined as follows, treating values of type CPU_Time, Time_Span, and Seconds_Count as mathematical integers. The effect of Split (T, SC, TS) is to set SC and TS to values such that TCPU_Time_Unit = SC1.0 + TSCPU_Time_Unit, and 0.0 <= TSCPU_Time_Unit < 1.0. The value returned by Time_Of(SC,TS,C) is the value T of the execution-time clock C 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. This protected object type has visible operations for the application tasks to initialize or finalize a CPU-time timer, to arm or disarm a timer, and to determine whether a timer has expired or not (Time_Was_Exceeded). In addition, Timer has an entry (Time_Exceeded) that can be used by application tasks to block until an execution time overrun is detected, or as an event that triggers the abortion of the instructions of a select statement with an abortable part.
The Timer.Initialize protected procedure allocates and initializes the resources required to operate a CPU-time timer based on the execution time clock specified by C. If the operation would exceed the limit of the maximum number of timers in the system, the Storage_Error exception is raised. The timer is initialized in the disarmed state.
The Timer.Finalize protected procedure deallocates the system resources used by the timer. No other calls to the timer operations of the associated timer may be made, except another Initialize call. Constraint_Error will be raised if such attempt is detected.
The Timer.Arm protected procedure loads the associated timer with the 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 Timer.Disarm protected procedure sets the timer to the disarmed state. In this state no timer expirations occur.
The Timer.Time_Exceeded protected entry suspends the calling task if the timer is in the armed state but has not yet expired. The entry is allowed to complete when the timer is in the armed state and has expired. If the timer is in the disarmed state, the Time_Error exception is raised.
The Timer.Time_Was_Exceeded 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 Time_Error exception is raised.
The Timer.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 Time_Error exception is raised.
The Time_Error exception is raised by Timer.Time_Exceeded, Timer.Time_Was_Exceeded, or Timer.Time_Remaining if an attempt is made to use a timer that is in the disarmed state.
Implementation Requirements
The range of CPU_Time values shall be sufficient to uniquely represent the range of execution times from the task start-up to 50 years of execution time later. CPU_Tick shall be no greater than 1 millisecond.
Documentation Requirements
The implementation shall document the values of CPU_Time_First, CPU_Time_Last, CPU_Time_Unit, and CPU_Tick.
The implementation shall document the properties of the underlying mechanism used to measure execution times, such as the range of values supported and any relevant aspects of the underlying hardware or operating system facilities used.
Metrics
The implementation shall document the following metrics:
- An upper bound on the execution-time duration of a clock
tick. This is a value D such that if t1 and t2 are any execution times of a given task such that t1<t2 and Clock[t1]=Clock[t2] then t2-t1 <= D.
- An upper bound on the size of a clock jump. A clock jump is the
difference between two successive distinct values of an execution -time clock (as observed by calling the Clock function with the same Clock_Id)
- An upper bound on the execution time of a call to the Clock
function, in processor clock cycles.
- Upper bounds on the execution times of the operators of the type
CPU_Time, in processor clock cycles.
Implementation Permissions
Implementations targeted to machines with word size smaller than 32 bits need not support the full range and granularity of the CPU_Time type.
Implementation Advice
When appropriate, implementations should provide configuration mechanisms to change the value of Tick.
!discussion
Need for execution time monitoring functionality ------------------------------------------------
Traditional real time systems were built (and still are) using cyclic executive schedulers. In these systems, if a particular task or routine exceeded its budgeted execution time, the system could detect the situation. Basically, whenever the minor cycle interrupt came in, it could check whether the current action had completed or not. If not, that meant an overrun. Unfortunately, in some concurrent real-time systems built with priority-based on-line schedulers there is no equivalent method to detect and handle execution time overruns. This is the case for systems built using the Ada tasking model and the associated Real-Time Annex.
In addition, many flexible real-time scheduling algorithms require the capability to measure execution time and be able to perform scheduling actions when a certain amount of execution time has been consumed (for example, sporadic servers in fixed priority systems, or the constant bandwidth server in EDF-scheduled systems). Support for execution time clocks and timers is essential to be able to implement such flexible scheduling algorithms.
In recognition of all these application requirements, the Real-Time extensions to POSIX have recently incorporated support for them. Real-Time POSIX supports execution time clocks and timers that allow an application to monitor the consumption of execution time by its tasks, and to set limits for this consumption. The next revision of the Ada language should support this functionality in order for the language to continue to be the best for programming real-time applications.
It could be argued that given that the POSIX standard already defines execution time clocks and timers it would not be necessary to have the same functionality in the Ada language standard, because the POSIX services can be accessed through the appropriate bindings. This is true for Ada platforms built on top of POSIX OS implementations, but not for bare-machine implementations, like the ones used in embedded systems, avionics, etc. For portability purposes it is necessary to have this functionality supported in a homogeneous way for all the implementations that choose to support it.
Two possible implementations ----------------------------
One important requirement of any execution-time functionality that may be incorporated into the Ada language is that it is implementable on top of the POSIX execution-time clocks and timers. In this document two different ways of providing the execution-time monitoring functionality are proposed, that satisfy the above requirement.
The first proposal integrates execution time clocks fully into the Ada Language, by creating a new Time type that can be used with all the forms of the delay until statement. A new package defining this new type is proposed, which includes operations to handle and manage values of that type. The price to pay for this integrated approach is that modifications are required to the compiler and to the run-time system.
The second proposal defines a new package that includes all the operations required to access the execution-time monitoring functionality. Some of these operations belong to a protected object type that represents execution-time timers. This approach does not require modification of the compiler, nor of the run-time system (provided that the POSIX execution-time functionality is available), but its execution time type is not integrated in the Ada language as a Time type.
Prototype implementations -------------------------
Prototype implementations have been developed for both proposals, using the MaRTE operating system that provides a POSIX.13 interface and includes execution-time clocks and timers.
The implementation of proposal A, with execution-time functionality integrated into the language, requires small modifications to the compiler and to the run-time, which are described in document [1]. The modifications were implemented in a short period of time and should not represent a large effort to current compiler implementors.
The implementation of proposal B 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 the underlaying execution-time monitoring functionality would have to be implemented in the scheduler. Document [2] describes one such implementation and it can be seen that it is relatively simple, and that it does not introduce any significant overhead into the scheduler.
The overheads are quite similar in both implementations, and are small.
Conclusion ----------
The IRTAW group recommends the first approach, with execution-time functionality integrated in the Ada Language, because it provides a simpler model to programmers. However, the group feels that there is a strong need to have the execution-time functionality in Ada, so if the second proposal, with a library implementation, has more probability of success, the group would also recommend its adoption.
The IRTAW group is not opposed to having this new functionality defined as optional in the Real-Time Systems Annex.
!examples
Example 1: Stopped task -----------------------
The following is an example of a periodic task that limits its own execution time to some predefined amount called WCET (worst-case execution time). If an execution time overrun is detected, the task aborts the remainder of its execution, until the next period.
Example 1 implemented with proposal A: --------------------------------------
with Ada.Real_Time, Ada.CPU_Time; use Ada; use type Ada.CPU_Time.Time; use type Ada.Real_Time.Time;
...
task body Periodic_Stopped is C : CPU_Time.Clock_ID := CPU_Time.CPU_Clock; -- My execution-time clock identifier Overrun : CPU_Time.Time; Next_Start : Real_Time.Time:=Real_Time.Clock; WCET : constant Duration:=1.0E-3; Period : constant Duration:=1.0E-2; begin loop Overrun := CPU_Time.Clock (C) + CPU_Time.To_Time_Span (WCET); select delay until Overrun; -- Execution-time-clock-based delay Handle_the_error; then abort Do_useful_work; end select; Next_Start := Next_Start + Real_Time.To_Time_Span(Period); delay until Next_Start; -- Real-time-clock-based delay end loop; end Periodic_Stopped;
...
Example 1 implemented with proposal B: ------------------------------------
with Ada.Real_Time, Ada.Real_Time.Execution_Time; use Ada; use type Ada.Real_Time.Time;
...
task body Periodic_Stopped is C : Real_Time.Execution_Time.Clock_ID := Real_Time.Execution_Time.CPU_Clock; -- My execution-time clock identifier The_Timer : Real_Time.Execution_Time.Timer; Next_Start : Real_Time.Time:=Real_Time.Clock; WCET : constant Duration:=1.0E-3; Period : constant Duration:=1.0E-2; begin The_Timer.Initialize(C); loop The_Timer.Arm(Real_Time.To_Time_Span(WCET)); select The_Timer.Time_Exceeded; -- Execution-time overrun detection Handle_the_error; then abort Do_useful_work; end select; The_Timer.Disarm; Next_Start := Next_Start + Real_Time.To_Time_Span(Period); delay until Next_Start; end loop; end Periodic_Stopped;
...
Example 2: Lowered task -----------------------
In this example, when an execution time overrun is detected the priority of the task is lowered to allow other lower priority tasks to continue meeting their timing requirements.
A simple implementation of this scheme uses two nested tasks: the Worker task and the Supervisor task. The Supervisor task sleeps until the execution time of the Worker task reaches the instant of the priority change. When this happens the supervisor lowers (or increases) the priority of the worker task. If the Worker task completes the work before the instant of the priority change then it aborts the Supervisor task.
Example 2 implemented with proposal A -------------------------------------
with Ada.CPU_Time, Ada.Dynamic_Priorities, System; use Ada; use type CPU_Time.Time; ...
task body Worker is task Supervisor is pragma Priority(System.Priority'Last); end Supervisor;
task body Supervisor is C : CPU_Time.Clock_ID := CPU_Time.CPU_Clock (Worker'Identity); WCET : constant Duration:=1.0E-3; Overrun : CPU_Time.Time := CPU_Time.Clock (C) + CPU_Time.To_Time_Span (WCET); Low_Prio : System.Priority:=System.Priority'First; begin delay until Overrun; -- CPU-time-based delay Dynamic_Priorities.Set_Priority(Low_Prio,Worker'Identity); end Supervisor; begin Do_useful_work; abort Supervisor; end Worker;
...
Example 2 implemented with proposal B -------------------------------------
with Ada.Real_Time,Ada.Real_Time.Execution_Time, Ada.Dynamic_Priorities, System; use Ada;
...
task body Worker is task Supervisor is pragma Priority(System.Priority'Last); end Supervisor;
task body Supervisor is C : Real_Time.Execution_Time.Clock_ID := Real_Time.Execution_Time.CPU_Clock (Worker'Identity); WCET : constant Duration:=1.0E-3; The_Timer : Real_Time.Execution_Time.Timer; Low_Prio : System.Priority:=System.Priority'First; begin The_Timer.Initialize(C); The_Timer.Arm(Real_Time.To_Time_Span(WCET)); The_Timer.Time_Exceeded; -- wait for timer overrun Dynamic_Priorities.Set_Priority(Low_Prio,Worker'Identity); end Supervisor; begin Do_useful_work; abort Supervisor; end Worker;
...
Example 3. Justification of the Clock_Id_Of function ----------------------------------------------------
The function Clock_id_Of included in proposal A is not strictly necessary and is only included for convenience. The clock information is inside the Time type anyway, so the function can be used for example to check the validity of an operation without getting the exception if two times are based upon different clocks:
if Clock_Id_Of(T1)=Clock_Id_Of(T2) then
TS:=T2-T1;
else
-- handle the error (T1 and T2 incompatible)
end if;
If Clock_Id_Of was not available, then the only way to find out if two time types are compatible is via the Incompatible_Times exception, which in some environments may not be convenient.
!appendix

From: Alan Burns
Sent: Monday, August 5, 2002  8:28 AM

I attach the AI from Michael Harbour on CPU clocks.
I'm not sure if this issue actually had an AI number.

For the real-time folks this is the second most important
issue (after Ravenscar).

You can see that the AI contains two possible approches, a
new timer type or a new library package. It would be useful
at the next ARG to have a general discusion about the approach
to be take.

[Editor's note: The attachment is draft 1 of this AI. The draft credited
authors of Michael Gonzalez Harbour, Javier Miranda, and Mario Aldea
on behalf of IRTAW11].

****************************************************************

Additional references for the original proposal:

 [1] A Proposal to Integrate the POSIX Execution-Time Clocks into Ada
     95. Technical Report, June, 2002, By J. Miranda Gonzalez and
     M. Gonzalez Harbour.

 [2] Implementing and using Execution Time Clocks in Ada Hard
     Real-Time Applications. By Gonzalez Harbour M., Aldea Rivas M.,
     Gutierrez Garcia J.J., Palencia Gutierrez J.C. International
     Conference on Reliable Software Technologies, Ada-Europe'98,
     Uppsala, Sweden, in Lecture Notes on Computer Science No. 1411,
     Junio, 1998, ISBN:3-540-64563-5, pp. 91,101.

 [3] Extending Ada's Real-Time Systems Annex with the POSIX Scheduling
     Services. By: Mario Aldea Rivas and Michael Gonzalez
     Harbour. IRTAW-2000, Las Navas, Avila, Spain.

****************************************************************


Questions? Ask the ACAA Technical Agent