Version 1.1 of acs/ac-00139.txt

Unformatted version of acs/ac-00139.txt version 1.1
Other versions for file acs/ac-00139.txt

!standard D.15(22/2)          07-01-22 AC95-00139/01
!class confirmation 07-01-22
!status received no action 07-01-22
!status received 06-11-12
!subject Deallocating timing events in Ada.Real_Time.Timing_events timing event handler
!summary
!appendix

From: Brad Moore
Date: Sunday, November 12, 2006  4:18 PM

The RM appears to be unclear with regard to deallocating timing events
for the Ada.Real_Time.Timing_Events package.

Specifically, it is not clear whether or not timing events allocated
from the heap can be deallocated in the client supplied
timing_event_handler callback.

There are cases where it would be very natural for the client to
allocate timing events, and have the timing_events deallocated once the
processing is complete from within client supplied timing_event_handler.

For this to work, the Ada.Real_Time.Timing_Events implementation needs
to assume that the timing_event may have been finalized upon returning
from the client supplied callback.

The current GNAT implementation supports this, but it is not clear that
every implementation would support this.

If the client is interested in portability, but is unable to assume that
timing_events can be finalized in the timing_event_handler, then the
client may potentially need to implement a garbage collection scheme in
a separate task to ensure a memory leak is avoided. This is awkward.

If the RM clearly stated that the implementation needs to support
finalizing timing events from within the timing_event_handler, the
Ada.Real_Time.Timing_Events package increases usability, since it can
significantly reduces the amount of code that the client might need to
write.

Assuming that timing events can be finalized within the
timing_event_handler, the next issue is that it is not easy for the
client to determine if a particular timing event has been finalized or
not, since timing events can be finalized in the context of the
Ada.Real_Time.Timing_Events package.

This could be facilitated by having the Current_Handler function in
Ada.Real_Time.Timing_Events check to see if the reference to the timing
event exists in the internal list of scheduled events. If it doesn't,
then it is safe to assume that the event does not have a current
handler, so that null could be returned. 

If the reference does exist in the list, then it can be assumed that the
timing event has not been finalized, and the timing event can be
dereferenced to retrieve the current handler to return to the client.

If a client knows that its timing_event will automatically be finalized
due to being processed at the timeout expiry, this provides a convenient
way for the client to determine if the timing_event has been processed
and finalized.

If for example, the client wanted to call Cancel_Handler sometime after
calling Set_Handler, the client could first check to see if the
timing_event has been finalized by calling Current_Handler. If null is
returned, it means the timing_event has already occurred, and there is
no need to cancel the timer or finalize the timing_event.

If the client cannot assume this behaviour for the Current_Handler call,
then the client is forced to keep a list of active timing_events, and
the burden of checking the reference is placed on the client.

The RM does not state the behaviour of Current_Handler when passed a
finalized timing_event. Given that there is a valid use case for this
scenario, what is the behaviour? Is null returned? Is an exception
raised? Is it implementation defined?

If the RM stated that Current_Handler returned null if the timing_event
parameter has been finalized due to timing_event_handler processing,
then usability of this package is increased by decreasing the amount of
code the client needs to write.

Note, I believe the same issues also apply to the
Ada.Execution_Time.Timers, and Ada.Execution_Time.Group_Budget packages.

In summary, there are two related issues that could be addressed by
providing more detail in the RM.

Of these two issues, the most important would be to state that the
implementation should allow finalizing timing_events from within the
timing_event_handler.

If the first issue is addressed, the second issue would be state that
Current_Handler returns null if passed a timing_event reference that has
been finalized, due to timer callback processing. The assumption is that
if the event has been finalized by the client, then there wont be a
matching reference in the internal list of scheduled events.

The RM should also state that it is erroneous for the client to finalize
a timing_event after calling Set_Handler, without first calling
Cancel_Handler.

****************************************************************

From: Randy Brukardt
Date: Monday, November 13, 2006  12:09 AM

...
> Specifically, it is not clear whether or not timing events allocated
> from the heap can be deallocated in the client supplied
> timing_event_handler callback.

It would have been nice if you had given an example of what you are talking
about; I'm guessing a bit.

Surely, an event other than the one that is pased to the handler can be
deallocated. Why wouldn't it be able to be, it is independent.

OTOH, it would be exceedingly bad practice to deallocate the event that is
passed to the handler. I'm talking about a case like:

    type Access_to_Event is access all Timing_Event;
    AE : Access_to_Event;
    procedure Free is new Ada.Unchecked_Deallocation (Timing_Event,
                        Access_to_Event);

    ...
    procedure Handler (Event : in out Timing_Event) is -- Presume this is
                                                  -- in a protected type
    begin
       Free (AE);
    end Handler;

If AE.all = Event, then this code is very bad practice (even if it is not
technically erroneous) -- having nothing to do with Timing_Event, simply bad
practice in general. If a Timing_Event were passed by copy, it definitely
would be erroneous (the copy back would be into deallocated memory). I'm not
certain whether it would be erroneous for a pass-by-reference parameter,
although there seem to be many cases where it would be (if a check needed to
be performed, for instance, which would require reading deallocated memory).
I would not want to encourage this sort of dangerous programming style for
the run-time.

Of course, just because some code is erroneous does not mean that it might
not work on some implementation. But this is the sort of programming that
should be avoided. It is never correct to deallocate the object passed
directly in a handler (remember that Finalize routines never should
deallocate the object passed, either).

As such, I wouldn't want to be trying to make this sort of thing work -- it
just doesn't fit the Ada model of handlers. (It might be possible to allow
this in a package that was designed from the ground up for that sort of
deallocation: presumably it would pass access values rather than objects to
the handlers, and would allow them to be deallocated. But it's too late for
that sort of redesign for the timing events.

In any case, I would say that your original question doesn't need to be
specifically mentioned by the Standard -- it just follows from the regular
language rules. And what you are trying to do is (or should be) erroneous
for any program -- there is nothing special about Timing_Events here.

****************************************************************


Questions? Ask the ACAA Technical Agent