This is GarbageCollector.m in view mode; [Download] [Up]
/*
Copyright (C) 1996
Ovidiu Predescu <ovidiu@bx.logicnet.ro>
Mircea Oancea <mircea@jupiter.elcom.pub.ro>
Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
This file is part of the FoundationExtensions library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <Foundation/NSArray.h>
#include <extensions/objc-runtime.h>
#include <extensions/GCObject.h>
#include <extensions/GarbageCollector.h>
@interface __DummyGCObject : GCObject
@end
@implementation __DummyGCObject
+ allocWithZone:(NSZone*)zone
{
return NSAllocateObject(self, 0, zone);
}
- (void)dealloc
{
}
@end
/* The GCDoubleLinkedList is a double linked list which contains as the first
element a dummy GCObject. This object is always the head of the list. A
new element is introduced immediately after the head. This way we don't
need to keep track of the head of the list when we remove an element. */
@interface GCDoubleLinkedList : NSObject
{
id list;
}
- (void)addObject:(id)anObject;
- (void)removeObject:(id)anObject;
- (id)firstObject;
- (void)removeAllObjects;
@end
@implementation GCDoubleLinkedList
- init
{
list = [__DummyGCObject new];
return self;
}
- (void)addObject:(id)anObject
{
id next = [list gcNextObject];
[list gcSetNextObject:anObject];
[anObject gcSetNextObject:next];
[next gcSetPreviousObject:anObject];
[anObject gcSetPreviousObject:list];
}
- (void)removeObject:(id)anObject
{
id prev = [anObject gcPreviousObject];
id next = [anObject gcNextObject];
[prev gcSetNextObject:next];
[next gcSetPreviousObject:prev];
}
- (id)firstObject
{
return [list gcNextObject];
}
- (void)removeAllObjects
{
[list gcSetNextObject:nil];
}
@end
@implementation GarbageCollector
static id gcObjectsToBeVisited;
static BOOL isGarbageCollecting = NO;
+ (void)initialize
{
gcObjectsToBeVisited = [GCDoubleLinkedList new];
}
+ (void)collectGarbages
{
id object;
isGarbageCollecting = YES;
/* First pass. All the objects in the gcObjectsToBeVisited list
receive the -decrementRefCount message. Each object should decrement
the ref count of all objects contained. */
object = [gcObjectsToBeVisited firstObject];
while(object) {
[object gcDecrementRefCountOfContainedObjects];
[object gcSetVisited:NO];
object = [object gcNextObject];
};
/* Second pass. All the objects in the gcObjectsToBeVisited list that have
the refCount greater than 0 receive the -incrementRefCount message.
Each object should increment the ref count of all objects contained.
Then it should send the -incrementRefCount message to all objects
contained. */
object = [gcObjectsToBeVisited firstObject];
while(object) {
if([object retainCount])
[object gcIncrementRefCountOfContainedObjects];
object = [object gcNextObject];
}
/* Third pass. All the objects that still have the refCount equal with 0
are part of cyclic graphs and none of the objects from this graph
are held by some object outside graph. These objects receive the
-dealloc message. In this method they should send the -dealloc message
to objects that are garbage collectable. An object could be asked if
it is garbage collectable by sending it the -isGarbageCollectable
message. */
object = [gcObjectsToBeVisited firstObject];
while(object) {
if([object retainCount] == 0) {
id nextObject = [object gcNextObject];
/* Remove object from gcObjectsToBeVisited list. We have to keep
the old nextObject because after removing the object from list
its nextObject is altered. */
[gcObjectsToBeVisited removeObject:object];
[object dealloc];
object = nextObject;
}
else object = [object gcNextObject];
}
isGarbageCollecting = NO;
}
+ (void)addObject:(id)anObject
{
[gcObjectsToBeVisited addObject:anObject];
}
+ (void)objectWillBeDeallocated:(id)anObject
{
/* We can remove without fear the object from its list because the head of
the list is always the same. */
id prev = [anObject gcPreviousObject];
id next = [anObject gcNextObject];
[prev gcSetNextObject:next];
[next gcSetPreviousObject:prev];
}
+ (BOOL)isGarbageCollecting { return isGarbageCollecting; }
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.