9.2.1 Interrupt handling.
This optional annex introduces two new library packages Ada.Interrupts and its child Ada.Interrupts.Names which provide the ability to use Ada subprograms as interrupt handlers. Actual interrupt handler subprograms must be protected procedures, procedures declared within a protected type. This has one major benefit in that such a procedure cannot be called more than once simultaneously.
To assist the packages below two additional pragmas are also included in this annex.
pragma Interrupt_Handler(Handler_Name);
This pragma identifies a protected procedure which is to be used as an interrupt handler. It is not installed as a handler, this has to be done using the facilities in the packages below.
pragma Attach_Handler(Handler_Name, expression);
This pragma directly associates a protected procedure with a given interrupt to act as an interrupt handler.
Library Specification - package Ada.Interrupts
This provides the ability to attach a protected procedure to an interrupt identifier, also the subprograms Is_Reserved and Is_Attached can be used to enquire of the state of an interrupt and its associated handler.
Library Specification - example package Ada.Interrupts.Names
This child package simply provides a list of symbolic names and their interrupt ID's, the package is completely implementation dependant. The example above is completely contrived and denotes a standard configuration for a PC.
Now we can take all of this information and develop an interrupt handler for some arbitrary device attached to our first PC serial port.
with Ada.Interrupts; package body Our_Device is -- internal protected type Device_Handler is entry Read(Char : out Character); entry Write(Char : in Character); private procedure Handler; pragma Attach_Handler(Handler, Ada.Interrupts.Names.Serial_Port01); end Device_Handler; .. end Our_Device;
In this example you can see that we have used the pragma Attach_Handler to statically map the handler for our device to the serial port interrupt.
This solution, although perfectly legal may not be acceptable in some environments. For example if we run the resulting application we take possession of the interrupt, but what happens when our application terminates? Does the operating system return the original handler?
If this is an embedded application, or part of the operating system itself then such code is perfectly acceptable. If not then we need a way to manage the interrupt handlers more flexibly.
with Ada.Interrupts; use Ada; package body Our_Device is -- internal protected type Device_Handler is entry Read(Char : out Character); entry Write(Char : in Character); private procedure Handler; pragma Interrupt_Handler(Handler); end Device_Handler; .. Our_Interrupt : Interrupts.Interrupt_ID; Old_Handler : Interrupts.Parameterless_Handler:= null; begin Get_Our_Interrupt(Our_Interrupt); if Interrupts.Is_Attached(Our_Interrupt) then Interrupts.Exchange_Handler(Old_Handler, Device_Handler.Handler'Access, Our_Interrupt); else Interrupts.Attach_Handler(Device_Handler.Handler'Access, Our_Interrupt); end if; .. if Old_Handler = null then Interrupts.Detach_Handler(Our_Interrupt); else Interrupts.Attach_Handler(Old_Interrupt, Our_Interrupt); end if; end Our_Device;
In the example above we have used the more general facilities provided by the library package Ada.Interrupts to accomplish the same result. Note that if the interrupt we wish to use already has a handler then we carefully save it and restore it later.
Copyright ©
1996 Simon Johnston &
Addison Wesley Longman