Ada Programming/Libraries/Ada.Interrupts
This language feature is available from Ada 95 on.
Ada.Interrupts is a unit of the Predefined Language Environment since Ada 95.
Introduction
editSometimes it's necessary for your program to be able to catch and handle interrupts such as SIGINT
, SIGTERM
or SIGHUP
, and for this we have the Ada.Interrupts package. Attaching handlers to interrupts can be done both statically and dynamically and, luckily, both methods are easy to grasp. The following program will show you both methods.
Example
editI've commented the program, so it should be fairly easy to understand what's going on. You can grab the entire program from this Git repository:
https://github.com/kjseefried/Catch_Signals
Git is available for all Linux distros. The commands to fetch Catch_Signals
using Git and then compile it are:
$ git clone https://github.com/kjseefried/Catch_Signals $ cd Catch_Signals $ gnatmake -P catch_signals.gpr
The executable can now be found in the exe/
directory.
If you don't feel like using Git, the full source code can be copied from below. I will of course do my best to make sure that the code on this page matches the code in the Git repository, but since this is a wiki where anybody can make changes, I cannot guarantee the safety of running the code on this page, so use it with caution.
The program attach signal handlers to these interrupts:
- SIGHUP
- SIGINT
- SIGPWR
- SIGTERM
You can send those interrupts to the running program like this:
kill -SIGHUP pid
Where pid
is the Process Id of the program.
catch_signals.gpr
editThis file sets up compile options. It informs the compiler of the location of the source files and where to put the object and the executable files. You must, of course, create the exe
and build
directories, if you haven't cloned the Git repository.
catch_signals.gpr
-------------------------------------------------------------------------------
-- --
-- Catch_Signals Project File --
-- --
-- Copyright (C) 2010, Thomas Løcke --
-- --
-- Catch_Signals is free software; you can redistribute it and/or modify --
-- it under terms of the GNU General Public License as published by the --
-- Free Software Foundation; either version 2, or (at your option) any --
-- later version. Catch_Signals is distributed in the hope that it will be --
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
-- General Public License for more details. You should have received a --
-- copy of the GNU General Public License distributed with Catch_Signals. --
-- If not, write to the Free Software Foundation, 51 Franklin Street, --
-- Fifth Floor, Boston, MA 02110 - 1301, USA. --
-- --
-------------------------------------------------------------------------------
project Catch_Signals is
for Source_Dirs use (".",
"src");
for Main use ("catch_signals.adb");
for Exec_Dir use "exe";
for Object_Dir use "build";
package Ide is
for Compiler_Command ("ada") use "gnatmake";
end Ide;
package Compiler is
Common_Options := ("-gnatwa",
"-gnaty3abcdefhiklmnoprstux",
"-Wall",
"-O2",
"-gnat05");
for Default_Switches ("Ada") use Common_Options;
end Compiler;
end Catch_Signals;
catch_signals.adb
editThis is the main program file. Not much happens here. We simply wait for an interrupt at the Process_Control.Wait
statement.
-------------------------------------------------------------------------------
-- --
-- Catch_Signals --
-- --
-- Copyright (C) 2010, Thomas Løcke --
-- --
-- Catch_Signals is free software; you can redistribute it and/or modify --
-- it under terms of the GNU General Public License as published by the --
-- Free Software Foundation; either version 2, or (at your option) any --
-- later version. Catch_Signals is distributed in the hope that it will be --
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Gene- --
-- ral Public License for more details. You should have received a copy --
-- of the GNU General Public License distributed with Catch_Signals. If --
-- not, write to the Free Software Foundation, 51 Franklin Street, --
-- Fifth Floor, Boston, MA 02110 - 1301, USA. --
-- --
-------------------------------------------------------------------------------
with Ada.Text_IO;
with Process_Control;
procedure Catch_Signals
is
use Ada.Text_IO;
begin
Put_Line ("Lets catch some interrupts!");
Process_Control.Wait;
-- Wait for an interrupt here. The program is "stuck" here until the
-- Process_State variable is set to Shutdown by one of the registered
-- interrupt handlers.
Put_Line ("Interrupt caught - shutting down.");
end Catch_Signals;
src/process_control.ads
editIn this file we define our interrupt handlers. For an example on how to dynamically attach an interrupt handler, take a look at the SIGHUP
code.
-------------------------------------------------------------------------------
-- --
-- Catch_Signals --
-- --
-- process_control --
-- --
-- SPEC --
-- --
-- Copyright (C) 2010, Thomas Løcke --
-- --
-- Catch_Signals is free software; you can redistribute it and/or modify --
-- it under terms of the GNU General Public License as published by the --
-- Free Software Foundation; either version 2, or (at your option) any --
-- later version. Catch_Signals is distributed in the hope that it will be --
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Gene- --
-- ral Public License for more details. You should have received a copy --
-- of the GNU General Public License distributed with Catch_Signals. If --
-- not, write to the Free Software Foundation, 51 Franklin Street, --
-- Fifth Floor, Boston, MA 02110 - 1301, USA. --
-- --
-------------------------------------------------------------------------------
with Ada.Interrupts.Names;
with Ada.Text_IO;
package Process_Control is
pragma Unreserve_All_Interrupts;
-- Make sure that GNAT does not handle any interrupts automatically.
-- As per GNAT 2010, this pragma only affects SIGINT.
procedure Wait;
-- Wait until Process_State is Shutdown.
private
type State is (Running, Shutdown, Stopped);
-- Define three different states of the running process.
package State_IO is new Ada.Text_IO.Enumeration_IO (State);
-- Instantiate a package so we can output the value of Process_State using
-- the familiar Put procedure.
Wait_Called : Boolean := False;
-- Set to True when Wait is called the first time.
protected Controller is
entry Check;
-- Check the Process_State is Shutdown, and if so, shut down the process
function Get_State return State;
-- Return the current Process_State.
procedure Handle_SIGINT;
procedure Handle_SIGPWR;
procedure Handle_SIGTERM;
pragma Attach_Handler (Handle_SIGINT, Ada.Interrupts.Names.SIGINT);
pragma Attach_Handler (Handle_SIGPWR, Ada.Interrupts.Names.SIGPWR);
pragma Attach_Handler (Handle_SIGTERM, Ada.Interrupts.Names.SIGTERM);
-- Statically attach handlers to the SIGINT, SIGPWR, SIGHUP and SIGTERM
-- interrupts.
procedure Handle_SIGHUP_Change_Handler;
procedure Handle_SIGHUP_Shutdown;
pragma Interrupt_Handler (Handle_SIGHUP_Change_Handler);
pragma Interrupt_Handler (Handle_SIGHUP_Shutdown);
-- Handle_SIGHUP_* can now be dynamically assigned using the
-- Ada.Interrupts.Attach_Handler procedure.
entry Start;
-- Set Process_State to Running.
private
Process_State : State := Stopped;
-- What state the process is in.
end Controller;
end Process_Control;
src/process_control.adb
editPay special attention to the Wait
procedure where the SIGHUP
interrupt is attached to the Handle_SIGHUP_Change_Handler
procedure, and later re-attached to the Handle_SIGHUP_Shutdown
procedure. This means that in order to kill the program using SIGHUP
, you have to do kill -SIGHUP pid
twice.
-------------------------------------------------------------------------------
-- --
-- Catch_Signals --
-- --
-- process_control --
-- --
-- BODY --
-- --
-- Copyright (C) 2010, Thomas Løcke --
-- --
-- Catch_Signals is free software; you can redistribute it and/or modify --
-- it under terms of the GNU General Public License as published by the --
-- Free Software Foundation; either version 2, or (at your option) any --
-- later version. Catch_Signals is distributed in the hope that it will be --
-- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Gene- --
-- ral Public License for more details. You should have received a copy --
-- of the GNU General Public License distributed with Catch_Signals. If --
-- not, write to the Free Software Foundation, 51 Franklin Street, --
-- Fifth Floor, Boston, MA 02110 - 1301, USA. --
-- --
-------------------------------------------------------------------------------
with Ada.Interrupts;
package body Process_Control is
------------
-- Wait --
------------
procedure Wait
is
use Ada.Interrupts;
use Ada.Text_IO;
use State_IO;
begin
if not Wait_Called then
Wait_Called := True;
Attach_Handler
(New_Handler => Controller.Handle_SIGHUP_Change_Handler'Access,
Interrupt => Ada.Interrupts.Names.SIGHUP);
-- Dynamically attach a handler to the SIGHUP interrupt.
Put ("Wait called. Process_State is ");
Put (Controller.Get_State);
New_Line;
Controller.Start;
Controller.Check;
end if;
end Wait;
------------------
-- Controller --
------------------
protected body Controller is
-------------
-- Check --
-------------
entry Check when Process_State = Shutdown
is
use Ada.Text_IO;
use State_IO;
begin
Put ("Check called. Process_State is ");
Put (Controller.Get_State);
New_Line;
end Check;
-----------------
-- Get_State --
-----------------
function Get_State return State
is
begin
return Process_State;
end Get_State;
------------------------------------
-- Handle_SIGHUP_Change_Handler --
------------------------------------
procedure Handle_SIGHUP_Change_Handler
is
use Ada.Interrupts;
use Ada.Text_IO;
begin
Put_Line ("Handle_SIGHUP_Change_Handler called.");
Put_Line
("Dynamically changing handler to Handle_SIGHUP_Shutdown.");
Put_Line ("Next SIGHUP will stop the program.");
Attach_Handler (New_Handler => Handle_SIGHUP_Shutdown'Access,
Interrupt => Ada.Interrupts.Names.SIGHUP);
-- Dynamically assign a new handler to the SIGHUP interrupt.
end Handle_SIGHUP_Change_Handler;
------------------------------
-- Handle_SIGHUP_Shutdown --
------------------------------
procedure Handle_SIGHUP_Shutdown
is
use Ada.Text_IO;
begin
Put_Line ("Handle_SIGHUP_Shutdown called.");
Process_State := Shutdown;
end Handle_SIGHUP_Shutdown;
---------------------
-- Handle_SIGINT --
---------------------
procedure Handle_SIGINT
is
use Ada.Text_IO;
begin
Put_Line ("Handle_SIGINT called.");
Process_State := Shutdown;
end Handle_SIGINT;
---------------------
-- Handle_SIGPWR --
---------------------
procedure Handle_SIGPWR
is
use Ada.Text_IO;
begin
Put_Line ("Handle_SIGPWR called.");
Process_State := Shutdown;
end Handle_SIGPWR;
----------------------
-- Handle_SIGTERM --
----------------------
procedure Handle_SIGTERM
is
use Ada.Text_IO;
begin
Put_Line ("Handle_SIGTERM called.");
Process_State := Shutdown;
end Handle_SIGTERM;
-------------
-- Start --
-------------
entry Start when Process_State = Stopped
is
use Ada.Text_IO;
use State_IO;
begin
Process_State := Running;
Put ("Start called. Process_State is ");
Put (Controller.Get_State);
New_Line;
Put_Line ("I will react on SIGHUP, SIGINT, SIGPWR and SIGTERM.");
end Start;
end Controller;
end Process_Control;
Specification
edit-- Standard Ada library specification -- Copyright (c) 2003-2018 Maxim Reznik <reznikmm@gmail.com> -- Copyright (c) 2004-2016 AXE Consultants -- Copyright (c) 2004, 2005, 2006 Ada-Europe -- Copyright (c) 2000 The MITRE Corporation, Inc. -- Copyright (c) 1992, 1993, 1994, 1995 Intermetrics, Inc. -- SPDX-License-Identifier: BSD-3-Clause and LicenseRef-AdaReferenceManual -- -------------------------------------------------------------------------with
System;package
Ada.Interruptsis
type
Interrupt_IDis
(Implementation_Defined);type
Parameterless_Handleris
access
protected
procedure
;function
Is_Reserved (Interrupt :in
Interrupt_ID)return
Boolean;function
Is_Attached (Interrupt :in
Interrupt_ID)return
Boolean;function
Current_Handler (Interrupt :in
Interrupt_ID)return
Parameterless_Handler;procedure
Attach_Handler (New_Handler :in
Parameterless_Handler; Interrupt :in
Interrupt_ID);procedure
Exchange_Handler (Old_Handler :out
Parameterless_Handler; New_Handler :in
Parameterless_Handler; Interrupt :in
Interrupt_ID);procedure
Detach_Handler (Interrupt :in
Interrupt_ID);function
Reference (Interrupt :in
Interrupt_ID)return
System.Address;private
end
Ada.Interrupts;
See also
editWikibook
editExternal examples
edit- Search for examples of
Ada.Interrupts
in: Rosetta Code, GitHub (gists), any Alire crate or this Wikibook. - Search for posts related to
Ada.Interrupts
in: Stack Overflow, comp.lang.ada or any Ada related page.
Ada Reference Manual
editAda 95
editAda 2005
editAda 2012
editOpen-Source Implementations
editFSF GNAT
- Specification: a-interr.ads
- Body: a-interr.adb
drake
- Specification: tasking/a-interr.ads
- Body: tasking/a-interr.adb