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.