!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. ****************************************************************