comp.lang.ada
 help / color / mirror / Atom feed
* Barrier re-evaluation issue with GNAT 4.3.2
@ 2009-09-24 17:02 Reto Buerki
  2009-09-24 17:47 ` Dmitry A. Kazakov
  2009-09-25 15:56 ` John B. Matthews
  0 siblings, 2 replies; 31+ messages in thread
From: Reto Buerki @ 2009-09-24 17:02 UTC (permalink / raw)


Hi,

The test code below implements a simple alarm clock which should wakeup
the task waiting on the "Wait_For_Wakeup" entry.

With GNAT 4.3.2 on Debian/stable this does not work. The main task
remains queued on the entry even though the Wakeup-handler is invoked
correctly by the Timing_Event.

Compiling the same code with GNAT 4.4.1-5 (on Debian/SID) or GNAT GPL
2009 leads to the expected behavior: The main task terminates after the
alarm has fired. This indicates a bug in FSF GNAT 4.3.2.

--------------------

with Ada.Text_IO;
with Alarm_Clock;

procedure Main is
   My_Alarm : Alarm_Clock.Alarm_Type;
begin
   Ada.Text_IO.Put_Line ("Starting alarm ...");
   My_Alarm.Start;

   Ada.Text_IO.Put_Line ("Waiting for alarm ...");
   My_Alarm.Wait_For_Wakeup;

   Ada.Text_IO.Put_Line ("ALARM!!");
end Main;

--------------------

with Ada.Real_Time.Timing_Events;

package Alarm_Clock is

   use Ada.Real_Time;

   protected type Alarm_Type is
      procedure Start;
      procedure Wakeup (Event : in out Timing_Events.Timing_Event);
      entry Wait_For_Wakeup;
   private
      Timer       : Timing_Events.Timing_Event;
      Alarm_Fired : Boolean := False;
   end Alarm_Type;

end Alarm_Clock;

--------------------

