This is GarbageCollector.m in view mode; [Download] [Up]
/*
GarbageCollector.m
Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
All rights reserved.
Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
This file is part of libFoundation.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.
We disclaim all warranties with regard to this software, including all
implied warranties of merchantability and fitness, in no event shall
we be liable for any special, indirect or consequential damages or any
damages whatsoever resulting from loss of use, data or profits, whether in
an action of contract, negligence or other tortious action, arising out of
or in connection with the use or performance of this software.
*/
#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.