Prev: Newbie question: How to use gnat make
Next: Performance of access type : a tiny mistake in the WikiBook ?
From: Reto Buerki on 30 Sep 2009 10:12 John B. Matthews wrote: > In article <h9sgj7$1qr$1(a)news.eternal-september.org>, > Reto Buerki <reet(a)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!
From: John B. Matthews on 30 Sep 2009 11:59 In article <h9vp0g$1kn$1(a)news.eternal-september.org>, Reto Buerki <reet(a)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>
From: John B. Matthews on 1 Oct 2009 12:12 In article <nospam-12AAE0.11590930092009(a)news.aioe.org>, "John B. Matthews" <nospam(a)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>
From: Anh Vo on 1 Oct 2009 13:17 On Oct 1, 9:12 am, "John B. Matthews" <nos...(a)nospam.invalid> wrote: > In article <nospam-12AAE0.11590930092...(a)news.aioe.org>, > "John B. Matthews" <nos...(a)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
From: John B. Matthews on 1 Oct 2009 22:26
In article <3c32a0db-9878-4057-b3b8-44d03f02571d(a)z3g2000prd.googlegroups.com>, Anh Vo <anhvofrcaus(a)gmail.com> wrote: > On Oct 1, 9:12 am, "John B. Matthews" <nos...(a)nospam.invalid> wrote: > > In article <nospam-12AAE0.11590930092...(a)news.aioe.org>, > > "John B. Matthews" <nos...(a)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> |