* 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