package body Alarm_Clock is

   protected body Alarm_Type is
      procedure Start is
      begin
         Timer.Set_Handler (In_Time => Seconds (3),
                            Handler => Wakeup'Access);
      end Start;

      procedure Wakeup (Event : in out Timing_Events.Timing_Event) is
      begin
         Alarm_Fired := True;
      end Wakeup;

      entry Wait_For_Wakeup when Alarm_Fired is
      begin
         null;
      end Wait_For_Wakeup;
   end Alarm_Type;

end Alarm_Clock;

--------------------

Avoiding the usage of Ada.Real_Time.Timing_Events by implementing a
delaying task does not solve the problem. So it's not Ada real time related.

We suspect that the Alarm_Fired-barrier of the Wait_For_Wakeup entry is
not correctly re-evaluated after the Wakeup()-handler has been called.

Switching the compiler is a solution we consider as last resort.

Does anybody know what the actual problem could be? Is there a different
way to implement the same functionality or a "workaround" which would
avoid this problem?

Thanks in advance,
- reto



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-24 17:02 Barrier re-evaluation issue with GNAT 4.3.2 Reto Buerki
@ 2009-09-24 17:47 ` Dmitry A. Kazakov
  2009-09-25  8:50   ` Brad Moore
  2009-09-28 10:18   ` Reto Buerki
  2009-09-25 15:56 ` John B. Matthews
  1 sibling, 2 replies; 31+ messages in thread
From: Dmitry A. Kazakov @ 2009-09-24 17:47 UTC (permalink / raw)


On Thu, 24 Sep 2009 19:02:14 +0200, Reto Buerki wrote:

> The test code below implements a simple alarm clock which should wakeup
> the task waiting on the "Wait_For_Wakeup" entry.
> 
> With GNAT 4.3.2 on Debian/stable this does not work. The main task
> remains queued on the entry even though the Wakeup-handler is invoked
> correctly by the Timing_Event.
> 
> Compiling the same code with GNAT 4.4.1-5 (on Debian/SID) or GNAT GPL
> 2009 leads to the expected behavior: The main task terminates after the
> alarm has fired. This indicates a bug in FSF GNAT 4.3.2.

It also works under GNAT Pro 6.2.1.

[...]

> Avoiding the usage of Ada.Real_Time.Timing_Events by implementing a
> delaying task does not solve the problem. So it's not Ada real time related.
> 
> We suspect that the Alarm_Fired-barrier of the Wait_For_Wakeup entry is
> not correctly re-evaluated after the Wakeup()-handler has been called.
> 
> Switching the compiler is a solution we consider as last resort.

Switching to a never version looks plausible to me.
 
> Does anybody know what the actual problem could be? Is there a different
> way to implement the same functionality or a "workaround" which would
> avoid this problem?

I was always wondering the rationale behind introducing
Ada.Real_Time.Timing_Events. The delay statement does the very same thing:

with Ada.Real_Time;  use Ada.Real_Time;
   ...
   Event : Time;
begin
   ...
   Put_Line ("Starting alarm ...");
   Event := Clock + To_Time_Span (3.0);

   Put_Line ("Waiting for alarm ...");
   delay until Event;
   Put_Line ("ALARM!!");

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-24 17:47 ` Dmitry A. Kazakov
@ 2009-09-25  8:50   ` Brad Moore
  2009-09-25  9:17     ` Dmitry A. Kazakov
  2009-09-28 10:18   ` Reto Buerki
  1 sibling, 1 reply; 31+ messages in thread
From: Brad Moore @ 2009-09-25  8:50 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> I was always wondering the rationale behind introducing
> Ada.Real_Time.Timing_Events. The delay statement does the very same thing:
> 
> with Ada.Real_Time;  use Ada.Real_Time;
>    ...
>    Event : Time;
> begin
>    ...
>    Put_Line ("Starting alarm ...");
>    Event := Clock + To_Time_Span (3.0);
> 
>    Put_Line ("Waiting for alarm ...");
>    delay until Event;
>    Put_Line ("ALARM!!");
> 

In this trivial example, a simple delay is probably all you need.

However, consider a slightly different twist on the alarm example.
Suppose you have a burglar alarm where if you trip the alarm
you have 1 minute to correctly enter the security code, or
the police are called. If you correctly enter the code in time
the alarm is canceled. This gets you into the realm where
the timing events package is more useful.

You could accomplish this also using a task to monitor the timeout, but 
that could be considered a "heavier" approach depending on the 
implementation of the timing events package. Timing events provide a 
simpler abstraction, if all you want is an event to fire at sometime in 
the future. Plus if you have many such sort of events in a program, you 
could potentially save yourself from having to add tasks for each event 
you want to monitor, resulting in less system resources being used.

Brad

--------------------------------------------

eg.

with Ada.Text_IO; use Ada;

with Burglar_Alarm;

procedure Test_Timers is
    My_Alarm : Burglar_Alarm.Alarm_Type;
    Code : Burglar_Alarm.Security_Code_Type;
begin
    Text_IO.Put_Line ("Tripping alarm ...");
    Burglar_Alarm.Trip (My_Alarm);

    while Burglar_Alarm.Is_Tripped (My_Alarm) loop
       begin

          Text_IO.Put_Line ("Enter Security Code: ");
          Code := Burglar_Alarm.Security_Code_Type'Value (Text_IO.Get_Line);
          Burglar_Alarm.Disarm (Alarm => My_Alarm,
                                Key   => Code);
       exception
          when Constraint_Error =>
             null; -- Silently ignore bad codes
       end;
    end loop;

    Text_IO.Put_Line ("Entered Correct Code!");

end Test_Timers;

------------------------------------------------------------

with Ada.Real_Time.Timing_Events; use Ada.Real_Time;

package Burglar_Alarm is

    type Alarm_Type is limited private;

    procedure Trip
      (Alarm : in out Alarm_Type);

    type Security_Code_Type is range 0 .. 9999;

    procedure Disarm
      (Alarm : in out Alarm_Type;
       Key : Security_Code_Type);
    --  Once an Alarm has been tripped, you have
    --  1 minute to enter the security code to
    --  disable the alarm, or else the police are called

    function Is_Tripped (Alarm : Alarm_Type) return Boolean;

private
    protected type Alarm_Type is
       function Is_Tripped return Boolean;
       procedure Start_Timer;
       procedure Disarm (Key : Security_Code_Type);
       procedure Call_Police (Event : in out Timing_Events.Timing_Event);
    private
       Timer       : Timing_Events.Timing_Event;
       Tripped     : Boolean := False;
       Sound_Alarm : Boolean := False;
       Security_Code : Security_Code_Type := 1234; --  set to some 
unique value;
    end Alarm_Type;
end Burglar_Alarm;

----------------------------------------------------------

with Ada.Text_IO; use Ada;
package body Burglar_Alarm is

    protected body Alarm_Type is

       procedure Call_Police (Event : in out Timing_Events.Timing_Event) is
          pragma Unreferenced (Event);
       begin
          Text_IO.Put_Line ("Come out with your hands up!");
       end Call_Police;

       procedure Disarm (Key : Security_Code_Type) is
          Cancelled : Boolean;
       begin
          if Key = Security_Code then
             Timer.Cancel_Handler (Cancelled);
             Tripped := False;
          end if;
       end Disarm;

       function Is_Tripped return Boolean is
       begin
          return Tripped;
       end Is_Tripped;

       procedure Start_Timer is
       begin
          Tripped := True;
          Timer.Set_Handler (In_Time => Minutes (1),
                             Handler => Call_Police'Access);
       end Start_Timer;

    end Alarm_Type;

    procedure Disarm
      (Alarm : in out Alarm_Type;
       Key : Security_Code_Type) is
    begin
       Alarm.Disarm (Key);
    end Disarm;

    function Is_Tripped (Alarm : Alarm_Type) return Boolean is
    begin
       return Alarm.Is_Tripped;
    end Is_Tripped;

    procedure Trip (Alarm : in out Alarm_Type) is
    begin
       Alarm.Start_Timer;
    end Trip;

end Burglar_Alarm;



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25  8:50   ` Brad Moore
@ 2009-09-25  9:17     ` Dmitry A. Kazakov
  2009-09-25  9:57       ` Ludovic Brenta
                         ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Dmitry A. Kazakov @ 2009-09-25  9:17 UTC (permalink / raw)


On Fri, 25 Sep 2009 02:50:32 -0600, Brad Moore wrote:

> Dmitry A. Kazakov wrote:
>> I was always wondering the rationale behind introducing
>> Ada.Real_Time.Timing_Events. The delay statement does the very same thing:
>> 
>> with Ada.Real_Time;  use Ada.Real_Time;
>>    ...
>>    Event : Time;
>> begin
>>    ...
>>    Put_Line ("Starting alarm ...");
>>    Event := Clock + To_Time_Span (3.0);
>> 
>>    Put_Line ("Waiting for alarm ...");
>>    delay until Event;
>>    Put_Line ("ALARM!!");
> 
> In this trivial example, a simple delay is probably all you need.
> 
> However, consider a slightly different twist on the alarm example.
> Suppose you have a burglar alarm where if you trip the alarm
> you have 1 minute to correctly enter the security code, or
> the police are called. If you correctly enter the code in time
> the alarm is canceled. This gets you into the realm where
> the timing events package is more useful.
> 
> You could accomplish this also using a task to monitor the timeout, but 
> that could be considered a "heavier" approach depending on the 
> implementation of the timing events package. Timing events provide a 
> simpler abstraction, if all you want is an event to fire at sometime in 
> the future. Plus if you have many such sort of events in a program, you 
> could potentially save yourself from having to add tasks for each event 
> you want to monitor, resulting in less system resources being used.

You must do it per a monitor task anyway. Your design is not scalable, and
the code is not conformant to Ada, because you are using potentially
blocking Put_Line within a protected action (in Call_Police).

When an alarm is triggered, that happens at the context of a protected
action. The protected action is quite limited to what you could do there.
That is only non-blocking and *very* short stuff. This means that you won't
be able to "call police" from there. You could set some flags, but you
could not initiate any "non-instant" action otherwise than by releasing a
task. Non-instant actions are for tasks. You need a task. If the key input
task gets blocked beyond reach of asynchronous transfer of control, which
is your case, because Ada does not require Text_IO abortable (yet
misleadingly provides an example of in RM (:-)), anyway, that means, you
inescapably need a second task.  

-----------
Timing_Events does not have any advantages over delay or asynchronous
transfer of control. I guess it was provided for some low-level stuff like
interrupts from hardware timers. However there was already a support for
interrupts mapped into protected operations, so it really puzzles me why
Timing_Events were added.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25  9:17     ` Dmitry A. Kazakov
@ 2009-09-25  9:57       ` Ludovic Brenta
  2009-09-25 10:31         ` Dmitry A. Kazakov
  2009-09-25 11:23       ` Jean-Pierre Rosen
  2009-09-25 17:06       ` Brad Moore
  2 siblings, 1 reply; 31+ messages in thread
From: Ludovic Brenta @ 2009-09-25  9:57 UTC (permalink / raw)


Dmitry A. Kazakov wrote on comp.lang.ada:
> Timing_Events does not have any advantages over delay or asynchronous
> transfer of control. I guess it was provided for some low-level stuff like
> interrupts from hardware timers. However there was already a support for
> interrupts mapped into protected operations, so it really puzzles me why
> Timing_Events were added.

The reasons are explained in AI95-297. It seems you've never written
any low-level code before, or cared about it?

[1] http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ais/ai-00297.txt?rev=1.25

--
Ludovic Brenta.



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25  9:57       ` Ludovic Brenta
@ 2009-09-25 10:31         ` Dmitry A. Kazakov
  0 siblings, 0 replies; 31+ messages in thread
From: Dmitry A. Kazakov @ 2009-09-25 10:31 UTC (permalink / raw)


On Fri, 25 Sep 2009 02:57:42 -0700 (PDT), Ludovic Brenta wrote:

> Dmitry A. Kazakov wrote on comp.lang.ada:
>> Timing_Events does not have any advantages over delay or asynchronous
>> transfer of control. I guess it was provided for some low-level stuff like
>> interrupts from hardware timers. However there was already a support for
>> interrupts mapped into protected operations, so it really puzzles me why
>> Timing_Events were added.
> 
> The reasons are explained in AI95-297. It seems you've never written
> any low-level code before, or cared about it?

... cared not to write lower-level code. (:-))

> [1] http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ais/ai-00297.txt?rev=1.25

The example of changing task priorities looks artificial to me. I don't
think a "normal" concurrent applications could benefit from Timing_Events.
There were much more pressing problems than this one (making tasks and
protected objects tagged, working task components of controlled objects
etc.)

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25  9:17     ` Dmitry A. Kazakov
  2009-09-25  9:57       ` Ludovic Brenta
@ 2009-09-25 11:23       ` Jean-Pierre Rosen
  2009-09-28 10:41         ` Reto Buerki
  2009-09-25 17:06       ` Brad Moore
  2 siblings, 1 reply; 31+ messages in thread
From: Jean-Pierre Rosen @ 2009-09-25 11:23 UTC (permalink / raw)


Dmitry A. Kazakov a �crit :
> Timing_Events does not have any advantages over delay or asynchronous
> transfer of control. I guess it was provided for some low-level stuff like
> interrupts from hardware timers. However there was already a support for
> interrupts mapped into protected operations, so it really puzzles me why
> Timing_Events were added.
> 
The answer is easy: because users asked for it. Of course, it is
useless, but some people don't feel easy with tasks, and want to use the
kind of tools they are accustomed to.

So rather than painfully answering requests like "why doesn't Ada have
that feature", it was simpler to say "what's the heck" and provide it.
If you don't like it (I am also in that case), don't use it.

-- 
---------------------------------------------------------
           J-P. Rosen (rosen@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-24 17:02 Barrier re-evaluation issue with GNAT 4.3.2 Reto Buerki
  2009-09-24 17:47 ` Dmitry A. Kazakov
@ 2009-09-25 15:56 ` John B. Matthews
  2009-09-26 14:23   ` John B. Matthews
  2009-09-28 10:28   ` Reto Buerki
  1 sibling, 2 replies; 31+ messages in thread
From: John B. Matthews @ 2009-09-25 15:56 UTC (permalink / raw)


In article <h9g8mf$v4f$1@news.eternal-september.org>,
 Reto Buerki <reet@codelabs.ch> wrote:

> The test code below implements a simple alarm clock which should 
> wakeup the task waiting on the "Wait_For_Wakeup" entry.
> 
> With GNAT 4.3.2 on Debian/stable this does not work. The main task 
> remains queued on the entry even though the Wakeup-handler is invoked 
> correctly by the Timing_Event.
> 
> Compiling the same code with GNAT 4.4.1-5 (on Debian/SID) or GNAT GPL 
> 2009 leads to the expected behavior: The main task terminates after 
> the alarm has fired. This indicates a bug in FSF GNAT 4.3.2.

I get the same result with FSF GNAT 4.3.4. I revised your code to follow 
the "protected Event" example seen here:

<http://www.adaic.com/standards/95rat/RAThtml/rat95-p1-2.html#9>

It seems to work. The compiler warns, "potentially blocking operation in 
protected operation" in Wakeup, although the Signal barrier is always 
true. I'm not sure the extra entries _should_ be required, but I think 
it might be more reliable in the face of multiple threads calling Wait. 
I don't know a reason why it wouldn't work under 4.3.2.

with Ada.Text_IO;
with Alarm_Clock;

procedure Main is
   My_Alarm : Alarm_Clock.Alarm_Type;
begin
   Ada.Text_IO.Put_Line ("Starting alarm ...");
   My_Alarm.Start;

   Ada.Text_IO.Put_Line ("Waiting for alarm ...");
   My_Alarm.Wait;

   Ada.Text_IO.Put_Line ("ALARM!!");
end Main;

package Alarm_Clock is

   use Ada.Real_Time;

   protected type Alarm_Type is
      entry Wait;
      entry Signal;
      procedure Start;
      procedure Wakeup(Event : in out Timing_Events.Timing_Event);

   private
      entry Reset;
      Alarm : Boolean := False;
   end Alarm_Type;

end Alarm_Clock;

package body Alarm_Clock is

   Timer : Timing_Events.Timing_Event;

   protected body Alarm_Type is

      procedure Start is
      begin
         Timer.Set_Handler(In_Time => Seconds (1),
                           Handler => Wakeup'Access);
      end Start;

      procedure Wakeup(Event : in out Timing_Events.Timing_Event) is
      begin
         Alarm := True;
         Signal;
      end Wakeup;

      entry Wait when Alarm is
      begin
         null;
      end Wait;

      entry Signal when True is
      begin
         if Wait'Count > 0 then
            Alarm := True;
            requeue Reset;
         end if;
      end Signal;

      entry Reset when Wait'Count = 0 is
      begin
         Alarm := False;
      end Reset;

   end Alarm_Type;

end Alarm_Clock;

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25  9:17     ` Dmitry A. Kazakov
  2009-09-25  9:57       ` Ludovic Brenta
  2009-09-25 11:23       ` Jean-Pierre Rosen
@ 2009-09-25 17:06       ` Brad Moore
  2009-09-25 18:42         ` Dmitry A. Kazakov
  2 siblings, 1 reply; 31+ messages in thread
From: Brad Moore @ 2009-09-25 17:06 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> You must do it per a monitor task anyway. Your design is not scalable, and
> the code is not conformant to Ada, because you are using potentially
> blocking Put_Line within a protected action (in Call_Police).
> 
> When an alarm is triggered, that happens at the context of a protected
> action. The protected action is quite limited to what you could do there.
> That is only non-blocking and *very* short stuff. This means that you won't
> be able to "call police" from there. You could set some flags, but you
> could not initiate any "non-instant" action otherwise than by releasing a
> task. Non-instant actions are for tasks. You need a task. If the key input
> task gets blocked beyond reach of asynchronous transfer of control, which
> is your case, because Ada does not require Text_IO abortable (yet
> misleadingly provides an example of in RM (:-)), anyway, that means, you
> inescapably need a second task.  

A real implementation of Call_Police would hopefully have more effect 
then just printing a message to a console. Yes, Text_IO.Put_Line is 
potentially blocking and clouds the example, thanks for catching that. 
Conceivably though, it may be possible to use some other console output 
that is non-blocking if Call_Police really does need to log something to 
a console. Also, Call_Police does not necessarily need to involve a 
task. For example, it may simply raise a signal on some hardware device 
that calls 911, or turns on a siren, or flashing lights or whatever.
Even if it does perform some protected operation that kicks off another 
task, the timing event approach might hold appeal to some, or be more of 
an appropriate design choice, though in that case, I would probably 
recommend at least considering some other approach such as the use a 
timed/conditional entry call.

Timing_Events should handle a reasonable number of events in the system. 
If your application has millions of these firing all over the place, 
then scalability could become an issue, and perhaps for such a system, 
some alternate design would be more appropriate.

> 
> -----------
> Timing_Events does not have any advantages over delay or asynchronous
> transfer of control. I guess it was provided for some low-level stuff like
> interrupts from hardware timers. However there was already a support for
> interrupts mapped into protected operations, so it really puzzles me why
> Timing_Events were added.
> 

I see timing events as being potentially useful reusable concurrency 
component.
If you ever need something that looks like timing_events, then hopefully
it will save you from having to write your own. It may have utility in 
some areas such as discrete event simulation, for example, if you need 
something to coordinate multiple tasks and ensure that signalling events 
occur and run to completion before before signaling subsequent events.

Whether timing_events is something that will be used a lot in practice 
is another question. I worked on a legacy system (written in Ada 83)
that had a package very similar to timing_events. It was used to
trigger timeouts in a run-to-completion tasking model.
In that environment, the creation of tasks was discouraged, and only
allowed if absolutely necessary. This timing_events package provided a 
convenient way to coordinate the existing tasks and trigger things to 
happen in the future without having to introduce more tasks in the 
system. Of course, as with the standard timing_package, timing events
need to be non-blocking and fast. Had the standard timing package
existed at that time, we probably would have used that instead.

If I were building the system again from scratch, though, maybe I 
wouldn't use timing_events at all.

I suspect that some people will find timing_events to be useful for 
specific types of applications, but probably will not be used on any 
grand scale. I think mostly people should/will want to use other 
existing synchronization mechanisms in Ada to coordinate tasks.

Brad



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25 17:06       ` Brad Moore
@ 2009-09-25 18:42         ` Dmitry A. Kazakov
  2009-09-25 19:39           ` Brad Moore
  0 siblings, 1 reply; 31+ messages in thread
From: Dmitry A. Kazakov @ 2009-09-25 18:42 UTC (permalink / raw)


On Fri, 25 Sep 2009 11:06:05 -0600, Brad Moore wrote:

> Dmitry A. Kazakov wrote:
>> You must do it per a monitor task anyway. Your design is not scalable, and
>> the code is not conformant to Ada, because you are using potentially
>> blocking Put_Line within a protected action (in Call_Police).
>> 
>> When an alarm is triggered, that happens at the context of a protected
>> action. The protected action is quite limited to what you could do there.
>> That is only non-blocking and *very* short stuff. This means that you won't
>> be able to "call police" from there. You could set some flags, but you
>> could not initiate any "non-instant" action otherwise than by releasing a
>> task. Non-instant actions are for tasks. You need a task. If the key input
>> task gets blocked beyond reach of asynchronous transfer of control, which
>> is your case, because Ada does not require Text_IO abortable (yet
>> misleadingly provides an example of in RM (:-)), anyway, that means, you
>> inescapably need a second task.  
> 
> A real implementation of Call_Police would hopefully have more effect 
> then just printing a message to a console. Yes, Text_IO.Put_Line is 
> potentially blocking and clouds the example, thanks for catching that. 
> Conceivably though, it may be possible to use some other console output 
> that is non-blocking if Call_Police really does need to log something to 
> a console. Also, Call_Police does not necessarily need to involve a 
> task. For example, it may simply raise a signal on some hardware device 
> that calls 911, or turns on a siren, or flashing lights or whatever.

This would mean that the hardware device encapsulated that task (e.g. HDD
controller). I don't think this could be considered a realistic scenario.
Hardware I/O on most platforms is too slow to be performed from a protected
action. If you have an OS, it is 10-100 times slower, at least. Doing this
within a protected action is not a good idea. One can imagine protected
action as a being performed by a task with highest real-time priority.
Without OS, considering low-level I/O, like DAQ boards, DMA access etc, the
performance penalty might be even higher.

> Timing_Events should handle a reasonable number of events in the system. 
> If your application has millions of these firing all over the place, 
> then scalability could become an issue, and perhaps for such a system, 
> some alternate design would be more appropriate.

No, because these events need to be handled by somewhere. Million events
handled by one task? That is the monitor task taking the shortest delay
from a queue of. Million tasks will not work anyway.

Speaking generally, IMO, the design should be driven by the worker tasks
rather than by events, because the system load is inflicted by the workers,
not by event propagation. An event implemented by protected actions are in
effect synchronous or else you have some task that reads out some queue of
events. There is no way to work around this. Either you process the event
right at the spot it was triggered (=you don't have events at all), or else
you postpone event handling to another task later. The bottom line, events
need tasks or else do not exist...

>> -----------
>> Timing_Events does not have any advantages over delay or asynchronous
>> transfer of control. I guess it was provided for some low-level stuff like
>> interrupts from hardware timers. However there was already a support for
>> interrupts mapped into protected operations, so it really puzzles me why
>> Timing_Events were added.
> 
> I see timing events as being potentially useful reusable concurrency 
> component.
> If you ever need something that looks like timing_events, then hopefully
> it will save you from having to write your own. It may have utility in 
> some areas such as discrete event simulation, for example, if you need 
> something to coordinate multiple tasks and ensure that signalling events 
> occur and run to completion before before signaling subsequent events.

This is IMO a different case, e.g. pulse events. Yes I have an
implementation of pulse events. But I don't see why pulse events cannot be
signaled from a scheduler task. The event source is unrelated to the way an
event is handled. Basically Timing_Events saves you exactly one "scheduler"
task, keeping in mind that the implementation of could deploy some hidden
task (thread) anyway. It does not save you the worker task(s).

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25 18:42         ` Dmitry A. Kazakov
@ 2009-09-25 19:39           ` Brad Moore
  0 siblings, 0 replies; 31+ messages in thread
From: Brad Moore @ 2009-09-25 19:39 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> This would mean that the hardware device encapsulated that task (e.g. HDD
> controller). I don't think this could be considered a realistic scenario.
> Hardware I/O on most platforms is too slow to be performed from a protected
> action. If you have an OS, it is 10-100 times slower, at least. Doing this
> within a protected action is not a good idea. One can imagine protected
> action as a being performed by a task with highest real-time priority.
> Without OS, considering low-level I/O, like DAQ boards, DMA access etc, the
> performance penalty might be even higher.

I was thinking more along the lines of changing the voltage of some 
output port on some device, or writing directly to the console buffer, 
rather than invoking some dialog with a HDD controller.
Depending on the device, it may be as simple as writing a single value 
to some memory address. Technically, this is a non-blocking scenario. It 
may (or may not) be slower than normal memory writes, but still 
satisfies RM 9.5.1(8). Just because it is protected, does not mean it 
cannot be preempted by a higher priority (e.g. interrupt) task. It wont 
cause deadlock. I think this is very much a realistic scenario.

> 
>> Timing_Events should handle a reasonable number of events in the system. 
>> If your application has millions of these firing all over the place, 
>> then scalability could become an issue, and perhaps for such a system, 
>> some alternate design would be more appropriate.
> 
> No, because these events need to be handled by somewhere. Million events
> handled by one task? That is the monitor task taking the shortest delay
> from a queue of. Million tasks will not work anyway.

I was agreeing with you that scalability could become an issue. 
Channeling everything through a single timer task (if that is how it is 
implemented) could introduce unacceptable latencies, if the number 
events grows too large.

>>> Timing_Events does not have any advantages over delay or asynchronous
>>> transfer of control. I guess it was provided for some low-level stuff like
>>> interrupts from hardware timers. However there was already a support for
>>> interrupts mapped into protected operations, so it really puzzles me why
>>> Timing_Events were added.
>> I see timing events as being potentially useful reusable concurrency 
>> component.
>> If you ever need something that looks like timing_events, then hopefully
>> it will save you from having to write your own. It may have utility in 
>> some areas such as discrete event simulation, for example, if you need 
>> something to coordinate multiple tasks and ensure that signalling events 
>> occur and run to completion before before signaling subsequent events.
> 
> This is IMO a different case, e.g. pulse events. Yes I have an
> implementation of pulse events. But I don't see why pulse events cannot be
> signaled from a scheduler task. The event source is unrelated to the way an
> event is handled. Basically Timing_Events saves you exactly one "scheduler"
> task, keeping in mind that the implementation of could deploy some hidden
> task (thread) anyway. It does not save you the worker task(s).
> 

Agreed, timing_events *is* basically a scheduler task. In my example, 
assuming Call_Police is not potentially blocking, and you try to rewrite
the example without having some type of a scheduler task, (whether it be
timing_events or your scheduler), then you may end up having to create 
some dedicated task to manage the timeout for the alarm. (Extra to the 
thread of control encapsulated by the hardware device) The scheduler 
model could be considered as being an improvement over this, but as 
system requirements can differ dramatically across different systems, YMMV.

Regards,
Brad



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25 15:56 ` John B. Matthews
@ 2009-09-26 14:23   ` John B. Matthews
  2009-09-28 10:28   ` Reto Buerki
  1 sibling, 0 replies; 31+ messages in thread
From: John B. Matthews @ 2009-09-26 14:23 UTC (permalink / raw)


In article <nospam-E7CE69.11564625092009@news.aioe.org>,
 "John B. Matthews" <nospam@nospam.invalid> wrote:

[...]
> <http://www.adaic.com/standards/95rat/RAThtml/rat95-p1-2.html#9>
[...]
>       procedure Wakeup(Event : in out Timing_Events.Timing_Event) is
>       begin
>          Alarm := True;
>          Signal;
>       end Wakeup;

Oops, procedure Wakeup shouldn't set Alarm; as the article explains, it 
should only be "true while tasks are being released."

      procedure Wakeup(Event : in out Timing_Events.Timing_Event) is
      begin
         Signal;
      end Wakeup;

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-24 17:47 ` Dmitry A. Kazakov
  2009-09-25  8:50   ` Brad Moore
@ 2009-09-28 10:18   ` Reto Buerki
  1 sibling, 0 replies; 31+ messages in thread
From: Reto Buerki @ 2009-09-28 10:18 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
>> Switching the compiler is a solution we consider as last resort.
> 
> Switching to a never version looks plausible to me.

Our current development environment is based on Debian/Stable. Switching
to GNAT 4.4 requires us to upgrade the environment to Debian
experimental or testing which could introduce some instabilities.
Furthermore, some work is required to do the actual upgrade.

> I was always wondering the rationale behind introducing
> Ada.Real_Time.Timing_Events. The delay statement does the very same thing:

The code I posted was just a small reproducer for the barrier
re-evaluation bug in FSF GNAT 4.3.2. As stated, the problem has nothing
to do with timing events, it also occurs when a "normal" Ada (scheduler)
task is delayed and calls the Wakeup() procedure. Obviously in this
simple example there's no need for timing events or an additional task.



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25 15:56 ` John B. Matthews
  2009-09-26 14:23   ` John B. Matthews
@ 2009-09-28 10:28   ` Reto Buerki
  2009-09-28 12:39     ` John B. Matthews
  1 sibling, 1 reply; 31+ messages in thread
From: Reto Buerki @ 2009-09-28 10:28 UTC (permalink / raw)


John B. Matthews wrote:
> I get the same result with FSF GNAT 4.3.4. I revised your code to follow 
> the "protected Event" example seen here:
> 
> <http://www.adaic.com/standards/95rat/RAThtml/rat95-p1-2.html#9>
> 
> It seems to work. The compiler warns, "potentially blocking operation in 
> protected operation" in Wakeup, although the Signal barrier is always 
> true. I'm not sure the extra entries _should_ be required, but I think 
> it might be more reliable in the face of multiple threads calling Wait. 
> I don't know a reason why it wouldn't work under 4.3.2.

Thanks for your effort in confirming the issue with GNAT 4.3.4 and for
the "protected Event" example.

We will see how we can integrate your idea into our project as a
workaround for the re-evaluation problem.



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-25 11:23       ` Jean-Pierre Rosen
@ 2009-09-28 10:41         ` Reto Buerki
  0 siblings, 0 replies; 31+ messages in thread
From: Reto Buerki @ 2009-09-28 10:41 UTC (permalink / raw)


Jean-Pierre Rosen wrote:
> Dmitry A. Kazakov a �crit :
>> Timing_Events does not have any advantages over delay or asynchronous
>> transfer of control. I guess it was provided for some low-level stuff like
>> interrupts from hardware timers. However there was already a support for
>> interrupts mapped into protected operations, so it really puzzles me why
>> Timing_Events were added.
>>
> The answer is easy: because users asked for it. Of course, it is
> useless, but some people don't feel easy with tasks, and want to use the
> kind of tools they are accustomed to.
> 
> So rather than painfully answering requests like "why doesn't Ada have
> that feature", it was simpler to say "what's the heck" and provide it.
> If you don't like it (I am also in that case), don't use it.

Could you elaborate the negative aspects of Ada.Real_Time.Timing_Events?

We found using timing events was straightforward and lightweight.



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 10:28   ` Reto Buerki
@ 2009-09-28 12:39     ` John B. Matthews
  2009-09-28 13:25       ` Reto Buerki
  0 siblings, 1 reply; 31+ messages in thread
From: John B. Matthews @ 2009-09-28 12:39 UTC (permalink / raw)


In article <h9q34o$odd$1@news.eternal-september.org>,
 Reto Buerki <reet@codelabs.ch> wrote:

> John B. Matthews wrote:
> > I get the same result with FSF GNAT 4.3.4. I revised your code to follow 
> > the "protected Event" example seen here:
> > 
> > <http://www.adaic.com/standards/95rat/RAThtml/rat95-p1-2.html#9>
> > 
> > It seems to work. The compiler warns, "potentially blocking operation in 
> > protected operation" in Wakeup, although the Signal barrier is always 
> > true. I'm not sure the extra entries _should_ be required, but I think 
> > it might be more reliable in the face of multiple threads calling Wait. 
> > I don't know a reason why it wouldn't work under 4.3.2.
> 
> Thanks for your effort in confirming the issue with GNAT 4.3.4 and for
> the "protected Event" example.

You're welcome.

> We will see how we can integrate your idea into our project as a
> workaround for the re-evaluation problem.

This alternative approach also works, without using requeue:

<http://www.adaic.com/standards/95rat/RAThtml/rat95-p2-9.html#2>

I am troubled by the "potentially blocking operation" warning. Two 
things make me think it may be irrelevant: 1) Signal does not actually 
block, except to dequeue waiters, and 2) Wakeup, which enters Signal, is 
itself a protected procedure:

