Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Interrupt handler and Ada.Real_Time.Timing_Events

155 views
Skip to first unread message

Reto Buerki

unread,
May 15, 2009, 12:26:12 PM5/15/09
to
Hi,

I hit a rather strange issue today mixing signal/interrupt handling with
Ada.Real_Time.Timing_Events. We have a real life application where we
use timing events but we also need a signal handler to catch signals
from the environment (SIGTERM etc.).

I wrote a small reproducer to illustrate the problem. The following
protected object is used as an interrupt handler, which can be attached
to a specific interrupt/signal:

with Ada.Interrupts;

package Handlers is

protected type Signal_Handler (Signal : Ada.Interrupts.Interrupt_ID)
is
pragma Interrupt_Priority;

entry Wait;
private
procedure Handle_Signal;
pragma Attach_Handler (Handle_Signal, Signal);

Occured : Boolean := False;
end Signal_Handler;

end Handlers;

package body Handlers is

protected body Signal_Handler is
procedure Handle_Signal is
begin
Occured := True;
end Handle_Signal;

entry Wait when Occured is
begin
if Wait'Count = 0 then
Occured := False;
end if;
end Wait;
end Signal_Handler;

end Handlers;

The handler is used like this:

with Ada.Text_IO;
with Ada.Interrupts.Names;

-- Uncommenting the next line breaks interrupt handler
-- with Ada.Real_Time.Timing_Events;

with Handlers;

procedure Interrupt_Problem is
use Ada.Interrupts;

Handler : Handlers.Signal_Handler (Signal => Names.SIGTERM);
begin

if Is_Attached (Interrupt => Names.SIGTERM) then
Ada.Text_IO.Put_Line ("Attached handler to SIGTERM");
else
Ada.Text_IO.Put_Line ("Could not attach to SIGTERM!");
return;
end if;

Handler.Wait;
Ada.Text_IO.Put_Line ("Interrupt received ...");

end Interrupt_Problem;

As expected, when sending SIGTERM to the running 'Interrupt_Problem'
process "Interrupt received ..." is displayed. So far so good.

As commented in the source code, as soon as the
Ada.Real_Time.Timing_Events package is with'ed, this mechanism breaks.

The signal handler is not invoked any more when I send a SIGTERM signal
to a running 'Interrupt_Problem' process, it just terminates without
triggering the Handler.Wait.

What could be the cause for this behavior? Is there a problem with this
code?

Thanks in advance!
- reto

Adam Beneschan

unread,
May 15, 2009, 12:54:17 PM5/15/09
to

My guess would be that when Ada.Real_Time.Timing_Events is with'ed,
this causes elaboration code for the Timing_Events package to be
executed (before Interrupt_Problem), and there must be something that
this elaboration does that interferes with the Attach_Handler
mechanism. I can't find anything in the language definition of
Timing_Events that would cause this, so it must be a problem
particular to your Ada compiler implementation, and you should contact
the vendor, or at least let us know what compiler you're using so that
others who may have some knowledge of that particular compiler might
be able to help.


> Is there a problem with this
> code?

Yes, definitely: "occurred" is misspelled. It has two R's. I happen
to know this one very well because I blew this word (or another form,
like "occurrence") in my 8th-grade spelling bee by only putting one R
in it. So you've brought up some memories here.......

-- Adam

Ludovic Brenta

unread,
May 15, 2009, 12:56:54 PM5/15/09
to

Ada.Real_Time.Timing_Events's elaboration block creates a task and
promotes it to an outer level (i.e. it is no longer dependent on a
master). The only way to terminate this task is by sending it
SIGTERM, so the task attaches another signal handler to SIGTERM before
yours. That handler catches the signal and does not propagate it to
any other handler. See System.Task_Primitives.Operations.Initialize.

I'm afraid there is no way out :) maybe you can use another signal in
your task?

--
Ludovic Brenta.

Reto Buerki

unread,
May 15, 2009, 7:24:04 PM5/15/09
to
Adam Beneschan wrote:
> My guess would be that when Ada.Real_Time.Timing_Events is with'ed,
> this causes elaboration code for the Timing_Events package to be
> executed (before Interrupt_Problem), and there must be something that
> this elaboration does that interferes with the Attach_Handler
> mechanism. I can't find anything in the language definition of
> Timing_Events that would cause this, so it must be a problem
> particular to your Ada compiler implementation, and you should contact
> the vendor, or at least let us know what compiler you're using so that
> others who may have some knowledge of that particular compiler might
> be able to help.

