[Pharo-project] [squeak-dev] Re: WeakRegistry>>remove: - when you'll be in trouble

Igor Stasenko siguctua at gmail.com
Sun Oct 10 19:10:50 EDT 2010

On 10 October 2010 23:43, Levente Uzonyi <leves at elte.hu> wrote:
> On Sun, 10 Oct 2010, Igor Stasenko wrote:
>> A current implementation of this method
>> remove: oldObject ifAbsent: exceptionBlock
>>        "Remove oldObject as one of the receiver's elements."
>>        oldObject ifNil: [ ^nil ].
>>        ^(self protected: [ valueDictionary removeKey: oldObject ifAbsent:
>> nil ])
>>                ifNil: [ exceptionBlock value ]
>> simply removes a previously registered object from registry and voila.
>> Now lets get back to our discussion about multiple finalizers per
>> object and using them in weak subscriptions etc.
>> Suppose i am added a socket to weak registry,
>> and suppose i am added a weak subscription to it.
>> Now, if i do 'socket close' , it tells weak registry to remove it from
>> list.
>> And what we'll have:
>> - socket handle is closed
>> - socket is wiped from weak registry
>> - but weak subscription still listed somewhere in a list of subscriptions
>> My suggestion is, that upon #remove:,
>> a weak registry should notify all executors that object of interest
>> are no longer takes part in finalization scheme,
>> so they should not count on receiving #finalize eventually.
>> In other words:
>> remove: oldObject ifAbsent: exceptionBlock
>>        "Remove oldObject as one of the receiver's elements."
>>        oldObject ifNil: [ ^nil ].
>>        ^(self protected: [ | executor |
>>            executor := valueDictionary removeKey: oldObject ifAbsent: nil.
>>            executor discardFinalization.
>>        ])
>>        ifNil: [ exceptionBlock value ]
> It's only an issue with the new WeakRegistry implementation, previous
> implementations don't have such problem. I think changing the method as you
> suggested, implementing WeakFinalizerItem >> #discardFinalization as
> "executor := nil" and changing WeakFinalizerItem >> #finalizaValues to
> ignore the executor if it's nil will fix the problem. Am I right?
> I don't get how "multiple finalizers per object" is related to this problem
> at all.

No, you miss the point.
When you removing object from weak registry, it is important , time to
time to tell all of its executors,
that they will no longer receive #finalize, because object is no
longer a member of weak registry.

If you simply set executor := nil, it does nothing, an executor itself
did not notified that he won't be needed
in any possible future.
So, if your finalization action is to remove some object(s) from the
list , you'll get your list dirty after object will die,
because #finalize will be never sent to your executor.

Here the simple test case:

| coll obj someWrapper |
coll := OrderedCollection new.
obj := Object new.
someWrapper := WeakArray with: obj.
coll add: someWrapper.

obj toFinalizeSend: #remove: to: coll with: someWrapper.
obj finalizationRegistry remove: obj.
obj := nil.
Smalltalk garbageCollect.
self assert: coll isEmpty

the point is, that once you doing a #remove: ,
your finalization scheme is broken.

> Levente

Best regards,
Igor Stasenko AKA sig.

More information about the Pharo-dev mailing list