<http://www.adaic.com/standards/05rm/html/RM-D-15.html>

I'd welcome critical thoughts.

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 12:39     ` John B. Matthews
@ 2009-09-28 13:25       ` Reto Buerki
  2009-09-28 14:05         ` Reto Buerki
  0 siblings, 1 reply; 31+ messages in thread
From: Reto Buerki @ 2009-09-28 13:25 UTC (permalink / raw)


John B. Matthews wrote:
> In article <h9q34o$odd$1@news.eternal-september.org>,
>  Reto Buerki <reet@codelabs.ch> wrote:
> 
>> John B. Matthews wrote:
>>> I get the same result with FSF GNAT 4.3.4. I revised your code to follow 
>>> the "protected Event" example seen here:
>>>
>>> <http://www.adaic.com/standards/95rat/RAThtml/rat95-p1-2.html#9>
>>>
>>> It seems to work. The compiler warns, "potentially blocking operation in 
>>> protected operation" in Wakeup, although the Signal barrier is always 
>>> true. I'm not sure the extra entries _should_ be required, but I think 
>>> it might be more reliable in the face of multiple threads calling Wait. 
>>> I don't know a reason why it wouldn't work under 4.3.2.
>> Thanks for your effort in confirming the issue with GNAT 4.3.4 and for
>> the "protected Event" example.
> 
> You're welcome.
> 
>> We will see how we can integrate your idea into our project as a
>> workaround for the re-evaluation problem.
> 
> This alternative approach also works, without using requeue:

Adapting your first example worked for us! We basically just moved the
Alarm_Fired assignment from Wakeup() into an extra Signal() entry:

procedure Wakeup (Event : in out Timing_Events.Timing_Event) is
begin
   Signal;
end Wakeup;

entry Signal when True is
begin
   Alarm_Fired := True;
end Signal;

This seems to cause a re-evaluation of the protected object barriers. It
does not work if Signal() is a protected procedure, it must be an entry.

> I am troubled by the "potentially blocking operation" warning. Two 
> things make me think it may be irrelevant: 1) Signal does not actually 
> block, except to dequeue waiters, and 2) Wakeup, which enters Signal, is 
> itself a protected procedure:
> 
> <http://www.adaic.com/standards/05rm/html/RM-D-15.html>
> 
> I'd welcome critical thoughts.

We are not getting such a warning with our code, but we are not using
"requeue" since our scenario is different.



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 13:25       ` Reto Buerki
@ 2009-09-28 14:05         ` Reto Buerki
  2009-09-28 18:38           ` Jeffrey R. Carter
  0 siblings, 1 reply; 31+ messages in thread