I'm using FSF GNAT 4.3.2 on Debian Lenny.

>> Is there a problem with this
>> code?
>
> Yes, definitely: "occurred" is misspelled. It has two R's. I happen
> to know this one very well because I blew this word (or another form,
> like "occurrence") in my 8th-grade spelling bee by only putting one R
> in it. So you've brought up some memories here.......

Sorry for digging out your long buried trauma from the 8th-grade
spelling bee! This was not my intention and I will definitely correct
the "Occured" in my example ;)

Hibou57 (Yannick Duchêne)

unread,
May 15, 2009, 7:24:36 PM5/15/09
to
On 15 mai, 18:56, Ludovic Brenta <ludo...@ludovic-brenta.org> wrote:
> Ada.Real_Time.Timing_Events's elaboration block creates a task and
> promotes it to an outer level (i.e. it is no longer dependent on a
> master).  The only way to terminate this task is by sending it
> SIGTERM, so the task attaches another signal handler to SIGTERM before
> yours.  That handler catches the signal and does not propagate it to
> any other handler.  See System.Task_Primitives.Operations.Initialize.
>
> I'm afraid there is no way out :) maybe you can use another signal in
> your task?
>
> --
> Ludovic Brenta.

Do you know why it is not propagated ?
SIGTERM is supposed to be intended to the whole of an application, not
only to a pat of it.

Reto Buerki

unread,
May 15, 2009, 8:20:54 PM5/15/09
to

I tried attaching the handler to various signals. As soon as the timer
task is started in the Ada.Real_Time.Timing_Events elaboration block, my
own handler is not triggered any more. This seems odd.

We are using Ada.Real_Time.Timing_Events to implement an event-driven
architecture in our application. The Timing_Event type seemed perfect
for this.

Nevertheless, the application should still be able to react to signals
it may receive from the operating system. Is it really Timing_Events XOR
interrupt handling?

Jeffrey R. Carter

unread,
May 15, 2009, 8:38:54 PM5/15/09
to
Reto Buerki wrote:
>
> We are using Ada.Real_Time.Timing_Events to implement an event-driven
> architecture in our application. The Timing_Event type seemed perfect
> for this.

Timing_Events are certainly suited for this. However, they were added in the
most recent revision of the language. Event-driven systems were implemented in
Ada long before that revision. Should you be unable to get your application to
work with Timing_Events, you can use the old-fashioned way to achieve the same
thing. This is done by having tasks that execute delay statements and then call
the appropriate protected operations. Effectively, a Timing_Event object is
shorthand for such a task.

--
Jeff Carter
"From this day on, the official language of San Marcos will be Swedish."
Bananas
28

sjw

unread,
May 16, 2009, 2:28:47 AM5/16/09
to
On Mac OS X/GCC 4.3.3, the program as written outputs "raised
PROGRAM_ERROR : Interrupt 15 is reserved".

Changed to SIGUSR1: now runs as designed.

Sending SIGTERM is ignored (this seems odd).

Uncomment Timing_Events: doesn't report anything, but ps shows "User
defined signal 1 ./interrupt_problem" and when I run ps again the
process has gone.

This is all deep stuff (and apparently OS-dependent)! If I had this
sort of problem at work, I would raise a ticket with AdaCore straight
away.

anon

unread,
May 16, 2009, 7:05:11 AM5/16/09
to
This is a Timeing example that uses "Ada.Real_Time.Timing_Events" package.

Now, adding an interrupt handler to this design you should wrap the interrupt
handler within a Task routine bacuse "Ada.Real_Time.Timing_Events" uses
tasking for its underlying algorithm, then call the Timers Shutdown routine
once the interrupt has occurred.

--
-- generic_timers.ads
--
with Ada.Real_Time.Timing_Events ;

generic
Multi_Events : Boolean := True ;
Timer_Name : String := "Generic_Timers" ;
Interval : in Ada.Real_Time.Time_Span ;
with procedure Action is <> ;

package Generic_Timers is

Timer_Error : exception ;

procedure Activate ;
procedure Shutdown ;

private

The_Event : Ada.Real_Time.Timing_Events.Timing_Event ;

end Generic_Timers ;

--
-- generic_timers.adb
--
with Ada.Real_Time ;
use Ada.Real_Time ;

