WeakArr.st
author claus
Mon, 10 Oct 1994 01:29:28 +0100
changeset 159 514c749165c3
parent 95 d22739a0c6e9
child 186 a4c3032fc825
permissions -rw-r--r--
*** empty log message ***

"
 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
! !