From: Reto Buerki @ 2009-09-28 14:05 UTC (permalink / raw)


Reto Buerki wrote:
> John B. Matthews wrote:
>> I am troubled by the "potentially blocking operation" warning. Two 
>> things make me think it may be irrelevant: 1) Signal does not actually 
>> block, except to dequeue waiters, and 2) Wakeup, which enters Signal, is 
>> itself a protected procedure:
>>
>> <http://www.adaic.com/standards/05rm/html/RM-D-15.html>
>>
>> I'd welcome critical thoughts.
> 
> We are not getting such a warning with our code, but we are not using
> "requeue" since our scenario is different.

Update: we just noticed that the warning actually *does* show up but we
missed it in the previous build.

I also think the warning is irrelevant. It seems that the compiler is
not smart enough to figure out that the Signal() entry is always open.



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 14:05         ` Reto Buerki
@ 2009-09-28 18:38           ` Jeffrey R. Carter
  2009-09-28 18:51             ` Dmitry A. Kazakov
                               ` (2 more replies)
  0 siblings, 3 replies; 31+ messages in thread
From: Jeffrey R. Carter @ 2009-09-28 18:38 UTC (permalink / raw)


Reto Buerki wrote:
> 
> Update: we just noticed that the warning actually *does* show up but we
> missed it in the previous build.
> 
> I also think the warning is irrelevant. It seems that the compiler is
> not smart enough to figure out that the Signal() entry is always open.

