CVS difference for ai05s/ai05-0111-1.txt

Differences between 1.6 and version 1.7
Log of other versions for file ai05s/ai05-0111-1.txt

--- ai05s/ai05-0111-1.txt	2009/02/17 05:53:49	1.6
+++ ai05s/ai05-0111-1.txt	2009/06/02 06:22:36	1.7
@@ -3679,3 +3679,199 @@
 [This is version /04 of the AI - Editor.]
 
 ****************************************************************
+
+From: Adam Beneschan
+Sent: Tuesday, May 19, 2009  4:33 PM
+
+!topic Mark/Release storage pools and finalization
+!reference 13.11, 7.6.1(11)
+!from Adam Beneschan 09-05-19
+!discussion
+
+The example in 13.11(38-43) envisions the possibility of creating a storage pool
+with Mark and Release operations.  However, I wonder if this example isn't
+erroneous (and if it is, it probably shouldn't be in the RM).  13.11(21) says
+that when Allocate is used to allocate an object, the storage should not be used
+for anything else while the "pool element" (i.e. the allocated object, 13.11(1))
+remains in existence.  From what I can tell, an object ceases to exist when it
+is finalized as part of the finalization of a master (7.6.1(11)), in this case
+the master in which the ultimate ancestor of the access type is declared, or
+when it is deallocated with an instance of Unchecked_Deallocation.  I don't
+think there's any other way for it to cease to exist; in fact, 7.6.1(10)
+explicitly says,
+
+  If an instance of Unchecked_Deallocation is never applied to an
+  object created by an allocator, the object will still exist when
+  the corresponding master completes, and it will be finalized then.
+
+Therefore, if the storage that has been reclaimed is then reused by another
+Allocate, it is being "used for another purpose" while "the pool element remains
+in existence", and is thus erroneous by 13.11(11).
+
+There's actually a real potential problem behind this.  What happens if someone
+uses Mark_Release_Pool_Type to allocate an object with a controlled part?  When
+does its Finalize get called?  If Release is used to reclaim storage, the object
+still exists by 7.6.1(10); and when the master is finalized, the language rules
+say that any allocated objects that haven't been deallocated with
+Unchecked_Deallocation will then be finalized.  Therefore, Finalize must be
+called on an object whose storage may well have been used for some other object.
+This seems pretty obnoxious.  I realize that using a Mark_Release_Pool_Type
+implies that you had better know what you're doing and not use any access
+objects that could point to objects released with Release.  But here, the
+runtime code is *forced* to use such objects, because of the rule in 7.6.1(10).
+The programmer doesn't have the power to avoid using the released access
+objects, and doesn't have a way to tell the runtime library not to tr to
+finalize them.
+
+At first, I thought maybe this could be solved by simply decreeing that the
+Release routine performs (in effect) an Unchecked_Deallocation on all objects
+whose storage it is reclaiming. But I don't think this can be done, since the
+Mark_Release_Pool_Type implementation doesn't know anything about the types of
+the objects it's allocating; in particular, it cannot know what objects it would
+need to call Finalize on.
+
+So I think something needs to be changed.  If Mark_Release_Pool_Type is just
+considered to be a bad idea because of this problem, the example ought to be
+removed.
+
+But if this type of pool is too useful to be simply considered "bad", perhaps
+something needs to be added to the language to help Release behave correctly?
+One thought would be to add a new pool type with a new operation:
+
+   type Storage_Pool_For_Controlled is abstract new
+       Root_Storage_Pool with private;
+
+   procedure Allocated_Controlled
+       (Pool : in out Storage_Pool_For_Controlled;
+        Storage_Address : in Address) is abstract;
+
+If T'Storage_Pool has a type that is a descendant of
+Storage_Pool_For_Controlled, then when an allocator of type T is performed,
+after calling Allocate, it would also call Allocated_Controlled with the address
+of any controlled component or subcomponent of the allocated object.  The order
+would be important. Then, if the pool reclaims any storage in any manner other
+than Deallocate, it would be expected to call Finalize on any object in that
+storage for which Allocated_Controlled was earlier called (probably in the
+reverse of the order in which Allocated_Controlled was called).
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, May 19, 2009  5:12 PM
+
+> The example in 13.11(38-43) envisions the possibility of creating a
+> storage pool with Mark and Release operations.
+> However, I wonder if this example isn't erroneous (and if it is, it
+> probably shouldn't be in the RM).
+
+It is well known the example in 13.11 is erroneous. Tucker argues that the
+intent was that it works, but that doesn't change what the words say (and as you
+point out, it is more than pedantic).
+
+This has been a major point of discussion related to AI05-0111; you can read the
+threads there if you are interested. (I see one that discusses the issue from
+March 13, 2008.)
+
+Note that we're not really close to a solution on this one. (I'm actually happy
+with the current state, since it reflects reality: it might work on some
+compiler some of the time, but it isn't portable. Tucker really dislikes that,
+though.)
+
+****************************************************************
+
+From: Adam Beneschan
+Sent: Tuesday, May 19, 2009  6:14 PM
+
+> This has been a major point of discussion related to AI05-0111; you
+> can read the threads there if you are interested. (I see one that
+> discusses the issue from March 13, 2008.)
+
+Thanks for the pointer.  I do try to look for existing AI's before posting
+something like this to see if it's already been discussed, but I guess I need to
+do a better job of searching.  Personally, I'm anticipating a possible future
+project in which a mark/release pool or something along those lines would be
+very useful, so I'm hoping the problems can be straightened out.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Tuesday, May 19, 2009  7:24 PM
+
+> The example in 13.11(38-43) envisions the possibility of creating a
+> storage pool with Mark and Release operations.  However, I wonder if
+> this example isn't erroneous (and if it is, it probably shouldn't be
+> in the RM).  13.11(21) says that when Allocate is used to allocate an
+> object, the storage should not be used for anything else while the
+> "pool element" (i.e. the allocated object, 13.11(1)) remains in
+> existence.  From what I can tell, an object ceases to exist when it is
+> finalized as part of the finalization of a master (7.6.1(11)),...
+
+That's not quite correct.  All of the objects belonging to a given master are
+finalized, and then they all cease to exist.  It is possible to get your hands
+on a finalized object that still exists.  And that's not erroneous.  It should
+be in its well-defined finalized state.
+
+That's a minor point, and doesn't affect your major point, which I think is
+correct.
+
+>...in this
+> case the master in which the ultimate ancestor of the access type is
+>declared, or when it is deallocated with an instance of
+>Unchecked_Deallocation.  I don't think there's any other way for it to
+>cease to exist; in fact, 7.6.1(10) explicitly says,
+>
+>   If an instance of Unchecked_Deallocation is never applied to an
+>   object created by an allocator, the object will still exist when
+>   the corresponding master completes, and it will be finalized then.
+>
+> Therefore, if the storage that has been reclaimed is then reused by
+> another Allocate, it is being "used for another purpose" while "the
+> pool element remains in existence", and is thus erroneous by
+> 13.11(11).
+
+Right.
+
+> There's actually a real potential problem behind this.  What happens
+> if someone uses Mark_Release_Pool_Type to allocate an object with a
+> controlled part?  When does its Finalize get called?
+
+Well, I've used something like MR pools heavily, and in practice, the answer is,
+they don't work for controlled stuff.  The program will likely crash. So don't
+do that.  ;-)
+
+Not a very satisfying answer from a language point of view.
+
+As Randy mentioned, this issue is being discussed by ARG.
+
+The case I'm talking about was not actually "mark/release", but a pool that is
+finalized (and ceases to exist, and frees the memory) long before the objects it
+contains cease to exist.  It works fine in practice, so long as controlled types
+are avoided.  Same basic issue as the MR pool.
+
+...
+> But if this type of pool is too useful to be simply considered "bad",
+> perhaps something needs to be added to the language to help Release
+> behave correctly?  One thought would be to add a new pool type with a
+> new operation:
+>
+>    type Storage_Pool_For_Controlled is abstract new
+>        Root_Storage_Pool with private;
+>
+>    procedure Allocated_Controlled
+>        (Pool : in out Storage_Pool_For_Controlled;
+>         Storage_Address : in Address) is abstract;
+>
+> If T'Storage_Pool has a type that is a descendant of
+> Storage_Pool_For_Controlled, then when an allocator of type T is
+> performed, after calling Allocate, it would also call
+> Allocated_Controlled with the address of any controlled component or
+> subcomponent of the allocated object.  The order would be important.
+> Then, if the pool reclaims any storage in any manner other than
+> Deallocate, it would be expected to call Finalize on any object in
+> that storage for which Allocated_Controlled was earlier called
+> (probably in the reverse of the order in which Allocated_Controlled
+> was called).
+
+Yeah, something like that.
+
+****************************************************************

Questions? Ask the ACAA Technical Agent