|Title||Unclear how to destroy a pool containing objects registered for finalization|
|Assigned user||Richard Brooksby|
|Description||The reference manual  says:|
"Note that there will be no attempt to finalize objects in the context of mps_arena_destroy or mps_pool_destroy. mps_pool_destroy should therefore not be invoked on pools containing objects registered for finalization."
How, then, do you destroy a pool containing objects registered for finalization?
|Analysis||Destroying the pool does not destroy finalization guardians that point into the pool. So these finalization guardians still exist (with the finalization reference pointing the space where the pool used to be). If finalization takes place, the finalization message will be posted. And then if the finalization code deferences the finalization reference, they'll get whatever now lives in that bit of memory (or maybe a segmentation fault).|
GDR 2013-05-21: I added a test case that destroys a pool containing finalization guardians (and then carries on allocating for a while in another pool). This test case fails with the assertion:
MPS ASSERTION FAILURE: ss->rank < RankEXACT || !ArenaIsReservedAddr(ss->arena, ref)
(Because ss->rank is RankFINAL.)
The backtrace shows:
#3 0x0000000100030b2b in _mps_fix2 (mps_ss=0x7fff5fbff420, mps_ref_io=0x7fff5fbff2a8) at trace.c:1380
#4 0x0000000100176617 in MRGRefSegScan (ss=0x7fff5fbff418, refseg=0x101812190, mrg=0x101ffdca8) at poolmrg.c:610
#5 0x0000000100175965 in MRGScan (totalReturn=0x7fff5fbff4e4, ss=0x7fff5fbff418, pool=0x101ffdca8, seg=0x101812190) at poolmrg.c:851
#6 0x000000010008d1b0 in PoolScan (totalReturn=0x7fff5fbff4e4, ss=0x7fff5fbff418, pool=0x101ffdca8, seg=0x101812190) at pool.c:397
#7 0x000000010018cd74 in traceScanSegRes (ts=1, rank=2, arena=0x1003b9000, seg=0x101812190) at trace.c:1162
#8 0x000000010009dc09 in traceScanSeg (ts=1, rank=2, arena=0x1003b9000, seg=0x101812190) at trace.c:1222
#9 0x00000001000a2b90 in TraceQuantum (trace=0x1003b9598) at trace.c:1833
#10 0x0000000100072e8d in TracePoll (globals=0x1003b9000) at trace.c:1981
#11 0x000000010000e5a6 in ArenaRelease (globals=0x1003b9000) at traceanc.c:562
#12 0x000000010000f6ad in ArenaStartCollect (globals=0x1003b9000, why=5) at traceanc.c:610
#13 0x000000010000f858 in ArenaCollect (globals=0x1003b9000, why=5) at traceanc.c:625
#14 0x000000010000f733 in mps_arena_collect (arena=0x1003b9000) at mpsi.c:295
Perhaps destroying a pool should destroy all finalization guardians that point into the pool? However, this would be an O(n) operation and we don't want to add such operations to the MPS.
Here's a design that avoids O(n) operations, but which adds a RingStruct to every finalization guardian:
* When the client program first registers a finalizable object in a pool P, allocate a *pool guardian* in the MRG pool.
* The pool P refers to its pool guardian if it exists.
* The pool guardian for P is the head of a ring. When the client program registers a finalizable object in pool P, add the corresponding finalization guardian to this ring.
* When pool P is about to be destroyed and if it has a pool guardian: free the pool guardian immediately if its ring is empty; otherwise, mark it as referring to a deleted pool.
* Before scanning a finalization reference, check its pool guardian: if this is marked as referring to a deleted pool, free the finalization guardian instead. If this causes the pool guardian's ring to become empty then free the pool guardian too.
|Created by||Gareth Rees|
|Created on||2012-10-24 15:15:44|
|Last modified by||Gareth Rees|
|Last modified on||2013-06-06 13:03:45|
|History||2012-10-24 GDR Created.|
2013-05-21 GDR Describe test case and assertion failure.
|182166||closed||2013-05-24 16:17:51||Gareth Rees||Document the way to safely destroy automatically managed pools.|