Prev: Package's private parts and protected types
Next: GNAT.Expect on Windows, without terminal window
From: Florian Weimer on 8 Feb 2010 09:16 It looks as if I might need to do some Ada maintenance programming soon. I can use the GNAT from GCC 4.3. Are there any new ways to ensure resource cleanup? I tried to use Ada.Finalization.Limited_Controlled in the past, but there were several issues with it: there was some run-time overhead (because of the tag and because the finalizer is abort-deferred, which seemed to defeat inlining and scalar replacement of aggregates), it was impossible to instantiate generics containing such types below the library level, and having multiple different types inherting from Limited_Controled in the same package often resulted in multi-dispatch errors (and using 'Class required exposing the tagged nature of the type in the interface, with has other drawbacks). Explicit cleanup using cleanup subprograms is okay, too, provided that there is some tool to ensure that they are used properly. This is despite the rather cumbersome syntax: declare X : Object; begin Init (X); begin Make_Use_Of (X); exception when others => Cleanup (X); raise; end; Cleanup (X); end; But I'd really have a tool that ensures that Init and Cleanup calls are properly paired in this way. Are there other approaches I don't know about yet?
From: Robert A Duff on 8 Feb 2010 10:31 Florian Weimer <fw(a)deneb.enyo.de> writes: > It looks as if I might need to do some Ada maintenance programming > soon. I can use the GNAT from GCC 4.3. > > Are there any new ways to ensure resource cleanup? > > I tried to use Ada.Finalization.Limited_Controlled in the past, but > there were several issues with it: there was some run-time overhead AdaCore is working on a more efficient implementation of finalization. > (because of the tag and because the finalizer is abort-deferred, ... I think if you use the appropriate pragma Restrictions, so the compiler knows there are no aborts, it will avoid the cost of deferring and undeferring aborts (which is quite high on some systems). >...which > seemed to defeat inlining Inlining of what? The Initialize and Finalize calls? It seems feasible to inline them in most cases, but I'm not sure if GNAT is capable of that. Try it. >...and scalar replacement of aggregates), it > was impossible to instantiate generics containing such types below the > library level,... Ada 2005 allows such nesting (with or without generics). .....and having multiple different types inherting from > Limited_Controled in the same package often resulted in multi-dispatch > errors (and using 'Class required exposing the tagged nature of the > type in the interface, with has other drawbacks). Yes, but in my experience these are minor issues. Another way to avoid multi-dispatch is to put the procedure in a nested package. Both workarounds are annoying, I admit. > Explicit cleanup using cleanup subprograms is okay, too, provided that > there is some tool to ensure that they are used properly. This is > despite the rather cumbersome syntax: > > declare > X : Object; > > begin > Init (X); > begin > Make_Use_Of (X); > exception > when others => > Cleanup (X); > raise; > end; > Cleanup (X); > end; > > But I'd really have a tool that ensures that Init and Cleanup calls > are properly paired in this way. You could wrap this is a procedure: procedure With_Cleanup (Action : not null access procedure (...)); so you only have to write the above pattern once (per type that needs cleanup), and you can call it with any Action procedure you like. Note that this is slightly different from using Limited_Controlled, because it does not clean up in case of abort. If you don't use abort, then this is not an issue. > Are there other approaches I don't know about yet? I think that about covers it. - Bob
From: Jean-Pierre Rosen on 8 Feb 2010 10:29 Florian Weimer a �crit : > declare > X : Object; > > begin > Init (X); > begin > Make_Use_Of (X); > exception > when others => > Cleanup (X); > raise; > end; > Cleanup (X); > end; > > But I'd really have a tool that ensures that Init and Cleanup calls > are properly paired in this way. > Such a tool exists, of course ;-). AdaControl rule Unsafe_Paired_Calls. -- --------------------------------------------------------- J-P. Rosen (rosen(a)adalog.fr) Visit Adalog's web site at http://www.adalog.fr
From: Florian Weimer on 8 Feb 2010 11:01 * Robert A. Duff: >> (because of the tag and because the finalizer is abort-deferred, ... > > I think if you use the appropriate pragma Restrictions, so the > compiler knows there are no aborts, it will avoid the cost > of deferring and undeferring aborts (which is quite high > on some systems). What is the appropriate pragma? This doesn't seem to have an effect: pragma Restrictions (No_Asynchronous_Control); >>...which >> seemed to defeat inlining > > Inlining of what? The Initialize and Finalize calls? Most of the benefit of inlining them, because there are multiple subprogram calls involved, including indirect ones. I doubt GCC treats them as intrinsics, so they interfere with register allocation etc. GCC doesn't seem to be able to devirtualize the implicit call to Finalize, either. I don't understand why GNAT needs to maintain a separate finalization list, either. C++ use regular exception handling for this task. > You could wrap this is a procedure: > > procedure With_Cleanup (Action : not null access procedure (...)); > > so you only have to write the above pattern once (per type that needs > cleanup), and you can call it with any Action procedure you like. Yes, I need to try that. Back when the original code was written, anonymous access-to-subprogram types were still rather buggy.
From: Robert A Duff on 8 Feb 2010 11:18 Florian Weimer <fw(a)deneb.enyo.de> writes: > * Robert A. Duff: > >>> (because of the tag and because the finalizer is abort-deferred, ... >> >> I think if you use the appropriate pragma Restrictions, so the >> compiler knows there are no aborts, it will avoid the cost >> of deferring and undeferring aborts (which is quite high >> on some systems). > > What is the appropriate pragma? This doesn't seem to have an effect: > > pragma Restrictions (No_Asynchronous_Control); That one says "I promise not to say 'with Ada.Asynchronous_Task_Control'", which is not related to aborts. It is considered obsolescent, because there's now a more general No_Dependence restriction. To get rid of aborts, I think you need both No_Abort_Statements and Max_Asynchronous_Select_Nesting => 0. I believe this will cause the overhead of abort deferral to go away, but to be sure, you should try it. >>>...which >>> seemed to defeat inlining >> >> Inlining of what? The Initialize and Finalize calls? > > Most of the benefit of inlining them, because there are multiple > subprogram calls involved, including indirect ones. I doubt GCC > treats them as intrinsics, so they interfere with register allocation > etc. GCC doesn't seem to be able to devirtualize the implicit call to > Finalize, either. > > I don't understand why GNAT needs to maintain a separate finalization > list, either. C++ use regular exception handling for this task. The new implementation of finalization I mentioned avoids those lists. Except that lists are needed in the case of heap-allocated objects, because they need to be finalized when the scope of the access type is left (unless finalized early by Unchecked_Deallocation). C++ does not require that, so is easier to implement, at the cost of possibly missing some finalizations. But anyway, efficient finalization is most important for stack-allocated objects. >> You could wrap this is a procedure: >> >> procedure With_Cleanup (Action : not null access procedure (...)); >> >> so you only have to write the above pattern once (per type that needs >> cleanup), and you can call it with any Action procedure you like. > > Yes, I need to try that. Back when the original code was written, > anonymous access-to-subprogram types were still rather buggy. And inefficient, because they used trampolines. GNAT got rid of trampolines except in some corner cases. Note that trampolines will cause your program to crash if DEP is enabled on windows (or the equivalent feature on Linux). There's a restriction for that, too -- search the GNAT docs for "trampoline". - Bob
|
Next
|
Last
Pages: 1 2 Prev: Package's private parts and protected types Next: GNAT.Expect on Windows, without terminal window |