"
COPYRIGHT (c) 1991 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
Array variableSubclass:#WeakArray
instanceVariableNames:'watcher dependents'
classVariableNames:'RegistrationFailedSignal'
poolDictionaries:''
category:'Collections-Arrayed'
!
WeakArray comment:'
COPYRIGHT (c) 1991 by Claus Gittinger
All Rights Reserved
$Header: /cvs/stx/stx/libbasic/Attic/WeakArr.st,v 1.6 1994-10-10 00:29:09 claus Exp $
'!
!WeakArray class methodsFor:'documentation'!
copyright
"
COPYRIGHT (c) 1991 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
"
!
version
"
$Header: /cvs/stx/stx/libbasic/Attic/WeakArr.st,v 1.6 1994-10-10 00:29:09 claus Exp $
"
!
documentation
"
WeakArrays can be used to trace disposal of objects; in contrast to other
objects, references by WeakArrays will NOT keep an object from dying.
Instead, whenever an object kept in a WeakArray dies, its entry is nilled,
and the WeakArray informed by the storage manager.
You can use WeakArrays to track disposal of objects which keep external
world resources. For example, FileStreams must close their underlying
file when disposed (otherwise you would run out of filedescriptors).
This can be done by keeping the FileStream objects in a weakArray, and
keep a parallel array of filedescriptors. Whenever a fileStream gets
free, search both arrays for an index where the stream is nil, but the
filedescriptor is non-nil. Then close that file, and nil the filedescriptor
entry.
Another application is caching of data - keep it in a weakArray, so the
data in that cache will not be unreclaimable due to being cached.
(for example, the ResourcePack class uses a WeakArray to cache recently
used resource data for a while).
This interrupt is cought here and informs the watcher and, if there is
a dependent, this one gets informed as well (I dont know, which of the
two mechanisms will survive in the long run - I started with the watcher,
but now switch to dependencies since they seem to provide more flexibility).
Therefore, be prepared, that the watcher mechanism will vanish in the
future.
"
! !
!WeakArray class methodsFor:'initialization'!
initialize
"setup the private signal"
RegistrationFailedSignal isNil ifTrue:[
Object initialize.
RegistrationFailedSignal := Object errorSignal newSignalMayProceed:true.
RegistrationFailedSignal nameClass:self message:#registrationFailedSignal.
RegistrationFailedSignal notifierString:'weakArray registration failed'.
]
! !
!WeakArray class methodsFor:'instance creation'!
new:size
"return a new weakArray with size slots"
"This is a kludge: I would like to set WEAK-flag in the classes
initialize method, but no order of class-init is defined (yet) ...
Therefore it could happen, that a WeakArray is used by other
class inits BEFORE this initialize is evaluated. To avoid this,
the WEAK bit in the class is set here, when the first WeakArray is
created."
self flags:(Behavior flagWeakPointers).
ObjectMemory disposeInterruptHandler:self.
^ (self basicNew:size) registerAsWeakArray
! !
!WeakArray methodsFor:'GC registration'!
registerAsWeakArray
"register the receiver in the VM -
i.e. tell the VM to nil disposed entries in the receiver
and notify the disposeInterruptHandler whenever that happened."
|ok|
%{
OBJ __addShadowObject();
ok = __addShadowObject(self, 0);
if (ok == false) {
/*
* this happens when too many shadow objects are
* already there, collect garbage to get rid of
* obsolete ones, and try again.
* since a full collect is expensive, we try
* a scavenge first, doing a full collect only if
* that does not help.
*/
nonTenuringScavenge(__context);
ok = __addShadowObject(self, 0);
if (ok == false) {
/* try more ... */
scavenge(__context);
ok = __addShadowObject(self, 0);
if (ok == false) {
/* hard stuff - need full collect */
__garbageCollect(__context);
ok = __addShadowObject(self, 0);
if (ok == false) {
/* mhmh - it seems that there are really many shadow
objects around - force creation */
ok = __addShadowObject(self, 1);
if (ok == false) {
/* no chance - something must be wrong */
}
}
}
}
}
%}.
ok ifFalse:[
^ RegistrationFailedSignal raiseRequestWith:self
]
! !
!WeakArray class methodsFor:'dispose handling'!
allShadowObjectsDo:aBlock
"evaluate the argument, aBlock for all known shadow objects"
%{
__allShadowObjectsDo(&aBlock, __context);
%}
!
allChangedShadowObjectsDo:aBlock
"evaluate the argument, aBlock for all known shadow objects which have
lost a pointer recently."
%{
__allChangedShadowObjectsDo(&aBlock, __context);
%}
!
disposeInterrupt
"this is triggered by the garbage collector,
whenever any shadowArray looses a pointer."
self allChangedShadowObjectsDo:[:aShadowArray |
aShadowArray changed.
aShadowArray watcher notNil ifTrue:[
aShadowArray watcher informDispose
]
]
! !
!WeakArray methodsFor:'copying'!
postCopy
"copying alone does not really help - we have to tell
the VM, that there is a new WeakArray around ...
Q: who copies weakArrays ?"
self dependents:nil.
self registerAsWeakArray.
! !
!WeakArray methodsFor:'accessing'!
dependents
"return the dependents of the receiver"
^ dependents
!
dependents:aCollection
"set the dependents of the receiver"
dependents := aCollection
!
watcher
"return the watcher of the receiver.
The watcher-stuff is a leftover from an old implementation
and will vanish soon"
^ watcher
!
watcher:anObject
"set the watcher of the receiver.
The watcher-stuff is a leftover from an old implementation
and will vanish soon"
watcher := anObject
! !