Prev: Newbie question: How to use gnat make
Next: Performance of access type : a tiny mistake in the WikiBook ?
From: Reto Buerki on 24 Sep 2009 13:02 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
From: Dmitry A. Kazakov on 24 Sep 2009 13:47 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
From: Brad Moore on 25 Sep 2009 04:50 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;
From: Dmitry A. Kazakov on 25 Sep 2009 05:17 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
From: Ludovic Brenta on 25 Sep 2009 05:57 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.
|
Next
|
Last
Pages: 1 2 3 4 5 6 7 Prev: Newbie question: How to use gnat make Next: Performance of access type : a tiny mistake in the WikiBook ? |