package body Generic_Timers is


protected Events is
procedure Handler ( Event: in out Timing_Events.Timing_Event ) ;
end Events ;

protected body Events is
procedure Handler ( Event: in out Timing_Events.Timing_Event ) is
begin
Action ;
if Multi_Events then
Activate ; -- periodic timer continues
end if ;
end Handler ;
end Events ;

procedure Activate is
use type Timing_Events.Timing_Event_Handler ;
begin
if Timing_Events.Current_Handler ( The_Event ) = null then
Timing_Events.Set_Handler ( The_Event,
Interval,
Events.Handler'Access ) ;
else
raise Timer_Error with "Activation " & Timer_Name ;
end if ;
end Activate ;

procedure Shutdown is
Success : Boolean := False ;
use type Timing_Events.Timing_Event_Handler ;
begin
if Timing_Events.Current_Handler ( The_Event ) /= null then
Timing_Events.Cancel_Handler ( The_Event, Success ) ;
if not Success then
raise Timer_Error with "Shutdown: " & Timer_Name ;
end if ;
end if ;
end Shutdown ;

end Generic_Timers ;

--
-- timers.ads
--
package Timers is

procedure Activate ;
procedure Shutdown ;

end Timers ;

--
-- Timers.adb
--
with Ada.Real_Time ;
with Ada.Text_IO ;

with Generic_Timers ;

package body Timers is

use Ada ;
use Real_Time ;
use Text_IO ;

------------------------------------
-- Define Periodic Event Timers --
------------------------------------
Periodic_Interval : constant Time_Span := Milliseconds ( 2000 ) ;
Periodic_Timer_ID : constant String := "Periodic Timer" ;

procedure Periodic_Action is
begin
Put_Line ( "Timeout: Periodic Timer" ) ;
end Periodic_Action ;

Package Periodic_Timer is new Generic_Timers ( True,
Periodic_Timer_ID,
Periodic_Interval,
Periodic_Action ) ;

----------------------------------
-- Define Single Event Timers --
----------------------------------
Single_Interval : constant Time_Span := Milliseconds ( 1000 ) ;
Single_Timer_ID : constant String := "Single Timer" ;

procedure Single_Action is
begin
Put_Line ( "Timeout: Single Timer " ) ;
end Single_Action ;

Package Single_Timer is new Generic_Timers ( False,
Single_Timer_ID,
Single_Interval,
Single_Action ) ;

----------------------------
-- Controlling Routines --
----------------------------

procedure Activate is
begin
Put_Line ( "Timers: Activate" ) ;

Periodic_Timer.Activate ;

for Index in 0 .. 3 loop
Single_Timer.Activate ;
delay 7.0 ;
end loop;
end Activate ;

procedure Shutdown is
begin
Put_Line ( "Timers: Shutdown" ) ;
Periodic_Timer.Shutdown ;
Single_Timer.Shutdown ;
end Shutdown;

end Timers ;

--
-- testing.adb
--
with Ada.Exceptions ;
with Ada.Text_IO ;

with Timers ;

procedure Testing is

use Ada ;
use Text_IO ;

begin

Put_Line ( "Testing : Begin" ) ;

Timers.Activate ;
delay 5.0 ;
Timers.Shutdown ;

Put_Line ( "Testing : End" ) ;
exception
when Error : others =>
Put_Line ( "Testing fails for because of ==> "
& Exceptions.Exception_Information ( Error ) ) ;
end Testing ;

Reto Buerki

unread,
May 29, 2009, 11:59:46 AM5/29/09
to
Jeffrey R. Carter wrote:
> Reto Buerki wrote:
>>
>> We are using Ada.Real_Time.Timing_Events to implement an event-driven
>> architecture in our application. The Timing_Event type seemed perfect
>> for this.
>
> Timing_Events are certainly suited for this. However, they were added in
> the most recent revision of the language. Event-driven systems were
> implemented in Ada long before that revision. Should you be unable to
> get your application to work with Timing_Events, you can use the
> old-fashioned way to achieve the same thing. This is done by having
> tasks that execute delay statements and then call the appropriate
> protected operations. Effectively, a Timing_Event object is shorthand
> for such a task.

Thanks for your answer. Re-implementing the Timing_Events functionality
seems to be the only possible solution for the moment.

I sent a bug report about this issue to rep...@adacore.com and added it
to the GCC bug database (bug #40285).

0 new messages