mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
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:
parent
67c379bc7a
commit
940de12cab
10 changed files with 249 additions and 201 deletions
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -73,11 +73,6 @@
|
|||
}
|
||||
@end
|
||||
|
||||
@interface GSInlineArray : GSArray
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
@interface GSPlaceholderArray : NSArray
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue