comp.lang.ada
 help / color / mirror / Atom feed
* Designing Timers using Ada.Real_Time.Timing_Events package
@ 2006-03-25 20:03 Anh Vo
  2006-03-25 20:58 ` Dmitry A. Kazakov
  2006-03-26  7:59 ` Martin Krischik
  0 siblings, 2 replies; 17+ messages in thread
From: Anh Vo @ 2006-03-25 20:03 UTC (permalink / raw)


All,

I attempted to design a basic timer package using the capabilities
provided by low level package Timing_Events as shown.

with Ada.Real_Time.Timing_Events;
package Basic_Timers is

   use Ada;

   Basic_Timer_Error : exception;

   type Timer_Type is abstract tagged limited private;
   type Timer_Type_Class is access all Timer_Type'Class;

   procedure Update (Observer : access Timer_Type) is abstract;

   procedure Set (This : access Timer_Type'Class;
                         Period : in Real_Time.Time_Span);
   procedure Start (This : access Timer_Type'Class);
   procedure Stop (This : access Timer_Type'Class);
   procedure Cancel (This : access Timer_Type'Class) renames Stop;

private

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

   type Timer_Type is abstract tagged limited
      record
         Period : Real_Time.Time_Span;
         Started : Boolean := False;
         Event : Real_Time.Timing_Events.Timing_Event;
         The_Handler : Events;
      end record;

   The_Timer : Timer_Type_Class := null;

end Basic_Timers;

package body Basic_Timers is

   protected body Events is
      procedure Handler (Event: in out
Real_Time.Timing_Events.Timing_Event) is
      begin
         The_Timer.Started := False;
         Update (The_Timer);
      end Handler;
   end Events;

   procedure Set (This : access Timer_Type'Class;
                        Period : in Real_Time.Time_Span) is
   begin
      This.Period := Period;
      The_Timer := Timer_Type_Class (This);
   end Set;

   procedure Start (This : access Timer_Type'Class) is
   begin
       if not This.Started then
          This.Started := True;
          Real_Time.Timing_Events.Set_Handler (
                      This.Event, This.Period,
This.The_Handler.Handler'access);
       else
          raise Basic_Timer_Error with "Wrong usage, basic timer
already started";
       end if;
   end Start;

   procedure Stop (This : access Timer_Type'Class) is
      Success : Boolean := False;
      use type Ada.Real_Time.Timing_Events.Timing_Event_Handler;
   begin
      if Real_Time.Timing_Events.Current_Handler (This.Event) /= null
then
         Real_Time.Timing_Events.Cancel_Handler (This.Event, Success);
         if Success then
            This.Started := False;
         else
            raise Basic_Timer_Error with "fail to cancel the basic
timer";
         end if;
      end if;
   end Stop;

end Basic_Timers;

It works fine as shown in the test codes

with Basic_Timers;
package Timers_Test1 is

   type State_Transition_Timer_Type is new
                                   Basic_Timers.Timer_Type with null
record;
   procedure Update (Observer : access State_Transition_Timer_Type);

   procedure Start;
   procedure Shutdown;

end Timers_Test1;

with Ada.Real_Time;
with Ada.Text_Io;
package body Timers_Test1 is

   use Ada;
   use Text_Io;

   State_Transition_Time : constant Real_Time.Time_Span :=
                                                 Real_Time.Milliseconds
(3000);
   State_Transition_Timer : aliased State_Transition_Timer_Type;

   procedure Update (Observer : access State_Transition_Timer_Type) is
   begin
      Put_Line ("The state Timer just expires. Do some thing here");
   end Update;

   procedure Start is
   begin
      Basic_Timers.Set (State_Transition_Timer'access,
State_Transition_Time);
      for Index in 1 .. 5 loop
         Basic_Timers.Start (State_Transition_Timer'access);
         delay 4.0;
      end loop;
   end Start;

   procedure Shutdown is
   begin
      Basic_Timers.Cancel (State_Transition_Timer'access);
   end Shutdown;

end Timers_Test1;

Howver, it ran into deadlock when the Update attempts to Start the
timer again as part of periodic timer as shown below.

with Basic_Timers;
package Timers_Test2 is

   type Periodic_Timer_Type is new
                                   Basic_Timers.Timer_Type with null
record;
   procedure Update (Observer : access Periodic_Timer_Type);

   procedure Start;
   procedure Shutdown;

end Timers_Test2;

with Ada.Real_Time;
with Ada.Text_Io;
package body Timers_Test2 is

   use Ada;
   use Text_Io;

   Periodic_Time : constant Real_Time.Time_Span :=
                                                 Real_Time.Milliseconds
(3000);
   Periodic_Timer : aliased Periodic_Timer_Type;

   procedure Update (Observer : access Periodic_Timer_Type) is
   begin
       Put_Line ("The state Timer just expires. Do some thing here");
       Basic_Timer.Start (Periodic_Timer);  --!!! causing deadlock
   end Update;

   procedure Start is
   begin
       Basic_Timers.Set (Periodic_Timer'access, Periodic_Time);
       Basic_Timers.Start (Periodic_Timer'access);
   end Start;

   procedure Shutdown is
   begin
       Basic_Timers.Cancel (Periodic_Timer'access);
   end Shutdown;

end Timers_Test2;

Just like semaphore if it is not used correctly, deadlock can occur as
in this case. Instead of limiting its usage, my desire to come with a
safer timer. This time I use a task to uncouple the protected handler
and the call back. I put it in a package called Sate_Timers. Its spec.
is the same as Basic_Timers spec. Thus, only its body is shown here to
cut down the lenghth of this message.

with System;
package body Safe_Timers is

   task Event_Handoff is
      pragma Priority (System.Priority'last - 2); -- Make sure it is
done
      entry Handoff;                                     -- without
interruption
   end Event_Handoff;

   task body Event_Handoff is
   begin
      Longlive :
      loop
         select
            accept Handoff;
            The_Timer.Started := False;
            Update (The_Timer);  -- dispatching to the observer
(callback)
         or
            terminate;  -- later alligator
         end select;
      end loop Longlive;
   end Event_Handoff;

   protected body Events is
      procedure Handler (Event: in out
Real_Time.Timing_Events.Timing_Event) is
      begin
         pragma Warnings (Off);
         Event_Handoff.Handoff;
      end Handler;
   end Events;

   procedure Set (This : access Timer_Type'Class;
                         Period : in Real_Time.Time_Span) is
   begin
      This.Period := Period;
      The_Timer := Timer_Type_Class (This);
   end Set;

   procedure Start (This : access Timer_Type'Class) is
   begin
      if not This.Started then
         This.Started := True;
         Real_Time.Timing_Events.Set_Handler (
                     This.Event, This.Period,
This.The_Handler.Handler'access);
      else
         raise Safe_Timer_Error with "Wrong usage - timer already
started";
      end if;
   end Start;

   procedure Stop (This : access Timer_Type'Class) is
      Success : Boolean := False;
      use type Ada.Real_Time.Timing_Events.Timing_Event_Handler;
   begin
      if Real_Time.Timing_Events.Current_Handler (This.Event) /= null
then
         Real_Time.Timing_Events.Cancel_Handler (This.Event, Success);
         if Success then
            This.Started := False;
         else
            raise Safe_Timer_Error with "fail to cancel the timer";
         end if;
      end if;
   end Stop;

end Safe_Timers;

Now Timers_Test2 does not cause deadlock any more.

I would like to know if I used Timing_Events package correctly in term
of its purpose. Secondly, is there any thing that these timers packages
can be improved. Thank you in advance for your thoughts.

AV
PS : these codes compiled and run on gnatgcc-4.2.0




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-25 20:03 Designing Timers using Ada.Real_Time.Timing_Events package Anh Vo
@ 2006-03-25 20:58 ` Dmitry A. Kazakov
  2006-03-26  5:39   ` Anh Vo
  2006-03-26  7:59 ` Martin Krischik
  1 sibling, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-25 20:58 UTC (permalink / raw)


On 25 Mar 2006 12:03:30 -0800, Anh Vo wrote:

[...]
> I would like to know if I used Timing_Events package correctly in term
> of its purpose. Secondly, is there any thing that these timers packages
> can be improved. Thank you in advance for your thoughts.

You can also use protected objects functionality rather than turn to
callbacks (which are always difficult to get right in presence on multiple
tasks.) A protected object may act as an waitable event triggered by the
timer via a call to its protected procedure and reset in its entry point
"Wait." This would be deadlock-free because anything the waiting task
should do upon the event would happen outside the protected action.

In a separate package you could wrap the task and the protected object in a
abstract limited tagged type with the primitive operation "On_Event" to
override (if you definitely want callbacks.)

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



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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-25 20:58 ` Dmitry A. Kazakov
@ 2006-03-26  5:39   ` Anh Vo
  2006-03-26 12:58     ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Anh Vo @ 2006-03-26  5:39 UTC (permalink / raw)


> You can also use protected objects functionality rather than turn to
> callbacks (which are always difficult to get right in presence on multiple
> tasks.) A protected object may act as an waitable event triggered by the
> timer via a call to its protected procedure and reset in its entry point
> "Wait." This would be deadlock-free because anything the waiting task
> should do upon the event would happen outside the protected action.

I did not know that it is possible to use protected objects
functionally while each timer used for different purpose. Could you
elaborate further? Or even better could you show your point with codes?

> In a separate package you could wrap the task and the protected object in a
> abstract limited tagged type with the primitive operation "On_Event" to
> override (if you definitely want callbacks.)

I am not sure what advantage gained for doing this way? Again, if you
show me some codes which could make me understatnd better. Thanks for
your suggestion.

AV




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-25 20:03 Designing Timers using Ada.Real_Time.Timing_Events package Anh Vo
  2006-03-25 20:58 ` Dmitry A. Kazakov
@ 2006-03-26  7:59 ` Martin Krischik
  2006-03-26 15:50   ` Anh Vo
  1 sibling, 1 reply; 17+ messages in thread
From: Martin Krischik @ 2006-03-26  7:59 UTC (permalink / raw)


Anh Vo wrote:

> PS : these codes compiled and run on gnatgcc-4.2.0

If this is not a typing mistake (i.E. you mend gnat-4.0.2) I suggest you use
4.1.0. GNAT compiled from /trunc tend to be instable.

Martin
-- 
mailto://krischik@users.sourceforge.net
Ada programming at: http://ada.krischik.com



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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-26  5:39   ` Anh Vo
@ 2006-03-26 12:58     ` Dmitry A. Kazakov
  2006-03-26 16:18       ` Anh Vo
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-26 12:58 UTC (permalink / raw)


On 25 Mar 2006 21:39:27 -0800, Anh Vo wrote:

>> You can also use protected objects functionality rather than turn to
>> callbacks (which are always difficult to get right in presence on multiple
>> tasks.) A protected object may act as an waitable event triggered by the
>> timer via a call to its protected procedure and reset in its entry point
>> "Wait." This would be deadlock-free because anything the waiting task
>> should do upon the event would happen outside the protected action.
> 
> I did not know that it is possible to use protected objects
> functionally while each timer used for different purpose. Could you
> elaborate further?

Why not? Each protected object would be a simple event. The handler set for
Ada.Real_Time.Timing_Events triggers an event(s). The functionality, i.e.
what has to be done upon the event, is outside. It happens in the task
waiting for the event. 

(I don't have GNAT GPL installed)

>> In a separate package you could wrap the task and the protected object in a
>> abstract limited tagged type with the primitive operation "On_Event" to
>> override (if you definitely want callbacks.)
> 
> I am not sure what advantage gained for doing this way?

Decoupling. The model one task - one callback is too specialized and
exposed to misuse. You might wish to have more than one task, you might
want handling the timer events on different contexts, routing and
re-routing them between tasks.

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



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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-26  7:59 ` Martin Krischik
@ 2006-03-26 15:50   ` Anh Vo
  0 siblings, 0 replies; 17+ messages in thread
From: Anh Vo @ 2006-03-26 15:50 UTC (permalink / raw)



Martin Krischik wrote:
> Anh Vo wrote:
>
> > PS : these codes compiled and run on gnatgcc-4.2.0
>
> If this is not a typing mistake (i.E. you mend gnat-4.0.2) I suggest you use
> 4.1.0. GNAT compiled from /trunc tend to be instable.

What I meant was GNAT compiler under gcc-4.2.0. It is currently at
statge 3 snapshot. 

AV




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-26 12:58     ` Dmitry A. Kazakov
@ 2006-03-26 16:18       ` Anh Vo
  2006-03-26 18:22         ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Anh Vo @ 2006-03-26 16:18 UTC (permalink / raw)


>> I did not know that it is possible to use protected objects
>> functionally while each timer used for different purpose. Could you
>> elaborate further?

> Why not? Each protected object would be a simple event. The handler set for
> Ada.Real_Time.Timing_Events triggers an event(s). The functionality, i.e.
> what has to be done upon the event, is outside. It happens in the task
> waiting for the event.

it works only if there is a specific purpose associated with an event.
In other word, an event handler must be set for a specific action. The
timers work almost like a generic in that the event is set once. The
action is supplied at the time of instantiation.

 > (I don't have GNAT GPL installed)

GNAT GPL has not implemented Timing_Events yet. GNAT under gcc-4.2.0 is
needed.

> Decoupling. The model one task - one callback is too specialized and
> exposed to misuse. You might wish to have more than one task, you might
> want handling the timer events on different contexts, routing and
> re-routing them between tasks.

For each timer defined through derivation, it is run under a separate
task. In case of Safe_Timers there are two tasks, additional task
needed for decoupling, running. Therefore, they are completely
separated between callbacks.

AV




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-26 16:18       ` Anh Vo
@ 2006-03-26 18:22         ` Dmitry A. Kazakov
  2006-03-26 19:43           ` Anh Vo
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-26 18:22 UTC (permalink / raw)


On 26 Mar 2006 08:18:56 -0800, Anh Vo wrote:

>>> I did not know that it is possible to use protected objects
>>> functionally while each timer used for different purpose. Could you
>>> elaborate further?
> 
>> Why not? Each protected object would be a simple event. The handler set for
>> Ada.Real_Time.Timing_Events triggers an event(s). The functionality, i.e.
>> what has to be done upon the event, is outside. It happens in the task
>> waiting for the event.
> 
> it works only if there is a specific purpose associated with an event.
> In other word, an event handler must be set for a specific action. The
> timers work almost like a generic in that the event is set once. The
> action is supplied at the time of instantiation.

Where is any problem? Event is decoupled from any purpose its signalling
might have. You do:

Timer_Canceled : exception;

protected type Periodic_Timer is
   entry Wait_For;
      -- May raise Timer_Canceled
   procedure Set (Period : Time_Span);
      -- Sets. reset timer
   procedure Cancel;
      -- Stops timer. Any task in Wait_For queue gets Timer_Canceled raised
   entry Simulate;
      -- Simulates a timer event
private
   procedure Signal (...);
      -- To be set as a handler for Ada.Real_Time.Timing_Events
   [...]
      -- Some internal entry to requeue Wait_For, if Signal cannot
      -- be an entry, but must be a protected procedure, instead.
   Inactive : Boolean := True;
end Periodic_Timer;

No tasks needed. Any number of tasks may wait for timer events. What they
do upon an event is up to them, as well as to take care if they catch all
events. So there is no deadlock if one of them hangs somewhere.

(I don't know the details of Ada.Real_Time.Timing_Events, but it should be
possible to do something like above.)

>> Decoupling. The model one task - one callback is too specialized and
>> exposed to misuse. You might wish to have more than one task, you might
>> want handling the timer events on different contexts, routing and
>> re-routing them between tasks.
> 
> For each timer defined through derivation, it is run under a separate
> task. In case of Safe_Timers there are two tasks, additional task
> needed for decoupling, running. Therefore, they are completely
> separated between callbacks.

So, when they, for example, must be the same task you will have a problem.
This design is too fragile.

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



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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-26 18:22         ` Dmitry A. Kazakov
@ 2006-03-26 19:43           ` Anh Vo
       [not found]             ` <3itd22hcekts5lsojdqjnn966bbvc8fckh@4ax.com>
  2006-03-27  7:49             ` Dmitry A. Kazakov
  0 siblings, 2 replies; 17+ messages in thread
From: Anh Vo @ 2006-03-26 19:43 UTC (permalink / raw)


>> it works only if there is a specific purpose associated with an event.
>> In other word, an event handler must be set for a specific action. The
>> timers work almost like a generic in that the event is set once. The
>> action is supplied at the time of instantiation.

> Where is any problem? Event is decoupled from any purpose its signalling
> might have. You do:

> Timer_Canceled : exception;

> protected type Periodic_Timer is
>   entry Wait_For;
>      -- May raise Timer_Canceled
>   procedure Set (Period : Time_Span);
>      -- Sets. reset timer
>   procedure Cancel;
>      -- Stops timer. Any task in Wait_For queue gets Timer_Canceled raised
>   entry Simulate;
>      -- Simulates a timer event
> private
>   procedure Signal (...);
>      -- To be set as a handler for Ada.Real_Time.Timing_Events
>   [...]
>      -- Some internal entry to requeue Wait_For, if Signal cannot
>      -- be an entry, but must be a protected procedure, instead.
>   Inactive : Boolean := True;
> end Periodic_Timer;
>
> No tasks needed. Any number of tasks may wait for timer events. What they
> do upon an event is up to them, as well as to take care if they catch all
> events. So there is no deadlock if one of them hangs somewhere.

I need to digest your design more details at implementation level to if
it works a intended. I recall that during testing if a deadlock occurs
in one event, the main program hung. That means the other callback did
not run due to the main program hung or the deadlock happening from the
earlier callback. I will post the resullts after implementing and
testing your design.

Regarding deadlock in general, if a deadlock occurs in one task, should
other tasks continue to operate and the main program should not hang?

>> For each timer defined through derivation, it is run under a separate
>> task. In case of Safe_Timers there are two tasks, additional task
>> needed for decoupling, running. Therefore, they are completely
>> separated between callbacks.

> So, when they, for example, must be the same task you will have a problem.
> This design is too fragile.

If deadlock occurs in one callbacks causing problems in others as
mentioned abouve, it is a fragile design indeed.

AV




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
       [not found]             ` <3itd22hcekts5lsojdqjnn966bbvc8fckh@4ax.com>
@ 2006-03-26 23:53               ` Anh Vo
       [not found]                 ` <0mae22lshe5nee8pt8h7seussloebv07g3@4ax.com>
  0 siblings, 1 reply; 17+ messages in thread
From: Anh Vo @ 2006-03-26 23:53 UTC (permalink / raw)


>> Regarding deadlock in general, if a deadlock occurs in one task, should
>> other tasks continue to operate and the main program should not hang?
>
>      As I understand the terms, pretty much by definition, a deadlock
> must involve more than one task... And the main program, also by
> definition, could be that task. While there may be other cases, the
> simple definition for a deadlock is for two or more concurrent threads
> of control to be blocked on mutual resources:
>
>        get_A                                   get_B
>        get_B (block)                   get_A (block)   (deadlock)
>        release_B                               release_A
>        release_A                               release_B
>
>        A more real-world situation could have many levels of calls before
> encountering blocking possibilities.

Does it mean that as long as the main task is not involved in the
deadlock, the main program should operate, not hung?

AV




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
       [not found]                 ` <0mae22lshe5nee8pt8h7seussloebv07g3@4ax.com>
@ 2006-03-27  5:01                   ` Anh Vo
       [not found]                     ` <5vse22h4mc1och27s0nkbv986csi2rorki@4ax.com>
  0 siblings, 1 reply; 17+ messages in thread
From: Anh Vo @ 2006-03-27  5:01 UTC (permalink / raw)



Dennis Lee Bieber wrote:
> On 26 Mar 2006 15:53:38 -0800, "Anh Vo" <anhvofrcaus@gmail.com>
> declaimed the following in comp.lang.ada:
>
> >
> > Does it mean that as long as the main task is not involved in the
> > deadlock, the main program should operate, not hung?
> >
> 	I was speaking generally, not specific to any particular code.
>
> 	Unfortunately, the code in your original post isn't useful to me; I
> only have GNAT/GPS GPL [at least I've finally moved up to that; last
> week I was still using GNAT 3.15p] -- I get:
>
> timers_test1.ads:1:06: "Ada.Real_Time.Timing_Events" is not a predefined
> library unit
>
> 	Which, as you comment somewhere in the chain, is not (yet) in the
> GNAT release.

In my original post I did mention in the PS that gcc-4.2.0 was needed
to compile these codes. GNAT-GPL and gcc-4.1.0 do not implement
Timing_Events yet.

> 	However, I don't find a "main program" in your original post; just a
> lot of packages, so I can't even review it visually to figure out what
> may be happening.

I will post entire codes including the main subprogram after you
building and installing gcc-4.2.0.

> > with Ada.Real_Time;
> > with Ada.Text_Io;
> > package body Timers_Test2 is
> >
> >    use Ada;
> >    use Text_Io;
> >
> >    Periodic_Time  : constant Real_Time.Time_Span         := Real_Time.Milliseconds
> >      (3000);
> >    Periodic_Timer :          aliased Periodic_Timer_Type;
> >
> >    procedure Update (
> >          Observer : access Periodic_Timer_Type) is
> >    begin
> >       Put_Line ("The state Timer just expires. Do some thing here");
> >       Basic_Timer.Start (Periodic_Timer);  --!!! causing deadlock
>
> 	Is that a typo? The package is Basic_TimerS

Yes, it is clearly a typo. However, it should be OK because Ada is a
case insensitive language.

> 	And what use is "Observer" (I suspect you should be calling
> 		basic_timers.start(Observer);

Both Observer and Periodic_Timer are the same.

> >    end Update;
> >
> >    procedure Start is
> >    begin
> >       Basic_Timers.Set (Periodic_Timer'access, Periodic_Time);
> >       Basic_Timers.Start (Periodic_Timer'access);
> >    end Start;
> >
> >    procedure Shutdown is
> >    begin
> >       Basic_Timers.Cancel (Periodic_Timer'access);
> >    end Shutdown;
> >
> > end Timers_Test2;
>
>
> > package body Basic_Timers is
> >
> >    protected body Events is
> >       procedure Handler (
> >             Event : in out Real_Time.Timing_Events.Timing_Event) is
> >       begin
> >          The_Timer.Started := False;
> >          Update (The_Timer);
> >       end Handler;
> >    end Events;
>
> 	I don't like the fact that you are using a "global" "the_timer"
> rather than somehow passing it in -- perhaps as an extension to
> timing_event...

As mentioned before I would like to design a generic timer used for
different purposes.

> 	Half the code seems to assume that there could be multiple timers
> that may need to be handled -- and then we get a this, which only knows
> about one instance...

This is the intention. Otherwise, there is no need for this package
since the Timing_Events can used directly.

> 	Maybe reverse your type definition; rather than embedding a
> timing_event inside your timer_type, extend timing_event with the other
> parameters... Then you'd have
>
> 	event.started := false;
> 	update(event);

This is needed so the timer can be started for the next cycle.

> 	This is all hypothesis, since I can not compile even the little you
> supplied (and don't have a main program). (Well, compile with complaints
> about ada.real_time-timing_events)

No, it is for real since I compiled and run it. Otherwise, I would not
dare to post the question in the first place. As mentioned earlier, you
need gcc-4.2.0. Any thing else will not do it. By the way, I suggest
reading a soon approved Ada 2005 Reference Manual and Ada 2005
Rationale at www.adaic.org specially package
Ada.Real_Time.Timing_Events.
 
AV




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-26 19:43           ` Anh Vo
       [not found]             ` <3itd22hcekts5lsojdqjnn966bbvc8fckh@4ax.com>
@ 2006-03-27  7:49             ` Dmitry A. Kazakov
  2006-03-27 18:14               ` Dmitry A. Kazakov
  1 sibling, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-27  7:49 UTC (permalink / raw)


On 26 Mar 2006 11:43:48 -0800, Anh Vo wrote:

>>> it works only if there is a specific purpose associated with an event.
>>> In other word, an event handler must be set for a specific action. The
>>> timers work almost like a generic in that the event is set once. The
>>> action is supplied at the time of instantiation.
> 
>> Where is any problem? Event is decoupled from any purpose its signalling
>> might have. You do:
> 
>> Timer_Canceled : exception;
> 
>> protected type Periodic_Timer is
>>   entry Wait_For;
>>      -- May raise Timer_Canceled
>>   procedure Set (Period : Time_Span);
>>      -- Sets. reset timer
>>   procedure Cancel;
>>      -- Stops timer. Any task in Wait_For queue gets Timer_Canceled raised
>>   entry Simulate;
>>      -- Simulates a timer event
>> private
>>   procedure Signal (...);
>>      -- To be set as a handler for Ada.Real_Time.Timing_Events
>>   [...]
>>      -- Some internal entry to requeue Wait_For, if Signal cannot
>>      -- be an entry, but must be a protected procedure, instead.
>>   Inactive : Boolean := True;
>> end Periodic_Timer;
>>
>> No tasks needed. Any number of tasks may wait for timer events. What they
>> do upon an event is up to them, as well as to take care if they catch all
>> events. So there is no deadlock if one of them hangs somewhere.
> 
> I need to digest your design more details at implementation level to if
> it works a intended.

The implementation goes roughly as follows (a modified Barnes code from
"95th rationale".) Presuming multiple waiting tasks and Signal required to
be a procedure, rather than an entry:

-- Main entrance (is closed during notification) The reason is
-- to aviod irace condition upon timer event. Otherwise a task
-- might get it twice.
entry Wait_For when Inactive or not Occured is
   if Inactive then
      raise Timer_Canceled;
   else
      requeue Wait_Notify with abort;
   end if;
end Wait_For;

-- The notification queue, this is a private entry point to gather
-- the waiting requests.
entry Wait_Notify when Inactive or Occured is
   if Inactive then
      raise Timer_Canceled;
   end if;
end Wait_Notify;

procedure Set (Period : Time_Span) is
begin
   -- attach Signal to the timer
   Inactive := False;
end Set;

procedure Signal (...) is
   Occurred := True;
end Signal;

procedure Stop is
   -- detach Signal from the timer
   Inactive := True;
end Stop;

> Regarding deadlock in general, if a deadlock occurs in one task, should
> other tasks continue to operate and the main program should not hang?

The "main program" is just a task (thread.) If it participates in deadlock,
it hangs, if it does not, then it doesn't. (:-))

The problem with synchronous messages (~callbacks) is that ithey are quite
easy falli into a deadlock. The example is Windows API. Typical scenario is
you take a mutex, send a message and spin for that mutex in the message's
callback. Thing like this happen on daily basis.

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



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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-27  7:49             ` Dmitry A. Kazakov
@ 2006-03-27 18:14               ` Dmitry A. Kazakov
  2006-03-27 22:00                 ` Anh Vo
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-27 18:14 UTC (permalink / raw)


On Mon, 27 Mar 2006 09:49:59 +0200, Dmitry A. Kazakov wrote:

> -- Main entrance (is closed during notification) The reason is
> -- to aviod irace condition upon timer event. Otherwise a task
> -- might get it twice.
> entry Wait_For when Inactive or not Occured is
>    if Inactive then
>       raise Timer_Canceled;
>    else
>       requeue Wait_Notify with abort;
>    end if;
> end Wait_For;
> 
> -- The notification queue, this is a private entry point to gather
> -- the waiting requests.
> entry Wait_Notify when Inactive or Occured is
>    if Inactive then
>       raise Timer_Canceled;

I forgot to reset it:

   else
      Occurred := Wait_Notify'Count > 0;

>    end if;
> end Wait_Notify;
> 
> procedure Set (Period : Time_Span) is
> begin
>    -- attach Signal to the timer
>    Inactive := False;
> end Set;
> 
> procedure Signal (...) is
>    Occurred := True;
> end Signal;
> 
> procedure Stop is
>    -- detach Signal from the timer
>    Inactive := True;
> end Stop;

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



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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-27 18:14               ` Dmitry A. Kazakov
@ 2006-03-27 22:00                 ` Anh Vo
  2006-03-28  7:51                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 17+ messages in thread
From: Anh Vo @ 2006-03-27 22:00 UTC (permalink / raw)



Dmitry A. Kazakov wrote:
> On Mon, 27 Mar 2006 09:49:59 +0200, Dmitry A. Kazakov wrote:
>
> > -- Main entrance (is closed during notification) The reason is
> > -- to aviod irace condition upon timer event. Otherwise a task
> > -- might get it twice.
> > entry Wait_For when Inactive or not Occured is
> >    if Inactive then
> >       raise Timer_Canceled;
> >    else
> >       requeue Wait_Notify with abort;
> >    end if;
> > end Wait_For;
> >
> > -- The notification queue, this is a private entry point to gather
> > -- the waiting requests.
> > entry Wait_Notify when Inactive or Occured is
> >    if Inactive then
> >       raise Timer_Canceled;
>
> I forgot to reset it:
>
>    else
>       Occurred := Wait_Notify'Count > 0;
>
> >    end if;
> > end Wait_Notify;
> >
> > procedure Set (Period : Time_Span) is
> > begin
> >    -- attach Signal to the timer
> >    Inactive := False;
> > end Set;
> >
> > procedure Signal (...) is
> >    Occurred := True;
> > end Signal;
> >
> > procedure Stop is
> >    -- detach Signal from the timer
> >    Inactive := True;
> > end Stop;

Dmitry,

Before going further, I would like to know if this is exactly what you
had in mind. By the way, it is compilable.


with Ada.Real_Time.Timing_Events;

package Dmitry_Timers is

   use Ada;

   Timer_Canceled : exception;

   protected type Periodic_Timer is
      entry Wait_For;
      -- May raise Timer_Canceled
      procedure Set (Period : Real_Time.Time_Span);
      -- Sets. reset timer
      procedure Cancel;
      -- Stops timer. Any task in Wait_For queue gets Timer_Canceled
raised
      entry Simulate;
      -- Simulates a timer event
   private
      procedure Signal (Event: in out
Real_Time.Timing_Events.Timing_Event);
      -- To be set as a handler for Ada.Real_Time.Timing_Events
      -- [...]
      -- Some internal entry to requeue Wait_For, if Signal cannot
      -- be an entry, but must be a protected procedure, instead.
      entry Wait_Notify;

      Inactive : Boolean := True;
      Occurred : Boolean := False;
      The_Event : Real_Time.Timing_Events.Timing_Event;
   end Periodic_Timer;

end Dmitry_Timers;

package body Dmitry_Timers is

   protected body Periodic_Timer is
      entry Wait_For when Inactive or not Occurred is
      begin
         if Inactive then
            raise Timer_Canceled;
         else
            requeue Wait_Notify with abort;
         end if;
      end Wait_For;

      entry Wait_Notify when Inactive or Occurred is
      begin
         if Inactive then
            raise Timer_Canceled;
         else
            Occurred := Wait_Notify'Count > 0;
         end if;
      end Wait_Notify;

      procedure Set (Period : Real_Time.Time_Span) is
      begin
         Real_Time.Timing_Events.Set_Handler (The_Event, Period,
Signal'access);
      end Set;

      procedure Cancel is
         Success : Boolean := False;
         use type Ada.Real_Time.Timing_Events.Timing_Event_Handler;
      begin
         if Real_Time.Timing_Events.Current_Handler (The_Event) /= null
then
            Real_Time.Timing_Events.Cancel_Handler (The_Event,
Success);
            Inactive := True;
            Occurred := False;
         end if;
      end Cancel;

      entry Simulate when True is
      begin
         null; -- What does it do exactly???
      end Simulate;

      procedure Signal (Event: in out
Real_Time.Timing_Events.Timing_Event) is
      begin
         Occurred := True;
         -- Action to be performed.
      end Signal;

   end Periodic_Timer;

end Dmitry_Timers;

AV




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
       [not found]                     ` <5vse22h4mc1och27s0nkbv986csi2rorki@4ax.com>
@ 2006-03-28  0:07                       ` Anh Vo
  0 siblings, 0 replies; 17+ messages in thread
From: Anh Vo @ 2006-03-28  0:07 UTC (permalink / raw)


>> Yes, it is clearly a typo. However, it should be OK because Ada is a
>> case insensitive language.

>        I used upper case to point out that the closing S was /missing/ in
> your posted code...

I expect some thing like this typo occur once in a while.

>        Given the supplied code I, at least, could not confirm that this is
> true in all cases... And if you really intend for something more
> flexible, you should be relying on the argument being passed in, not on
> some static single entity in the background, to identify which timer
> event triggered.

I am afraid I do not understand what mean here. Argument passing does
not always provide flexibility for all cases specially this one.

> > No, it is for real since I compiled and run it. Otherwise, I would not
>
>        Again, you misunderstood me... I meant that /my conclusions/ were
> hypothetical -- in that it is all based upon reading various web pages
> and playing with code.

I am puzzled here also. I do not see how the combination of my codes
and your reading various web pages make you conclude that this is
hypothetical.

>        As for building a GCC line... Sorry, but I am not configured to do
> such; especially not on a home WinXP machine -- it it isn't available as
> part of a pre-built binary installer, it doesn't go on.... At work, the
> company has a support agreement with ACT, and is using GNAT 3.16a; they
> are only now studying GNAT Pro for compatibility -- so obviously I
> wouldn't have access to this timing module there either (even if they
> converted to GNAT Pro).

It shoud not be difficult to build gcc-4.2.0 if you have a linux box
and approximately three hours.

AV




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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-27 22:00                 ` Anh Vo
@ 2006-03-28  7:51                   ` Dmitry A. Kazakov
  2006-03-28 16:00                     ` Anh Vo
  0 siblings, 1 reply; 17+ messages in thread
From: Dmitry A. Kazakov @ 2006-03-28  7:51 UTC (permalink / raw)


On 27 Mar 2006 14:00:01 -0800, Anh Vo wrote:

> Before going further, I would like to know if this is exactly what you
> had in mind. By the way, it is compilable.
> 
> with Ada.Real_Time.Timing_Events;
> 
> package Dmitry_Timers is
> 
>    use Ada;
> 
>    Timer_Canceled : exception;
> 
>    protected type Periodic_Timer is
>       entry Wait_For;
>       -- May raise Timer_Canceled
>       procedure Set (Period : Real_Time.Time_Span);
>       -- Sets. reset timer
>       procedure Cancel;
>       -- Stops timer. Any task in Wait_For queue gets Timer_Canceled
> raised
>       entry Simulate;
>       -- Simulates a timer event
>    private
>       procedure Signal (Event: in out
> Real_Time.Timing_Events.Timing_Event);
>       -- To be set as a handler for Ada.Real_Time.Timing_Events
>       -- [...]
>       -- Some internal entry to requeue Wait_For, if Signal cannot
>       -- be an entry, but must be a protected procedure, instead.
>       entry Wait_Notify;
> 
>       Inactive : Boolean := True;
>       Occurred : Boolean := False;
>       The_Event : Real_Time.Timing_Events.Timing_Event;
>    end Periodic_Timer;
> 
> end Dmitry_Timers;
> 
> package body Dmitry_Timers is
> 
>    protected body Periodic_Timer is
>       entry Wait_For when Inactive or not Occurred is
>       begin
>          if Inactive then
>             raise Timer_Canceled;
>          else
>             requeue Wait_Notify with abort;
>          end if;
>       end Wait_For;
> 
>       entry Wait_Notify when Inactive or Occurred is
>       begin
>          if Inactive then
>             raise Timer_Canceled;
>          else
>             Occurred := Wait_Notify'Count > 0;
>          end if;
>       end Wait_Notify;
> 
>       procedure Set (Period : Real_Time.Time_Span) is
>       begin
>          Real_Time.Timing_Events.Set_Handler (The_Event, Period,
> Signal'access);
++++++++++++++++
Inactive := False;

>       end Set;
> 
>       procedure Cancel is
>          Success : Boolean := False;
>          use type Ada.Real_Time.Timing_Events.Timing_Event_Handler;
>       begin
>          if Real_Time.Timing_Events.Current_Handler (The_Event) /= null
> then
>             Real_Time.Timing_Events.Cancel_Handler (The_Event,
> Success);
>             Inactive := True;
>             Occurred := False;
>          end if;
>       end Cancel;
> 
>       entry Simulate when True is
>       begin
>          null; -- What does it do exactly???

Emulates a premature timer event. It could be a direct call to Signal:

   Signal (The_Event);

It can be a procedure rather than entry, because Signal is a procedure.

>       end Simulate;
> 
>       procedure Signal (Event: in out
> Real_Time.Timing_Events.Timing_Event) is
>       begin
>          Occurred := True;
>          -- Action to be performed.
>       end Signal;
> 
>    end Periodic_Timer;
> 
> end Dmitry_Timers;

I cannot comment on Real_Time.Timing_Events, I have no any experience of
using it...

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



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

* Re: Designing Timers using Ada.Real_Time.Timing_Events package
  2006-03-28  7:51                   ` Dmitry A. Kazakov
@ 2006-03-28 16:00                     ` Anh Vo
  0 siblings, 0 replies; 17+ messages in thread
From: Anh Vo @ 2006-03-28 16:00 UTC (permalink / raw)


 > Emulates a premature timer event. It could be a direct call to
Signal:
>
>    Signal (The_Event);

OK got it. It is used to notify on demand.

> It can be a procedure rather than entry, because Signal is a procedure.

I agree it should be a procedure.

> >       end Simulate;
> >
> >       procedure Signal (Event: in out
> > Real_Time.Timing_Events.Timing_Event) is
> >       begin
> >          Occurred := True;
> >          -- Action to be performed.
> >       end Signal;
> >
> >    end Periodic_Timer;
> >
> > end Dmitry_Timers;
>
> I cannot comment on Real_Time.Timing_Events, I have no any experience of
> using it...

I did not have much experience on Timing_Events until I read John
Barnes' Ada 2005 rationale. In addition, I gained more confidence after
compile and running it.

AV




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

end of thread, other threads:[~2006-03-28 16:00 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-03-25 20:03 Designing Timers using Ada.Real_Time.Timing_Events package Anh Vo
2006-03-25 20:58 ` Dmitry A. Kazakov
2006-03-26  5:39   ` Anh Vo
2006-03-26 12:58     ` Dmitry A. Kazakov
2006-03-26 16:18       ` Anh Vo
2006-03-26 18:22         ` Dmitry A. Kazakov
2006-03-26 19:43           ` Anh Vo
     [not found]             ` <3itd22hcekts5lsojdqjnn966bbvc8fckh@4ax.com>
2006-03-26 23:53               ` Anh Vo
     [not found]                 ` <0mae22lshe5nee8pt8h7seussloebv07g3@4ax.com>
2006-03-27  5:01                   ` Anh Vo
     [not found]                     ` <5vse22h4mc1och27s0nkbv986csi2rorki@4ax.com>
2006-03-28  0:07                       ` Anh Vo
2006-03-27  7:49             ` Dmitry A. Kazakov
2006-03-27 18:14               ` Dmitry A. Kazakov
2006-03-27 22:00                 ` Anh Vo
2006-03-28  7:51                   ` Dmitry A. Kazakov
2006-03-28 16:00                     ` Anh Vo
2006-03-26  7:59 ` Martin Krischik
2006-03-26 15:50   ` Anh Vo

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