D.15 Timing Events
This subclause describes a language-defined package to allow user-defined
protected procedures to be executed at a specified time without the need
for a task or a delay statement.
The following language-defined library package exists:
Timing_Event is tagged limited private
is access protected procedure
(Event : in out
Set_Handler (Event : in out
At_Time : in
Handler : in
Set_Handler (Event : in out
In_Time : in
Handler : in
Current_Handler (Event : Timing_Event)
Cancel_Handler (Event : in out
Cancelled : out
Time_Of_Event (Event : Timing_Event) return
... -- not specified by the language
The type Timing_Event represents a time in the future when an event is
to occur. The type Timing_Event needs finalization
An object of type Timing_Event is said to be set
if it is associated
with a nonnull value of type Timing_Event_Handler and cleared
otherwise. All Timing_Event objects are initially cleared.
The type Timing_Event_Handler identifies a protected procedure to be
executed by the implementation when the timing event occurs. Such a protected
procedure is called a handler
Type Timing_Event is tagged. This makes it possible to share a handler
between several events. In simple cases, 'Access can be used to compare
the parameter with a specific timing event object (this works because
a tagged type is a by-reference type). In more complex cases, a type
extension of type Timing_Event can be declared; a double type conversion
can be used to access the extension data. For example:
type Toaster_Timing_Event is new Timing_Event with record
Slot : Natural;
protected body Toaster is
procedure Timer (Event : in out Timing_Event) is
The extra conversion to the class-wide type
is necessary to make the conversions legal. While this usage is clearly
ugly, we think that the need for this sort of usage will be rare, so
we can live with it. It's certainly better than having no way to associate
data with an event.
The procedures Set_Handler associate the handler Handler with the event
Event: if Handler is null
, the event is cleared; otherwise, it
is set. The first procedure Set_Handler sets the execution time for the
event to be At_Time. The second procedure Set_Handler sets the execution
time for the event to be Real_Time.Clock + In_Time.
A call of a procedure Set_Handler for an event that is already set replaces
the handler and the time of execution; if Handler is not null
the event remains set.
As soon as possible after the time set for the event, the handler is
executed, passing the event as parameter. The handler is only executed
if the timing event is in the set state at the time of execution. The
initial action of the execution of the handler is to clear the event.
Reason: The second sentence of this paragraph
is because of a potential race condition. The time might expire and yet
before the handler is executed, some task could call Cancel_Handler (or
equivalently call Set_Handler with a null parameter) and thus
clear the handler.
If the Ceiling_Locking policy (see D.3
in effect when a procedure Set_Handler is called, a check is made that
the ceiling priority of Handler.all
If the check fails, Program_Error is raised.
If a procedure Set_Handler is called with zero or negative In_Time or
with At_Time indicating a time in the past, then the handler is executed
as soon as possible after the completion of the call of Set_Handler.
The handler will still be executed. Under no circumstances is a scheduled
call of a handler lost.
We say “as soon as possible” so that we do not deadlock if
we are executing the handler when Set_Handler is called. In that case,
the current invocation of the handler must complete before the new handler
can start executing.
The function Current_Handler returns the handler associated with the
event Event if that event is set; otherwise, it returns null
The procedure Cancel_Handler clears the event if it is set. Cancelled
is assigned True if the event was set prior to it being cleared; otherwise,
it is assigned False.
The function Time_Of_Event returns the time of the event if the event
is set; otherwise, it returns Real_Time.Time_First.
As part of the finalization of an object of type Timing_Event, the Timing_Event
Implementation Note: This is the only
finalization defined by the language that has a visible effect; but an
implementation may have other finalization that it needs to perform.
Implementations need to ensure that the event is cleared before anything
else is finalized that would prevent a set event from being triggered.
If several timing events are set for the same time, they are executed
in FIFO order of being set.
An exception propagated from a handler invoked by a timing event has
For a given Timing_Event object, the implementation shall perform the
operations declared in this package atomically with respect to any of
these operations on the same Timing_Event object. The replacement of
a handler by a call of Set_Handler shall be performed atomically with
respect to the execution of the handler.
Reason: This prevents various race conditions.
In particular it ensures that if an event occurs when Set_Handler is
changing the handler then either the new or old handler is executed in
response to the appropriate event. It is never possible for a new handler
to be executed in response to an old event.
The implementation shall document the following metric:
An upper bound on the lateness of the execution of a handler. That is,
the maximum time between the time specified for the event and when a
handler is actually invoked assuming no other handler or task is executing
during this interval.
Documentation Requirement: The metrics
for timing events.
The protected handler procedure should be executed directly by the real-time
clock interrupt mechanism.
Implementation Advice: For a timing event,
the handler should be executed directly by the real-time clock interrupt
Since a call of Set_Handler is not a potentially blocking operation,
it can be called from within a handler.
A Timing_Event_Handler can be associated with several Timing_Event objects.
Extensions to Ada 95
Wording Changes from Ada 2005
Reworded to eliminate a deadlock condition if the
event time is in the past and a handler is currently executing. This
is technically an inconsistency, but only if a program is depending on
deadlocking; since it is impossible to imagine how that could be useful,
we have not documented this as an inconsistency.
Clarified the metric for lateness of a timing event
to exclude interference from other handlers and tasks. This change might
change the documentation of an implementation, but not the implementation
itself, so there is no inconsistency.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe