On 10 October 2010 23:43, Levente Uzonyi <leves@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.