Add some flexibility

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@33355 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2011-06-20 07:33:27 +00:00
parent c5c5f18075
commit e84d049078
4 changed files with 125 additions and 84 deletions

View file

@ -129,120 +129,132 @@
struct exitLink {
struct exitLink *next;
Class cls;
};
struct leakLink {
struct leakLink *next;
id obj;
id *at;
id obj; // Object to release or class for atExit
SEL sel; // Selector for atExit or 0 if releasing
id *at; // Address of static variable or NULL
};
static struct exitLink *exited = 0;
static struct leakLink *leaked = 0;
static BOOL enabled = NO;
static BOOL shouldCleanUp = NO;
static void
handleExit()
{
if (YES == shouldCleanUp)
while (exited != 0)
{
while (leaked != 0)
{
struct leakLink *tmp = leaked;
struct exitLink *tmp = exited;
leaked = tmp->next;
exited = tmp->next;
if (0 != tmp->sel)
{
Method method;
IMP msg;
method = class_getClassMethod(tmp->obj, tmp->sel);
msg = method_getImplementation(method);
if (0 != msg)
{
(*msg)(tmp->obj, tmp->sel);
}
}
else if (YES == shouldCleanUp)
{
if (0 != tmp->at)
{
tmp->obj = *(tmp->at);
*(tmp->at) = nil;
}
[tmp->obj release];
free(tmp);
}
}
while (exited != 0)
{
struct exitLink *tmp = exited;
exited = tmp->next;
[tmp->cls atExit];
free(tmp);
}
[gnustep_global_lock release];
}
@implementation NSObject(atExit)
+ (void) atExit
{
return;
}
@implementation NSObject(GSCleanup)
+ (id) leakAt: (id*)anAddress
{
struct leakLink *l;
struct exitLink *l;
l = (struct leakLink*)malloc(sizeof(struct leakLink));
l = (struct exitLink*)malloc(sizeof(struct exitLink));
l->at = anAddress;
l->obj = [*anAddress retain];
l->sel = 0;
[gnustep_global_lock lock];
l->next = leaked;
leaked = l;
l->next = exited;
exited = l;
[gnustep_global_lock unlock];
return l->obj;
}
+ (id) leak: (id)anObject
{
struct leakLink *l;
struct exitLink *l;
l = (struct leakLink*)malloc(sizeof(struct leakLink));
l = (struct exitLink*)malloc(sizeof(struct exitLink));
l->at = 0;
l->obj = [anObject retain];
l->sel = 0;
[gnustep_global_lock lock];
l->next = leaked;
leaked = l;
l->next = exited;
exited = l;
[gnustep_global_lock unlock];
return l->obj;
}
+ (void) registerAtExit
+ (BOOL) registerAtExit
{
Method m = class_getClassMethod(self, @selector(atExit));
return [self registerAtExit: @selector(atExit)];
}
if (m != 0)
+ (BOOL) registerAtExit: (SEL)sel
{
Method m;
Class s;
struct exitLink *l;
if (0 == sel)
{
Class s = class_getSuperclass(self);
sel = @selector(atExit);
}
if (0 == s || class_getClassMethod(s, @selector(atExit)) != m)
m = class_getClassMethod(self, sel);
if (0 == m)
{
return NO; // method not implemented.
}
s = class_getSuperclass(self);
if (0 != s && class_getClassMethod(s, sel) == m)
{
return NO; // method not implemented in this class
}
[gnustep_global_lock lock];
for (l = exited; l != 0; l = l->next)
{
if (l->obj == self && sel_isEqual(l->sel, sel))
{
struct exitLink *l;
[gnustep_global_lock lock];
for (l = exited; l != 0; l = l->next)
{
if (l->cls == self)
{
[gnustep_global_lock unlock];
return; // Already registered
}
}
l = (struct exitLink*)malloc(sizeof(struct exitLink));
l->cls = self;
l->next = exited;
exited = l;
if (NO == enabled)
{
atexit(handleExit);
enabled = YES;
}
[gnustep_global_lock lock];
[gnustep_global_lock unlock];
return NO; // Already registered
}
}
l = (struct exitLink*)malloc(sizeof(struct exitLink));
l->obj = self;
l->sel = sel;
l->at = 0;
l->next = exited;
exited = l;
if (NO == enabled)
{
atexit(handleExit);
enabled = YES;
}
[gnustep_global_lock lock];
return YES;
}
+ (void) setShouldCleanUp: (BOOL)aFlag

View file

@ -136,7 +136,7 @@ static void GSMakeZombie(NSObject *o)
c = object_getClass(o);
object_setClass(o, zombieClass);
if (NSDeallocateZombies == NO)
if (0 != zombieMap)
{
[allocationLock lock];
NSMapInsert(zombieMap, (void*)o, (void*)c);
@ -149,7 +149,7 @@ static void GSLogZombie(id o, SEL sel)
{
Class c = 0;
if (NSDeallocateZombies == NO)
if (0 != zombieMap)
{
[allocationLock lock];
c = NSMapGet(zombieMap, (void*)o);
@ -1106,6 +1106,7 @@ objc_create_block_classes_as_subclasses_of(Class super);
if (YES == GSPrivateEnvironmentFlag("GNUSTEP_SHOULD_CLEAN_UP", NO))
{
[self setShouldCleanUp: YES];
[self registerAtExit: @selector(_atExit)];
}
/* Set up the autorelease system ... we must do this before using any
@ -1149,6 +1150,11 @@ objc_create_block_classes_as_subclasses_of(Class super);
return;
}
+ (void) _atExit
{
DESTROY(zombieMap);
}
/**
* Allocates a new instance of the receiver from the default
* zone, by invoking +allocWithZone: with
@ -2460,7 +2466,7 @@ objc_create_block_classes_as_subclasses_of(Class super);
}
- (Class) originalClass
{
return NSMapGet(zombieMap, (void*)self);
return zombieMap ? NSMapGet(zombieMap, (void*)self) : Nil;
}
- (void) forwardInvocation: (NSInvocation*)anInvocation
{
@ -2481,7 +2487,7 @@ objc_create_block_classes_as_subclasses_of(Class super);
return nil;
}
[allocationLock lock];
c = NSMapGet(zombieMap, (void*)self);
c = zombieMap ? NSMapGet(zombieMap, (void*)self) : Nil;
[allocationLock unlock];
return [c instanceMethodSignatureForSelector: aSelector];
}