An entry call is always potentially blocking, regardless of its barrier; see ARM 
9.5.1. Technically, this code contains a bounded error. Since the potentially 
blocking operation was detected, your program should raise Program_Error; GNAT 
pretends that it hasn't detected that the operation is potentially blocking and 
lets you get away with only a warning. Other compilers (and even other versions 
of GNAT) may actually raise Program_Error.

-- 
Jeff Carter
"Strange women lying in ponds distributing swords
is no basis for a system of government."
Monty Python & the Holy Grail
66



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 18:38           ` Jeffrey R. Carter
@ 2009-09-28 18:51             ` Dmitry A. Kazakov
  2009-09-29  8:37               ` Reto Buerki
  2009-09-28 21:13             ` Robert A Duff
  2009-09-29  8:30             ` Reto Buerki
  2 siblings, 1 reply; 31+ messages in thread
From: Dmitry A. Kazakov @ 2009-09-28 18:51 UTC (permalink / raw)


On Mon, 28 Sep 2009 11:38:18 -0700, Jeffrey R. Carter wrote:

> An entry call is always potentially blocking, regardless of its barrier; see ARM 
> 9.5.1. Technically, this code contains a bounded error. Since the potentially 
> blocking operation was detected, your program should raise Program_Error; GNAT 
> pretends that it hasn't detected that the operation is potentially blocking and 
> lets you get away with only a warning. Other compilers (and even other versions 
> of GNAT) may actually raise Program_Error.

A small addition to above. If you wanted to call to an entry from inside a
protected procedure you have two options:

1. the callee is made a protected procedure (can be factored out);
2. the caller is made an entry, and the call replaced with requeue.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 18:38           ` Jeffrey R. Carter
  2009-09-28 18:51             ` Dmitry A. Kazakov
@ 2009-09-28 21:13             ` Robert A Duff
  2009-09-28 22:28               ` Jeffrey R. Carter
  2009-09-29  8:30             ` Reto Buerki
  2 siblings, 1 reply; 31+ messages in thread
