From: Dmitry A. Kazakov on
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
From: Jean-Pierre Rosen on
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(a)adalog.fr)
Visit Adalog's web site at http://www.adalog.fr
From: John B. Matthews on
In article <h9g8mf$v4f$1(a)news.eternal-september.org>,
Reto Buerki <reet(a)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>
From: Brad Moore on
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
From: Dmitry A. Kazakov on
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