More garbage collection updates/fixes.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@27590 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2009-01-13 15:57:38 +00:00
parent 67c379bc7a
commit 940de12cab
10 changed files with 249 additions and 201 deletions

View file

@ -43,7 +43,11 @@
static SEL eqSel;
static SEL oaiSel;
#if GS_WITH_GC
static Class GSArrayClass;
#else
static Class GSInlineArrayClass;
#endif
@class GSArray;
@ -75,7 +79,8 @@ static Class GSInlineArrayClass;
[NSNumber numberWithUnsignedInt: _count], @"Count",
self, @"Array", nil, nil];
reason = [NSString stringWithFormat: @"Index %d is out of range %d (in '%@')",
reason = [NSString stringWithFormat:
@"Index %d is out of range %d (in '%@')",
index, _count, NSStringFromSelector(sel)];
exception = [NSException exceptionWithName: NSRangeException
@ -91,7 +96,11 @@ static Class GSInlineArrayClass;
[self setVersion: 1];
eqSel = @selector(isEqual:);
oaiSel = @selector(objectAtIndex:);
#if GS_WITH_GC
GSArrayClass = [GSArray class];
#else
GSInlineArrayClass = [GSInlineArray class];
#endif
}
}
@ -349,19 +358,29 @@ static Class GSInlineArrayClass;
}
@end
#if !GS_WITH_GC
/* This class stores objects inline in data beyond the end of the instance.
* However, when GC is enabled the object data is typed, and all data after
* the end of the class is ignored by the garbage collector (which would
* mean that objects in the array could be collected).
* We therefore do not provide the class ewhan GC is being used.
*/
@interface GSInlineArray : GSArray
{
}
@end
@implementation GSInlineArray
- (void) dealloc
{
if (_contents_array)
{
#if !GS_WITH_GC
unsigned i;
for (i = 0; i < _count; i++)
{
[_contents_array[i] release];
}
#endif
}
NSDeallocateObject(self);
GSNOSUPERDEALLOC;
@ -392,6 +411,7 @@ static Class GSInlineArrayClass;
return self;
}
@end
#endif
@implementation GSMutableArray
@ -437,7 +457,11 @@ static Class GSInlineArrayClass;
{
NSArray *copy;
#if GS_WITH_GC
copy = (id)NSAllocateObject(GSArrayClass, 0, zone);
#else
copy = (id)NSAllocateObject(GSInlineArrayClass, sizeof(id)*_count, zone);
#endif
return [copy initWithObjects: _contents_array count: _count];
}
@ -1002,7 +1026,11 @@ static Class GSInlineArrayClass;
+ (void) initialize
{
#if GS_WITH_GC
GSArrayClass = [GSArray class];
#else
GSInlineArrayClass = [GSInlineArray class];
#endif
}
- (id) autorelease
@ -1039,13 +1067,21 @@ static Class GSInlineArrayClass;
}
else
{
GSInlineArray *a;
unsigned c;
#if GS_WITH_GC
GSArray *a;
[aCoder decodeValueOfObjCType: @encode(unsigned) at: &c];
a = (id)NSAllocateObject(GSArrayClass, 0, GSObjCZone(self));
a->_contents_array = NSZoneMalloc(GSObjCZone(self), sizeof(id)*c);
#else
GSInlineArray *a;
[aCoder decodeValueOfObjCType: @encode(unsigned) at: &c];
a = (id)NSAllocateObject(GSInlineArrayClass,
sizeof(id)*c, GSObjCZone(self));
a->_contents_array = (id*)&a[1];
#endif
if (c > 0)
{
[aCoder decodeArrayOfObjCType: @encode(id)
@ -1059,8 +1095,12 @@ static Class GSInlineArrayClass;
- (id) initWithObjects: (id*)objects count: (unsigned)count
{
#if GS_WITH_GC
self = (id)NSAllocateObject(GSArrayClass, 0, GSObjCZone(self));
#else
self = (id)NSAllocateObject(GSInlineArrayClass, sizeof(id)*count,
GSObjCZone(self));
#endif
return [self initWithObjects: objects count: count];
}

View file

@ -73,11 +73,6 @@
}
@end
@interface GSInlineArray : GSArray
{
}
@end
@interface GSPlaceholderArray : NSArray
{
}

View file

@ -84,7 +84,6 @@ extern void GSPropertyListMake(id,NSDictionary*,BOOL,BOOL,unsigned,id*);
static Class NSArrayClass;
static Class GSArrayClass;
static Class GSInlineArrayClass;
static Class NSMutableArrayClass;
static Class GSMutableArrayClass;
static Class GSPlaceholderArrayClass;
@ -125,7 +124,6 @@ static SEL rlSel;
NSArrayClass = [NSArray class];
NSMutableArrayClass = [NSMutableArray class];
GSArrayClass = [GSArray class];
GSInlineArrayClass = [GSInlineArray class];
GSMutableArrayClass = [GSMutableArray class];
GSPlaceholderArrayClass = [GSPlaceholderArray class];

View file

@ -82,6 +82,7 @@ static unsigned disabled = 0;
- (void) disableCollectorForPointer: (void *)ptr
{
// FIXME
[self notImplemented: _cmd];
return;
}
@ -102,6 +103,7 @@ static unsigned disabled = 0;
- (void) enableCollectorForPointer: (void *)ptr
{
// FIXME
[self notImplemented: _cmd];
return;
}

View file

@ -30,13 +30,22 @@
*/
#include "config.h"
#include "Foundation/NSNotification.h"
#include "Foundation/NSException.h"
#include "Foundation/NSLock.h"
#include "Foundation/NSThread.h"
#include "Foundation/NSDebug.h"
#include "GNUstepBase/GSLock.h"
#import "Foundation/NSNotification.h"
#import "Foundation/NSException.h"
#import "Foundation/NSLock.h"
#import "Foundation/NSThread.h"
#import "Foundation/NSDebug.h"
#import "GNUstepBase/GSLock.h"
/* purgeCollected() returns a list of observations with any observations for
* a collected observer removed.
*/
#if GS_WITH_GC
#include <gc.h>
#define purgeCollected(X) (X = listPurge(X, nil))
#else
#define purgeCollected(X) (X)
#endif
/**
* Concrete class implementing NSNotification.
@ -425,6 +434,9 @@ static void obsFree(Observation *o)
{
NCTable *t = o->link;
#if GS_WITH_GC
GC_unregister_disappearing_link((GC_PTR*)&o->observer);
#endif
o->link = (NCTable*)t->freeList;
t->freeList = o;
}
@ -533,7 +545,7 @@ purgeMapNode(GSIMapTable map, GSIMapNode node, id observer)
* I know of.
*
* We also use this trick to differentiate between map table keys that
* should be treated as objects (notification names) and thise that
* should be treated as objects (notification names) and those that
* should be treated as pointers (notification objects)
*/
#define CHEATGC(X) (id)(((uintptr_t)X) | 1)
@ -641,7 +653,10 @@ static NSNotificationCenter *default_center = nil;
*
* <p>The notification center does not retain observer or object. Therefore,
* you should always send removeObserver: or removeObserver:name:object: to
* the notification center before releasing these objects.</p>
* the notification center before releasing these objects.<br />
* As a convenience, when built with garbage collection, you do not need to
* remove any garbage collected observer as the system will do it implicitly.
* </p>
*
* <p>NB. For MacOS-X compatibility, adding an observer multiple times will
* register it to receive multiple copies of any matching notification, however
@ -687,8 +702,23 @@ static NSNotificationCenter *default_center = nil;
o->retained = 0;
o->next = 0;
#if GS_WITH_GC
/* Ensure that if the observer is garbage collected, we clear the
* oservation so that we don't end up sending notifications to the
* deallocated object.
* The observer must be a real GC-allocated object or this mechanism
* can't be used.
*/
if (GC_base(observer) != 0)
{
GC_general_register_disappearing_link((GC_PTR*)&o->observer, observer);
}
#endif
if (object != nil)
object = CHEATGC(object);
{
object = CHEATGC(object);
}
/*
* Record the Observation in one of the linked lists.
@ -943,6 +973,7 @@ static NSNotificationCenter *default_center = nil;
*/
- (void) _postAndRelease: (NSNotification*)notification
{
IF_NO_GC(GSGarbageCollector *collector = [NSGarbageCollector defaultCollector])
Observation *o;
unsigned count;
NSString *name = [notification name];
@ -952,6 +983,9 @@ static NSNotificationCenter *default_center = nil;
GSIArrayItem i[64];
GSIArray_t b;
GSIArray a = &b;
#if GS_WITH_GG
GSGarbageCollector *collector = [NSGarbageCollector defaultCollector];
#endif
if (name == nil)
{
@ -971,14 +1005,21 @@ static NSNotificationCenter *default_center = nil;
GSIArrayInitWithZoneAndStaticCapacity(a, NSDefaultMallocZone(), 64, i);
/*
* Lock the table of observers while we traverse it.
* Lock the table of observations while we traverse it.
*
* The table of observations contains weak pointers which are zeroed when
* the observers get garbage collected. So to avoid consistency problems
* we disable gc while we copy all the observations we are interested in.
*/
lockNCTable(TABLE);
#if GS_WITH_GG
[collector disable];
#endif
/*
* Find all the observers that specified neither NAME nor OBJECT.
*/
for (o = WILDCARD; o != ENDOBS; o = o->next)
for (o = purgeCollected(WILDCARD); o != ENDOBS; o = o->next)
{
GSIArrayAddItem(a, (GSIArrayItem)o);
}
@ -991,7 +1032,7 @@ static NSNotificationCenter *default_center = nil;
n = GSIMapNodeForSimpleKey(NAMELESS, (GSIMapKey)object);
if (n != 0)
{
o = n->value.ext;
o = purgeCollected(n->value.ext);
while (o != ENDOBS)
{
GSIArrayAddItem(a, (GSIArrayItem)o);
@ -1023,7 +1064,7 @@ static NSNotificationCenter *default_center = nil;
n = GSIMapNodeForSimpleKey(m, (GSIMapKey)object);
if (n != 0)
{
o = n->value.ext;
o = purgeCollected(n->value.ext);
while (o != ENDOBS)
{
GSIArrayAddItem(a, (GSIArrayItem)o);
@ -1039,7 +1080,7 @@ static NSNotificationCenter *default_center = nil;
n = GSIMapNodeForSimpleKey(m, (GSIMapKey)nil);
if (n != 0)
{
o = n->value.ext;
o = purgeCollected(n->value.ext);
while (o != ENDOBS)
{
GSIArrayAddItem(a, (GSIArrayItem)o);
@ -1047,13 +1088,17 @@ static NSNotificationCenter *default_center = nil;
}
}
}
}
}
/*
* Finished with the table ... we can unlock it.
* Finished with the table ... we can unlock it and re-enable garbage
* collection, safe in the knowledge that the observers we will be
* notifying won't get collected prematurely.
*/
#if GS_WITH_GG
[collector enable];
#endif
unlockNCTable(TABLE);
/*

View file

@ -80,6 +80,10 @@
#include "GSPrivate.h"
#include "GSRunLoopCtxt.h"
#if GS_WITH_GC
#include <gc.h>
#endif
@interface NSAutoreleasePool (NSThread)
+ (void) _endThread: (NSThread*)thread;
@end
@ -506,6 +510,9 @@ gnustep_base_thread_callback(void)
objc_thread_set_data (NULL);
#if GS_WITH_GC && defined(HAVE_GC_REGISTER_MY_THREAD)
GC_unregister_my_thread();
#endif
/*
* Tell the runtime to exit the thread
*/
@ -734,6 +741,9 @@ gnustep_base_thread_callback(void)
NSStringFromSelector(_cmd)];
}
#if GS_WITH_GC && defined(HAVE_GC_REGISTER_MY_THREAD)
GC_register_my_thread();
#endif
#if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
if (_stackSize > 0)
{