From: Robert A Duff @ 2009-09-28 21:13 UTC (permalink / raw)


"Jeffrey R. Carter" <spam.jrcarter.not@spam.acm.org> writes:

> An entry call is always potentially blocking, regardless of its barrier;
> see ARM 9.5.1. Technically, this code contains a bounded error. Since
> the potentially blocking operation was detected, your program should
> raise Program_Error; GNAT pretends that it hasn't detected that the
> operation is potentially blocking and lets you get away with only a
> warning. Other compilers (and even other versions of GNAT) may actually
> raise Program_Error.

Pragma Detect_Blocking will cause GNAT to raise Program_Error.
If you want to write portable code, you should use this
pragma.

- Bob



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 21:13             ` Robert A Duff
@ 2009-09-28 22:28               ` Jeffrey R. Carter
  2009-10-10  5:41                 ` Randy Brukardt
  0 siblings, 1 reply; 31+ messages in thread
From: Jeffrey R. Carter @ 2009-09-28 22:28 UTC (permalink / raw)


Robert A Duff wrote:
> 
> Pragma Detect_Blocking will cause GNAT to raise Program_Error.
> If you want to write portable code, you should use this
> pragma.

I thought there would be a way to make GNAT be an Ada compiler, but a quick look 
at the secret documentation didn't find it.

-- 
Jeff Carter
"Strange women lying in ponds distributing swords
is no basis for a system of government."
Monty Python & the Holy Grail
66



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 18:38           ` Jeffrey R. Carter
  2009-09-28 18:51             ` Dmitry A. Kazakov
  2009-09-28 21:13             ` Robert A Duff
@ 2009-09-29  8:30             ` Reto Buerki
  2009-09-29 15:06               ` John B. Matthews
  2 siblings, 1 reply; 31+ messages in thread
From: Reto Buerki @ 2009-09-29  8:30 UTC (permalink / raw)


Jeffrey R. Carter wrote:
> Reto Buerki wrote:
>>
>> Update: we just noticed that the warning actually *does* show up but we
>> missed it in the previous build.
>>
>> I also think the warning is irrelevant. It seems that the compiler is
>> not smart enough to figure out that the Signal() entry is always open.
> 
> An entry call is always potentially blocking, regardless of its barrier;
> see ARM 9.5.1. Technically, this code contains a bounded error. Since
> the potentially blocking operation was detected, your program should
> raise Program_Error; GNAT pretends that it hasn't detected that the
> operation is potentially blocking and lets you get away with only a
> warning. Other compilers (and even other versions of GNAT) may actually
> raise Program_Error.

Thanks for the clarification and the pointer to the ARM. This basically
means that our workaround is not legal Ada code ...




^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 18:51             ` Dmitry A. Kazakov
@ 2009-09-29  8:37               ` Reto Buerki
  0 siblings, 0 replies; 31+ messages in thread
From: Reto Buerki @ 2009-09-29  8:37 UTC (permalink / raw)


Dmitry A. Kazakov wrote:
> On Mon, 28 Sep 2009 11:38:18 -0700, Jeffrey R. Carter wrote:
> 
>> An entry call is always potentially blocking, regardless of its barrier; see ARM 
>> 9.5.1. Technically, this code contains a bounded error. Since the potentially 
>> blocking operation was detected, your program should raise Program_Error; GNAT 
>> pretends that it hasn't detected that the operation is potentially blocking and 
>> lets you get away with only a warning. Other compilers (and even other versions 
>> of GNAT) may actually raise Program_Error.
> 
> A small addition to above. If you wanted to call to an entry from inside a
> protected procedure you have two options:
> 
> 1. the callee is made a protected procedure (can be factored out);

This does not work in our case because of the compiler bug: barriers are
only re-evaluated if the callee is an entry.

> 2. the caller is made an entry, and the call replaced with requeue.

We will look into this. Since access types to protected entries are not
allowed, we need to rewrite some alarm timer code first.



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-29  8:30             ` Reto Buerki
@ 2009-09-29 15:06               ` John B. Matthews
  2009-09-30 14:12                 ` Reto Buerki
  0 siblings, 1 reply; 31+ messages in thread
From: John B. Matthews @ 2009-09-29 15:06 UTC (permalink / raw)


In article <h9sgj7$1qr$1@news.eternal-september.org>,
 Reto Buerki <reet@codelabs.ch> wrote:

> Jeffrey R. Carter wrote:
> > Reto Buerki wrote:
> >>
> >> Update: we just noticed that the warning actually *does* show up but we
> >> missed it in the previous build.
> >>
> >> I also think the warning is irrelevant. It seems that the compiler is
> >> not smart enough to figure out that the Signal() entry is always open.
> > 
> > An entry call is always potentially blocking, regardless of its barrier;
> > see ARM 9.5.1. Technically, this code contains a bounded error. Since
> > the potentially blocking operation was detected, your program should
> > raise Program_Error; GNAT pretends that it hasn't detected that the
> > operation is potentially blocking and lets you get away with only a
> > warning. Other compilers (and even other versions of GNAT) may actually
> > raise Program_Error.
> 
> Thanks for the clarification and the pointer to the ARM. This basically
> means that our workaround is not legal Ada code ...

Well, it's a bounded error. Using Pragma Detect_Blocking, as suggested 
by Bob Duff, will tell you if the compiler's warning is actualized at 
run-time. As this is a work-around and your original code seems correct, 
you might arrange things so that the original can be restored easily 
upon upgrade or port.

Because this can be a maintenance headache, you might also look through 
some other examples of Timing_Events with a view towards your intended 
usage:

<http://www.adaic.com/standards/05rat/html/Rat-1-3-4.html>
<http://www.adaic.com/standards/05rat/html/Rat-5-6.html>

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-29 15:06               ` John B. Matthews
@ 2009-09-30 14:12                 ` Reto Buerki
  2009-09-30 15:59                   ` John B. Matthews
  0 siblings, 1 reply; 31+ messages in thread
