C.3 Interrupt Support
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
[This subclause specifies the language-defined model for hardware interrupts in addition to mechanisms for handling interrupts.]
Dynamic Semantics
2[An interrupt represents a class of events that are detected by the hardware or the system software.] Interrupts are said to occur. An occurrence of an interrupt is separable into generation and delivery. Generation of an interrupt is the event in the underlying hardware or system that makes the interrupt available to the program. Delivery is the action that invokes part of the program as response to the interrupt occurrence. Between generation and delivery, the interrupt occurrence [(or interrupt)] is pending. Some or all interrupts may be blocked. When an interrupt is blocked, all occurrences of that interrupt are prevented from being delivered. Certain interrupts are reserved. The set of reserved interrupts is implementation defined. A reserved interrupt is either an interrupt for which user-defined handlers are not supported, or one which already has an attached handler by some other implementation-defined means. Program units can be connected to nonreserved interrupts. While connected, the program unit is said to be attached to that interrupt. The execution of that program unit, the interrupt handler, is invoked upon delivery of the interrupt occurrence.
While a handler is attached to an interrupt, it is called once for each delivered occurrence of that interrupt. While the handler executes, the corresponding interrupt is blocked.
While an interrupt is blocked, all occurrences of that interrupt are prevented from being delivered. Whether such occurrences remain pending or are lost is implementation defined.
Each interrupt has a default treatment which determines the system's response to an occurrence of that interrupt when no user-defined handler is attached. The set of possible default treatments is implementation defined, as is the method (if one exists) for configuring the default treatments for interrupts.
An interrupt is delivered to the handler (or default treatment) that is in effect for that interrupt at the time of delivery.
An exception propagated from a handler that is invoked by an interrupt has no effect.
[If the Ceiling_Locking policy (see D.3) is in effect, the interrupt handler executes with the active priority that is the ceiling priority of the corresponding protected object.]
Implementation Requirements
9/5The implementation shall provide a mechanism to determine the minimum stack space that is necessary for each interrupt handler and to reserve that space for the execution of the handler. [This space should accommodate nested invocations of the handler where the system permits this.]
If the hardware or the underlying system holds pending interrupt occurrences, the implementation shall provide for later delivery of these occurrences to the program.
If the Ceiling_Locking policy is not in effect, the implementation shall provide means for the application to specify whether interrupts are to be blocked during protected actions.
Documentation Requirements
12The implementation shall document the following items:
a)
- For each interrupt, which interrupts are blocked from delivery when a handler attached to that interrupt executes (either as a result of an interrupt delivery or of an ordinary call on a procedure of the corresponding protected object).
b)- Any interrupts that cannot be blocked, and the effect of attaching handlers to such interrupts, if this is permitted.
c)- Which run-time stack an interrupt handler uses when it executes as a result of an interrupt delivery; if this is configurable, what is the mechanism to do so; how to specify how much space to reserve on that stack.
d)- Any implementation- or hardware-specific activity that happens before a user-defined interrupt handler gets control (e.g., reading device registers, acknowledging devices).
e)- Any timing or other limitations imposed on the execution of interrupt handlers.
f)- The state (blocked/unblocked) of the nonreserved interrupts when the program starts; if some interrupts are unblocked, what is the mechanism a program can use to protect itself before it can attach the corresponding handlers.
g)- Whether the interrupted task is allowed to resume execution before the interrupt handler returns.
h)- The treatment of interrupt occurrences that are generated while the interrupt is blocked; i.e., whether one or more occurrences are held for later delivery, or all are lost.
i)- Whether predefined or implementation-defined exceptions are raised as a result of the occurrence of any interrupt, and the mapping between the machine interrupts (or traps) and the predefined exceptions.
j)- On a multi-processor, the rules governing the delivery of an interrupt to a particular processor.
Implementation Permissions
23/2If the underlying system or hardware does not allow interrupts to be blocked, then no blocking is required [as part of the execution of subprograms of a protected object for which one of its subprograms is an interrupt handler].
In a multi-processor with more than one interrupt subsystem, it is implementation defined whether (and how) interrupt sources from separate subsystems share the same Interrupt_Id type (see C.3.2). In particular, the meaning of a blocked or pending interrupt may then be applicable to one processor only.
Implementations are allowed to impose timing or other limitations on the execution of interrupt handlers.
Other forms of handlers are allowed to be supported, in which case the rules of this subclause should be adhered to.
The active priority of the execution of an interrupt handler is allowed to vary from one occurrence of the same interrupt to another.
Implementation Advice
28/2If the Ceiling_Locking policy is not in effect, the implementation should provide means for the application to specify which interrupts are to be blocked during protected actions, if the underlying system allows for finer-grained control of interrupt blocking.
C.3.1 Protected Procedure Handlers
Paragraphs 1 through 6 were moved to Annex J, “Obsolescent Features”.
Static Semantics
6.1/3For a parameterless protected procedure, the following language-defined representation aspects may be specified:
Interrupt_Handler
- The type of aspect Interrupt_Handler is Boolean. If directly specified, the aspect_definition shall be a static expression. [This aspect is never inherited;] if not directly specified, the aspect is False.
Attach_Handler
- The aspect Attach_Handler is an
expression
, which shall be of type Interrupts.Interrupt_Id. [This aspect is never inherited.]
Legality Rules
7/3If either the Attach_Handler or Interrupt_Handler aspect are specified for a protected procedure, the corresponding protected_type_declaration
or single_protected_declaration
shall be a library-level declaration and shall not be declared within a generic body. In addition to the places where Legality Rules normally apply (see 12.3), this rule also applies in the private part of an instance of a generic unit.
protected_type_declaration
, an object_declaration
of an object of that type need not be at library level.This paragraph was deleted.
Dynamic Semantics
9/3If the Interrupt_Handler aspect of a protected procedure is True, then the procedure may be attached dynamically, as a handler, to interrupts (see C.3.2). [Such procedures are allowed to be attached to multiple interrupts.]
The expression
specified for the Attach_Handler aspect of a protected procedure P is evaluated as part of the creation of the protected object that contains P. The value of the expression
identifies an interrupt. As part of the initialization of that object, P (the handler procedure) is attached to the identified interrupt. A check is made that the corresponding interrupt is not reserved. Program_Error is raised if the check fails, and the existing treatment for the interrupt is not affected.
If the Ceiling_Locking policy (see D.3) is in effect, then upon the initialization of a protected object that contains a protected procedure for which either the Attach_Handler aspect is specified or the Interrupt_Handler aspect is True, a check is made that the initial ceiling priority of the object is in the range of System.Interrupt_Priority. If the check fails, Program_Error is raised.
{8652/0068} When a protected object is finalized, for any of its procedures that are attached to interrupts, the handler is detached. If the handler was attached by a procedure in the Interrupts package or if no user handler was previously attached to the interrupt, the default treatment is restored. If the Attach_Handler aspect was specified and the most recently attached handler for the same interrupt is the same as the one that was attached at the time the protected object was initialized, the previous handler is restored.
When a handler is attached to an interrupt, the interrupt is blocked [(subject to the Implementation Permission in C.3)] during the execution of every protected action on the protected object containing the handler.
If restriction No_Dynamic_Attachment is in effect, then a check is made that the interrupt identified by an Attach_Handler aspect does not appear in any previously elaborated Attach_Handler aspect; Program_Error is raised if this check fails.
Erroneous Execution
14If the Ceiling_Locking policy (see D.3) is in effect and an interrupt is delivered to a handler, and the interrupt hardware priority is higher than the ceiling priority of the corresponding protected object, the execution of the program is erroneous.
{8652/0068} If the handlers for a given interrupt attached via aspect Attach_Handler are not attached and detached in a stack-like (LIFO) order, program execution is erroneous. In particular, when a protected object is finalized, the execution is erroneous if any of the procedures of the protected object are attached to interrupts via aspect Attach_Handler and the most recently attached handler for the same interrupt is not the same as the one that was attached at the time the protected object was initialized.
Metrics
15The following metric shall be documented by the implementation:
- The worst-case overhead for an interrupt handler that is a parameterless protected procedure, in clock cycles. This is the execution time not directly attributable to the handler procedure or the interrupted execution. It is estimated as C – (A+B), where A is how long it takes to complete a given sequence of instructions without any interrupt, B is how long it takes to complete a normal call to a given protected procedure, and C is how long it takes to complete the same sequence of instructions when it is interrupted by one execution of the same procedure called via an interrupt.
Implementation Permissions
17/3When the aspects Attach_Handler or Interrupt_Handler are specified for a protected procedure, the implementation is allowed to impose implementation-defined restrictions on the corresponding protected_type_declaration
and protected_body
.
An implementation may use a different mechanism for invoking a protected procedure in response to a hardware interrupt than is used for a call to that protected procedure from a task.
Notwithstanding what this subclause says elsewhere, the Attach_Handler and Interrupt_Handler aspects are allowed to be used for other, implementation defined, forms of interrupt handlers.
Implementation Advice
20Whenever possible, the implementation should allow interrupt handlers to be called directly by the hardware.
Whenever practical, the implementation should detect violations of any implementation-defined restrictions before run time.
Incompatibilities With Ada 95
Wording Changes from Ada 95
Extensions to Ada 2005
pragma
s Interrupt_Handler and Attach_Handler are now obsolescent. Wording Changes from Ada 2005
Inconsistencies With Ada 2012
C.3.2 The Package Interrupts
Static Semantics
1The following language-defined packages exist:
with System;
with System.Multiprocessors;
package Ada.Interrupts
with Nonblocking, Global => in out synchronized is
type Interrupt_Id is implementation-defined;
type Parameterless_Handler is
access protected procedure
with Nonblocking => False;
3/1This paragraph was deleted.
4function Is_Reserved (Interrupt : Interrupt_Id)
return Boolean;
5function Is_Attached (Interrupt : Interrupt_Id)
return Boolean;
6function Current_Handler (Interrupt : Interrupt_Id)
return Parameterless_Handler;
7procedure Attach_Handler
(New_Handler : in Parameterless_Handler;
Interrupt : in Interrupt_Id);
8procedure Exchange_Handler
(Old_Handler : out Parameterless_Handler;
New_Handler : in Parameterless_Handler;
Interrupt : in Interrupt_Id);
9procedure Detach_Handler
(Interrupt : in Interrupt_Id);
10function Reference (Interrupt : Interrupt_Id)
return System.Address;
10.1/3function Get_CPU (Interrupt : Interrupt_Id)
return System.Multiprocessors.CPU_Range;
11private
... -- not specified by the language
end Ada.Interrupts;
12/5package Ada.Interrupts.Names
with Nonblocking, Global => null is
implementation-defined : constant Interrupt_Id :=
implementation-defined;
. . .
implementation-defined : constant Interrupt_Id :=
implementation-defined;
end Ada.Interrupts.Names;
Dynamic Semantics
13The Interrupt_Id type is an implementation-defined discrete type used to identify interrupts.
The Is_Reserved function returns True if and only if the specified interrupt is reserved.
The Is_Attached function returns True if and only if a user-specified interrupt handler is attached to the interrupt.
{8652/0069} The Current_Handler function returns a value that represents the attached handler of the interrupt. If no user-defined handler is attached to the interrupt, Current_Handler returns null.
The Attach_Handler procedure attaches the specified handler to the interrupt, overriding any existing treatment (including a user handler) in effect for that interrupt. If New_Handler is null, the default treatment is restored. If New_Handler designates a protected procedure for which the aspect Interrupt_Handler is False, Program_Error is raised. In this case, the operation does not modify the existing interrupt treatment.
{8652/0069} The Exchange_Handler procedure operates in the same manner as Attach_Handler with the addition that the value returned in Old_Handler designates the previous treatment for the specified interrupt. If the previous treatment is not a user-defined handler, null is returned.
The Detach_Handler procedure restores the default treatment for the specified interrupt.
For all operations defined in this package that take a parameter of type Interrupt_Id, with the exception of Is_Reserved and Reference, a check is made that the specified interrupt is not reserved. Program_Error is raised if this check fails.
If, by using the Attach_Handler, Detach_Handler, or Exchange_Handler procedures, an attempt is made to detach a handler that was attached statically (using the aspect Attach_Handler), the handler is not detached and Program_Error is raised.
The Reference function returns a value of type System.Address that can be used to attach a task entry via an address clause (see J.7.1) to the interrupt specified by Interrupt. This function raises Program_Error if attaching task entries to interrupts (or to this particular interrupt) is not supported.
The function Get_CPU returns the processor on which the handler for Interrupt is executed. If the handler can execute on more than one processor the value System.Multiprocessors.Not_A_Specific_CPU is returned.
Implementation Requirements
23At no time during attachment or exchange of handlers shall the current handler of the corresponding interrupt be undefined.
Documentation Requirements
24/5The implementation shall document, when the Ceiling_Locking policy (see D.3) is in effect, the default ceiling priority assigned to a protected object that contains a protected procedure that specifies either the Attach_Handler or Interrupt_Handler aspects, but does not specify the Interrupt_Priority aspect. [This default can be different for different interrupts.]
Implementation Advice
25If implementation-defined forms of interrupt handler procedures are supported, such as protected procedures with parameters, then for each such form of a handler, a type analogous to Parameterless_Handler should be specified in a child package of Interrupts, with the same operations as in the predefined package Interrupts.
Examples
27Example of interrupt handlers:
Device_Priority : constant
array (Ada.Interrupts.Interrupt_Id range 1..5) of
System.Interrupt_Priority := ( ... );
protected type Device_Interface
(Int_Id : Ada.Interrupts.Interrupt_Id)
with Interrupt_Priority => Device_Priority(Int_Id) is
procedure Handler
with Attach_Handler => Int_Id;
...
end Device_Interface;
...
Device_1_Driver : Device_Interface(1);
...
Device_5_Driver : Device_Interface(5);
...
Wording Changes from Ada 95
Incompatibilities With Ada 2005
use_clause
, and an entity E with a defining_identifier
of Get_CPU is defined in a package that is also referenced in a use_clause
, the entity E may no longer be use-visible, resulting in errors. This should be rare and is easily fixed if it does occur.