From: Reto Buerki @ 2009-09-30 14:12 UTC (permalink / raw)


John B. Matthews wrote:
> In article <h9sgj7$1qr$1@news.eternal-september.org>,
>  Reto Buerki <reet@codelabs.ch> wrote:
> 
>> Jeffrey R. Carter wrote:
>>> An entry call is always potentially blocking, regardless of its barrier;
>>> see ARM 9.5.1. Technically, this code contains a bounded error. Since
>>> the potentially blocking operation was detected, your program should
>>> raise Program_Error; GNAT pretends that it hasn't detected that the
>>> operation is potentially blocking and lets you get away with only a
>>> warning. Other compilers (and even other versions of GNAT) may actually
>>> raise Program_Error.
>> Thanks for the clarification and the pointer to the ARM. This basically
>> means that our workaround is not legal Ada code ...
> 
> Well, it's a bounded error. Using Pragma Detect_Blocking, as suggested 
> by Bob Duff, will tell you if the compiler's warning is actualized at 
> run-time. As this is a work-around and your original code seems correct, 
> you might arrange things so that the original can be restored easily 
> upon upgrade or port.

The code runs correctly even though Program_Error is raised when
compiled with the Detect_Blocking pragma.

I think it's good enough as a workaround, we will upgrade to GNAT 4.4.x
as soon as possible.

Thanks for all your help!



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-30 14:12                 ` Reto Buerki
@ 2009-09-30 15:59                   ` John B. Matthews
  2009-10-01 16:12                     ` John B. Matthews
  0 siblings, 1 reply; 31+ messages in thread
From: John B. Matthews @ 2009-09-30 15:59 UTC (permalink / raw)


In article <h9vp0g$1kn$1@news.eternal-september.org>,
 Reto Buerki <reet@codelabs.ch> wrote:

> John B. Matthews wrote:
> > Using Pragma Detect_Blocking, as suggested by Bob Duff, will tell 
> > you if the compiler's warning is actualized at run-time. As this is 
> > a work-around and your original code seems correct, you might 
> > arrange things so that the original can be restored easily upon 
> > upgrade or port.
> 
> The code runs correctly even though Program_Error is raised when
> compiled with the Detect_Blocking pragma.
> 
> I think it's good enough as a workaround, we will upgrade to GNAT 
> 4.4.x as soon as possible.

Excellent, although upgrading has it's own perils. :-)

Another alternative, suggested by Dmitry A. Kazakov, is to replace entry 
Wait with procedure Wait, which obviates the need for Signal: 

with Ada.Text_IO;
with Alarm_Clock;

procedure Main is
   My_Alarm : Alarm_Clock.Alarm_Type;
begin
   Ada.Text_IO.Put_Line ("Setting alarm ...");
   My_Alarm.Set;

   Ada.Text_IO.Put_Line ("Waiting for alarm ...");
   My_Alarm.Wait;

   Ada.Text_IO.Put_Line ("ALARM!!");
end Main;

with Ada.Real_Time.Timing_Events;

package Alarm_Clock is

   protected type Alarm_Type is
      procedure Set;
      procedure Wait;
   end Alarm_Type;

end Alarm_Clock;

package body Alarm_Clock is

   use Ada.Real_Time;
   Timer : Timing_Events.Timing_Event;
   Fired : Boolean := False;

   protected body Alarm_Type is

      procedure Wakeup(Event : in out Timing_Events.Timing_Event) is
      begin
         Fired := True;
      end Wakeup;

      procedure Set is
      begin
         Timer.Set_Handler(In_Time => Seconds (2),
                           Handler => Wakeup'Access);
      end Set;

      procedure Wait is
      begin
         loop
            exit when Fired;
         end loop;
      end Wait;

   end Alarm_Type;

end Alarm_Clock;

> Thanks for all your help!

I enjoyed the opportunity to examine this interesting question.

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-30 15:59                   ` John B. Matthews
@ 2009-10-01 16:12                     ` John B. Matthews
  2009-10-01 17:17                       ` Anh Vo
  0 siblings, 1 reply; 31+ messages in thread
From: John B. Matthews @ 2009-10-01 16:12 UTC (permalink / raw)


In article <nospam-12AAE0.11590930092009@news.aioe.org>,
 "John B. Matthews" <nospam@nospam.invalid> wrote:

[...]
> Another alternative, suggested by Dmitry A. Kazakov, is to replace 
> entry Wait with procedure Wait, which obviates the need for Signal: 

Sorry, I carelessly posted code with a busy-wait. Please consider this 
alternative, which polls the timer's state:

with Ada.Text_IO;
with Alarm_Clock;

procedure Main is
   My_Alarm : Alarm_Clock.Alarm_Type;
begin
   Ada.Text_IO.Put_Line ("Setting alarm ...");
   My_Alarm.Set;

   Ada.Text_IO.Put_Line ("Waiting for alarm ...");
   My_Alarm.Wait;

   Ada.Text_IO.Put_Line ("ALARM!!");
end Main;

package Alarm_Clock is

   type Alarm_Type is tagged null record;
   procedure Set(Alarm : Alarm_Type);
   procedure Wait(Alarm : Alarm_Type);

end Alarm_Clock;

with Ada.Real_Time.Timing_Events;

package body Alarm_Clock is

   use Ada.Real_Time;
   Timer : Timing_Events.Timing_Event;
   Fired : Boolean := False;

   protected Clock is
      procedure Wakeup(Event : in out Timing_Events.Timing_Event);
   end Clock;

   protected body Clock is
      procedure Wakeup(Event : in out Timing_Events.Timing_Event) is
      begin
         Fired := True;
      end Wakeup;
   end Clock;

   procedure Set(Alarm : Alarm_Type) is
   begin
      Timer.Set_Handler(In_Time => Seconds(3),
                        Handler => Clock.Wakeup'Access);
   end Set;

   procedure Wait(Alarm : Alarm_Type) is
   begin
      loop
         delay 1.0;
         exit when Fired;
      end loop;
   end Wait;

end Alarm_Clock;


-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-10-01 16:12                     ` John B. Matthews
@ 2009-10-01 17:17                       ` Anh Vo
  2009-10-02  2:26                         ` John B. Matthews
  0 siblings, 1 reply; 31+ messages in thread
From: Anh Vo @ 2009-10-01 17:17 UTC (permalink / raw)


On Oct 1, 9:12 am, "John B. Matthews" <nos...@nospam.invalid> wrote:
> In article <nospam-12AAE0.11590930092...@news.aioe.org>,
>  "John B. Matthews" <nos...@nospam.invalid> wrote:
>
> [...]
>
> > Another alternative, suggested by Dmitry A. Kazakov, is to replace
> > entry Wait with procedure Wait, which obviates the need for Signal:
>
> Sorry, I carelessly posted code with a busy-wait. Please consider this
> alternative, which polls the timer's state:
>
> with Ada.Text_IO;
> with Alarm_Clock;
>
> procedure Main is
>    My_Alarm : Alarm_Clock.Alarm_Type;
> begin
>    Ada.Text_IO.Put_Line ("Setting alarm ...");
>    My_Alarm.Set;
>
>    Ada.Text_IO.Put_Line ("Waiting for alarm ...");
>    My_Alarm.Wait;
>
>    Ada.Text_IO.Put_Line ("ALARM!!");
> end Main;
>
> package Alarm_Clock is
>
>    type Alarm_Type is tagged null record;
>    procedure Set(Alarm : Alarm_Type);
>    procedure Wait(Alarm : Alarm_Type);
>
> end Alarm_Clock;
>
> with Ada.Real_Time.Timing_Events;
>
> package body Alarm_Clock is
>
>    use Ada.Real_Time;
>    Timer : Timing_Events.Timing_Event;
>    Fired : Boolean := False;
>
>    protected Clock is
>       procedure Wakeup(Event : in out Timing_Events.Timing_Event);
>    end Clock;
>
>    protected body Clock is
>       procedure Wakeup(Event : in out Timing_Events.Timing_Event) is
>       begin
>          Fired := True;
>       end Wakeup;
>    end Clock;
>
>    procedure Set(Alarm : Alarm_Type) is
>    begin
>       Timer.Set_Handler(In_Time => Seconds(3),
>                         Handler => Clock.Wakeup'Access);
>    end Set;
>
>    procedure Wait(Alarm : Alarm_Type) is
>    begin
>       loop
>          delay 1.0;
>          exit when Fired;
>       end loop;
>    end Wait;
>
> end Alarm_Clock;

I am curious why Alarm_Type is even needed in this case. In addition,
Alarm_Clock works the first time. However, it won't work right on the
second time and on because Fired was not reset after the Alarm goes
off.

Anh Vo



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-10-01 17:17                       ` Anh Vo
@ 2009-10-02  2:26                         ` John B. Matthews
  0 siblings, 0 replies; 31+ messages in thread
From: John B. Matthews @ 2009-10-02  2:26 UTC (permalink / raw)


In article 
<3c32a0db-9878-4057-b3b8-44d03f02571d@z3g2000prd.googlegroups.com>,
 Anh Vo <anhvofrcaus@gmail.com> wrote:

> On Oct 1, 9:12 am, "John B. Matthews" <nos...@nospam.invalid> wrote:
> > In article <nospam-12AAE0.11590930092...@news.aioe.org>,
> >  "John B. Matthews" <nos...@nospam.invalid> wrote:
> > [...]
> > > Another alternative, suggested by Dmitry A. Kazakov, is to 
> > > replace entry Wait with procedure Wait, which obviates the need 
> > > for Signal:
> >
> > Sorry, I carelessly posted code with a busy-wait. Please consider 
> > this alternative, which polls the timer's state:
[...]
> >    type Alarm_Type is tagged null record;
[...]
> I am curious why Alarm_Type is even needed in this case.

Good question. It's not. I was tinkering with several implementation 
that matched a variant of the OP's main. As this is a work-around, I 
wanted to preserve the calling style, which used the prefixed notation. 
That style was available to protected types in Ada 95 and was extended 
to tagged types in Ada 05. I didn't realize how much I liked the 
notation until I stared using Ada.Containers.

> In addition, Alarm_Clock works the first time. However, it won't work 
> right on the second time and on because Fired was not reset after the 
> Alarm goes off.

Good catch; thank you. Set should clear Fired.

Another work-around implementation is shown below. Entering Signal from 
the protected procedure Wakeup is a bounded error (LRM 9.5.1(11)), and 
the compiler (FSF GNAT 4.3.4) issues a corresponding compile time 
warning. Interestingly, using pragma Detect_Blocking does not raise 
Program_Error. I'm curious to know whether that's just a reasonable 
limitation in how the pragma is implemented, or is the entry call 
reasonable in this context.

with Ada.Real_Time.Timing_Events;

package Alarm_Clock is

   use Ada.Real_Time;

   protected type Alarm_Type is
      procedure Set;
      entry Wait;
      entry Signal;
   end Alarm_Type;

end Alarm_Clock;

Pragma Detect_Blocking;
package body Alarm_Clock is

   Timer : Timing_Events.Timing_Event;

   protected body Alarm_Type is

      procedure Wakeup(Event : in out Timing_Events.Timing_Event) is
      begin
         Signal;
      end Wakeup;

      procedure Set is
      begin
         Timer.Set_Handler(In_Time => Seconds (1),
                           Handler => Wakeup'Access);
      end Set;

      entry Wait when Signal'Count > 0 is
      begin
         null;
      end Wait;

      entry Signal when Wait'Count = 0 is
      begin
         null;
      end Signal;

   end Alarm_Type;

end Alarm_Clock;

-- 
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: Barrier re-evaluation issue with GNAT 4.3.2
  2009-09-28 22:28               ` Jeffrey R. Carter
@ 2009-10-10  5:41                 ` Randy Brukardt
  0 siblings, 0 replies; 31+ messages in thread
From: Randy Brukardt @ 2009-10-10  5:41 UTC (permalink / raw)


"Jeffrey R. Carter" <spam.jrcarter.not@spam.acm.org> wrote in message 
news:h9rco8$u58$1@news.tornevall.net...
> Robert A Duff wrote:
>>
>> Pragma Detect_Blocking will cause GNAT to raise Program_Error.
>> If you want to write portable code, you should use this
>> pragma.
>
> I thought there would be a way to make GNAT be an Ada compiler, but a 
> quick look at the secret documentation didn't find it.

GNAT does some weird things, but this isn't one of them. Pragma 
Detect_Blocking is standard Ada 2005 (added for the Ravenscar profile). It 
should be the default, but it isn't because various real-time people who 
ought to know better don't want to pay the miniscule cost of the check. [I 
think the check should be the default with the possibility of check 
suppression -- which hardly ever would be used. But some people think 
possible deadlocks are a better outcome. Bah!] Because of that, almost all 
Ada compilers will behave as GNAT does in this case. If you want portable 
Ada code (at runtime), you need to include the pragma -- for *all* 
compilers, not just GNAT. (If you are doing pure Ada 95, you are out of 
luck, unfortunately.)

                                              Randy.





^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2009-10-10  5:41 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-24 17:02 Barrier re-evaluation issue with GNAT 4.3.2 Reto Buerki
2009-09-24 17:47 ` Dmitry A. Kazakov
2009-09-25  8:50   ` Brad Moore
2009-09-25  9:17     ` Dmitry A. Kazakov
2009-09-25  9:57       ` Ludovic Brenta
2009-09-25 10:31         ` Dmitry A. Kazakov
2009-09-25 11:23       ` Jean-Pierre Rosen
2009-09-28 10:41         ` Reto Buerki
2009-09-25 17:06       ` Brad Moore
2009-09-25 18:42         ` Dmitry A. Kazakov
2009-09-25 19:39           ` Brad Moore
2009-09-28 10:18   ` Reto Buerki
2009-09-25 15:56 ` John B. Matthews
2009-09-26 14:23   ` John B. Matthews
2009-09-28 10:28   ` Reto Buerki
2009-09-28 12:39     ` John B. Matthews
2009-09-28 13:25       ` Reto Buerki
2009-09-28 14:05         ` Reto Buerki
2009-09-28 18:38           ` Jeffrey R. Carter
2009-09-28 18:51             ` Dmitry A. Kazakov
2009-09-29  8:37               ` Reto Buerki
2009-09-28 21:13             ` Robert A Duff
2009-09-28 22:28               ` Jeffrey R. Carter
2009-10-10  5:41                 ` Randy Brukardt
2009-09-29  8:30             ` Reto Buerki
2009-09-29 15:06               ` John B. Matthews
2009-09-30 14:12                 ` Reto Buerki
2009-09-30 15:59                   ` John B. Matthews
2009-10-01 16:12                     ` John B. Matthews
2009-10-01 17:17                       ` Anh Vo
2009-10-02  2:26                         ` John B. Matthews

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox