mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 16:50:58 +00:00
atexit improvements
This commit is contained in:
parent
e64b7dc6b3
commit
dd3367de3b
4 changed files with 86 additions and 42 deletions
|
@ -212,46 +212,49 @@ extern "C" {
|
||||||
+ (void) atExit;
|
+ (void) atExit;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/** Category for methods handling leaked memory cleanup on exit of process
|
/** Category for methods handling leaked memory clean-up on exit of process
|
||||||
* (for use when debugging memory leaks).<br />
|
* (for use when debugging memory leaks).<br />
|
||||||
* You enable this by calling the +setShouldCleanUp: method (done implicitly
|
* You enable this by calling the +setShouldCleanUp: method (done implicitly
|
||||||
* by gnustep-base if the GNUSTEP_SHOULD_CLEAN_UP environment variable is
|
* by gnustep-base if the GNUSTEP_SHOULD_CLEAN_UP environment variable is
|
||||||
* set to YES).<br />
|
* set to YES).<br />
|
||||||
* Your class then has two options for performing cleanup when the process
|
* Your class then has two options for performing clean-up when the process
|
||||||
* ends:
|
* ends:
|
||||||
* <p>1. Use the +leak: method to register objects which are simply to be
|
* <p>1. Use the +leaked: method to register objects which are simply to be
|
||||||
* retained until the process ends, and then either ignored or released
|
* retained until the process ends, and then either ignored or released
|
||||||
* depending on the cleanup setting in force. This mechanism is simple
|
* depending on the clean-up setting in force. This mechanism is simple
|
||||||
* and should be sufficient for many classes.
|
* and should be sufficient for many classes.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>2. Implement a +atExit method to be run when the process ends and,
|
* <p>2. Implement a +atExit method to be run when the process ends and,
|
||||||
* within your +initialize implementation, call +shouldCleanUp to determine
|
* within your +initialize implementation, call +shouldCleanUp to determine
|
||||||
* whether cleanup should be done, and if it returns YES then call
|
* whether clean-up should be done, and if it returns YES then call
|
||||||
* +registerAtExit to have your +atExit method called when the process
|
* +registerAtExit to have your +atExit method called when the process
|
||||||
* terminates.
|
* terminates.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>The order in which 'leaked' objects are released and +atExit methods
|
* <p>The order in which 'leaked' objects are released and +atExit methods
|
||||||
* are called on process exist is the reverse of the order in which they
|
* are called on process exist is the reverse of the order in which they
|
||||||
* werse set up suing this API.
|
* werse set up using this API.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
@interface NSObject(GSCleanup)
|
@interface NSObject(GSCleanUp)
|
||||||
|
|
||||||
|
/** Returns YES if the process is exiting (and perhaps performing clean-up).
|
||||||
/** This method simply retains its argument so that it will never be
|
|
||||||
* deallocated during normal operation, but keeps track of it so that
|
|
||||||
* it is released during process exit if cleanup is enabled.<br />
|
|
||||||
* Returns its argument.
|
|
||||||
*/
|
*/
|
||||||
+ (id) NS_RETURNS_RETAINED leak: (id)anObject;
|
+ (BOOL) isExiting;
|
||||||
|
|
||||||
/** This method retains the object at *anAddress so that it will never be
|
/** This method informs the system that the object at anAddress has been
|
||||||
* deallocated during normal operation, but keeps track of the address
|
* intentionally leaked (will not be deallocated by higher level code)
|
||||||
* so that the object is released and the address is zeroed during process
|
* and should be cleaned up at process exit (and the address content
|
||||||
* exit if cleanup is enabled.<br />
|
* zeroed out) if clean-up is enabled.
|
||||||
* Returns the object at *anAddress.
|
|
||||||
*/
|
*/
|
||||||
+ (id) NS_RETURNS_RETAINED leakAt: (id*)anAddress;
|
+ (void) leaked: (id*)anAddress;
|
||||||
|
|
||||||
|
/** Deprecated: use +leaked: instead.
|
||||||
|
*/
|
||||||
|
+ (id) NS_RETURNS_RETAINED leak: (id)anObject ;//GS_DEPRECATED_FUNC;
|
||||||
|
|
||||||
|
/** Deprecated: use +leaked: instead.
|
||||||
|
*/
|
||||||
|
+ (id) NS_RETURNS_RETAINED leakAt: (id*)anAddress ;//GS_DEPRECATED_FUNC;
|
||||||
|
|
||||||
/** Sets the receiver to have its +atExit method called at the point when
|
/** Sets the receiver to have its +atExit method called at the point when
|
||||||
* the process terminates.<br />
|
* the process terminates.<br />
|
||||||
|
@ -269,10 +272,10 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
+ (BOOL) registerAtExit: (SEL)aSelector;
|
+ (BOOL) registerAtExit: (SEL)aSelector;
|
||||||
|
|
||||||
/** Specifies the default cleanup behavior on process exit ... the value
|
/** Specifies the default clean-up behavior on process exit ... the value
|
||||||
* returned by the NSObject implementation of the +shouldCleanUp method.<br />
|
* returned by the NSObject implementation of the +shouldCleanUp method.<br />
|
||||||
* Calling this method with a YES argument implicitly enables the support for
|
* Calling this method with a YES argument implicitly enables the support for
|
||||||
* cleanup at exit.<br />
|
* clean-up at exit.<br />
|
||||||
* The GNUstep Base library calls this method with the value obtained from
|
* The GNUstep Base library calls this method with the value obtained from
|
||||||
* the GNUSTEP_SHOULD_CLEAN_UP environment variable when NSObject is
|
* the GNUSTEP_SHOULD_CLEAN_UP environment variable when NSObject is
|
||||||
* initialised.
|
* initialised.
|
||||||
|
|
|
@ -156,6 +156,7 @@ struct exitLink {
|
||||||
static struct exitLink *exited = 0;
|
static struct exitLink *exited = 0;
|
||||||
static BOOL enabled = NO;
|
static BOOL enabled = NO;
|
||||||
static BOOL shouldCleanUp = NO;
|
static BOOL shouldCleanUp = NO;
|
||||||
|
static BOOL isExiting = NO;
|
||||||
static NSLock *exitLock = nil;
|
static NSLock *exitLock = nil;
|
||||||
|
|
||||||
static inline void setup()
|
static inline void setup()
|
||||||
|
@ -176,7 +177,10 @@ static inline void setup()
|
||||||
static void
|
static void
|
||||||
handleExit()
|
handleExit()
|
||||||
{
|
{
|
||||||
BOOL unknownThread = GSRegisterCurrentThread();
|
BOOL unknownThread;
|
||||||
|
|
||||||
|
isExiting = YES;
|
||||||
|
unknownThread = GSRegisterCurrentThread();
|
||||||
CREATE_AUTORELEASE_POOL(arp);
|
CREATE_AUTORELEASE_POOL(arp);
|
||||||
|
|
||||||
while (exited != 0)
|
while (exited != 0)
|
||||||
|
@ -212,9 +216,32 @@ handleExit()
|
||||||
{
|
{
|
||||||
GSUnregisterCurrentThread();
|
GSUnregisterCurrentThread();
|
||||||
}
|
}
|
||||||
|
isExiting = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation NSObject(GSCleanup)
|
@implementation NSObject(GSCleanUp)
|
||||||
|
|
||||||
|
+ (BOOL) isExiting
|
||||||
|
{
|
||||||
|
return isExiting;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (void) leaked: (id*)anAddress
|
||||||
|
{
|
||||||
|
struct exitLink *l;
|
||||||
|
|
||||||
|
NSAssert(*anAddress && [*anAddress isKindOfClass: [NSObject class]],
|
||||||
|
NSInvalidArgumentException);
|
||||||
|
l = (struct exitLink*)malloc(sizeof(struct exitLink));
|
||||||
|
l->at = anAddress;
|
||||||
|
l->obj = *anAddress;
|
||||||
|
l->sel = 0;
|
||||||
|
setup();
|
||||||
|
[exitLock lock];
|
||||||
|
l->next = exited;
|
||||||
|
exited = l;
|
||||||
|
[exitLock unlock];
|
||||||
|
}
|
||||||
|
|
||||||
+ (id) leakAt: (id*)anAddress
|
+ (id) leakAt: (id*)anAddress
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,7 +105,15 @@ static SEL rlSel;
|
||||||
|
|
||||||
+ (void) atExit
|
+ (void) atExit
|
||||||
{
|
{
|
||||||
DESTROY(defaultPlaceholderArray);
|
id o;
|
||||||
|
|
||||||
|
/* The default placeholder array overrides -dealloc so we must get rid of
|
||||||
|
* it directly.
|
||||||
|
*/
|
||||||
|
o = defaultPlaceholderArray;
|
||||||
|
defaultPlaceholderArray = nil;
|
||||||
|
NSDeallocateObject(o);
|
||||||
|
|
||||||
DESTROY(placeholderMap);
|
DESTROY(placeholderMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,9 +166,13 @@ static NSMapTable *placeholderMap;
|
||||||
static gs_mutex_t placeholderLock = GS_MUTEX_INIT_STATIC;
|
static gs_mutex_t placeholderLock = GS_MUTEX_INIT_STATIC;
|
||||||
|
|
||||||
|
|
||||||
static SEL cMemberSel = 0;
|
static SEL cMemberSel = 0;
|
||||||
static NSCharacterSet *nonBase = nil;
|
static NSCharacterSet *nonBase = nil;
|
||||||
static BOOL (*nonBaseImp)(id, SEL, unichar) = 0;
|
static BOOL (*nonBaseImp)(id, SEL, unichar) = 0;
|
||||||
|
|
||||||
|
static NSCharacterSet *wPathSeps = nil;
|
||||||
|
static NSCharacterSet *uPathSeps = nil;
|
||||||
|
static NSCharacterSet *rPathSeps = nil;
|
||||||
|
|
||||||
/* Macro to return the receiver if it is already immutable, but an
|
/* Macro to return the receiver if it is already immutable, but an
|
||||||
* autoreleased copy otherwise. Used where we have to return an
|
* autoreleased copy otherwise. Used where we have to return an
|
||||||
|
@ -308,9 +312,6 @@ GSPathHandling(const char *mode)
|
||||||
static NSCharacterSet*
|
static NSCharacterSet*
|
||||||
pathSeps(void)
|
pathSeps(void)
|
||||||
{
|
{
|
||||||
static NSCharacterSet *wPathSeps = nil;
|
|
||||||
static NSCharacterSet *uPathSeps = nil;
|
|
||||||
static NSCharacterSet *rPathSeps = nil;
|
|
||||||
if (GSPathHandlingRight())
|
if (GSPathHandlingRight())
|
||||||
{
|
{
|
||||||
if (rPathSeps == nil)
|
if (rPathSeps == nil)
|
||||||
|
@ -318,9 +319,8 @@ pathSeps(void)
|
||||||
GS_MUTEX_LOCK(placeholderLock);
|
GS_MUTEX_LOCK(placeholderLock);
|
||||||
if (rPathSeps == nil)
|
if (rPathSeps == nil)
|
||||||
{
|
{
|
||||||
rPathSeps
|
rPathSeps = RETAIN([NSCharacterSet
|
||||||
= [NSCharacterSet characterSetWithCharactersInString: @"/\\"];
|
characterSetWithCharactersInString: @"/\\"]);
|
||||||
rPathSeps = [NSObject leakAt: &rPathSeps];
|
|
||||||
}
|
}
|
||||||
GS_MUTEX_UNLOCK(placeholderLock);
|
GS_MUTEX_UNLOCK(placeholderLock);
|
||||||
}
|
}
|
||||||
|
@ -333,9 +333,8 @@ pathSeps(void)
|
||||||
GS_MUTEX_LOCK(placeholderLock);
|
GS_MUTEX_LOCK(placeholderLock);
|
||||||
if (uPathSeps == nil)
|
if (uPathSeps == nil)
|
||||||
{
|
{
|
||||||
uPathSeps
|
uPathSeps = RETAIN([NSCharacterSet
|
||||||
= [NSCharacterSet characterSetWithCharactersInString: @"/"];
|
characterSetWithCharactersInString: @"/"]);
|
||||||
uPathSeps = [NSObject leakAt: &uPathSeps];
|
|
||||||
}
|
}
|
||||||
GS_MUTEX_UNLOCK(placeholderLock);
|
GS_MUTEX_UNLOCK(placeholderLock);
|
||||||
}
|
}
|
||||||
|
@ -348,9 +347,8 @@ pathSeps(void)
|
||||||
GS_MUTEX_LOCK(placeholderLock);
|
GS_MUTEX_LOCK(placeholderLock);
|
||||||
if (wPathSeps == nil)
|
if (wPathSeps == nil)
|
||||||
{
|
{
|
||||||
wPathSeps
|
wPathSeps = RETAIN([NSCharacterSet
|
||||||
= [NSCharacterSet characterSetWithCharactersInString: @"\\"];
|
characterSetWithCharactersInString: @"\\"]);
|
||||||
wPathSeps = [NSObject leakAt: &wPathSeps];
|
|
||||||
}
|
}
|
||||||
GS_MUTEX_UNLOCK(placeholderLock);
|
GS_MUTEX_UNLOCK(placeholderLock);
|
||||||
}
|
}
|
||||||
|
@ -881,6 +879,10 @@ register_printf_atsign ()
|
||||||
+ (void) atExit
|
+ (void) atExit
|
||||||
{
|
{
|
||||||
DESTROY(placeholderMap);
|
DESTROY(placeholderMap);
|
||||||
|
DESTROY(nonBase);
|
||||||
|
DESTROY(rPathSeps);
|
||||||
|
DESTROY(uPathSeps);
|
||||||
|
DESTROY(wPathSeps);
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void) initialize
|
+ (void) initialize
|
||||||
|
@ -900,7 +902,6 @@ register_printf_atsign ()
|
||||||
ranSel = @selector(rangeOfComposedCharacterSequenceAtIndex:);
|
ranSel = @selector(rangeOfComposedCharacterSequenceAtIndex:);
|
||||||
|
|
||||||
nonBase = [NSCharacterSet nonBaseCharacterSet];
|
nonBase = [NSCharacterSet nonBaseCharacterSet];
|
||||||
nonBase = [NSObject leakAt: &nonBase];
|
|
||||||
nonBaseImp
|
nonBaseImp
|
||||||
= (BOOL(*)(id,SEL,unichar))[nonBase methodForSelector: cMemberSel];
|
= (BOOL(*)(id,SEL,unichar))[nonBase methodForSelector: cMemberSel];
|
||||||
|
|
||||||
|
@ -3951,9 +3952,13 @@ register_printf_atsign ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
BOOL result;
|
||||||
|
|
||||||
|
ENTER_POOL
|
||||||
NSData *d = [self dataUsingEncoding: encoding];
|
NSData *d = [self dataUsingEncoding: encoding];
|
||||||
unsigned length = [d length];
|
unsigned length = [d length];
|
||||||
BOOL result = (length < maxLength) ? YES : NO;
|
|
||||||
|
result = (length < maxLength) ? YES : NO;
|
||||||
|
|
||||||
if (d == nil)
|
if (d == nil)
|
||||||
{
|
{
|
||||||
|
@ -3966,6 +3971,7 @@ register_printf_atsign ()
|
||||||
}
|
}
|
||||||
memcpy(buffer, [d bytes], length);
|
memcpy(buffer, [d bytes], length);
|
||||||
buffer[length] = '\0';
|
buffer[length] = '\0';
|
||||||
|
LEAVE_POOL
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4279,7 +4285,7 @@ register_printf_atsign ()
|
||||||
if (GSFromUnicode(&b, &l, u, len, encoding, NSDefaultMallocZone(),
|
if (GSFromUnicode(&b, &l, u, len, encoding, NSDefaultMallocZone(),
|
||||||
options) == YES)
|
options) == YES)
|
||||||
{
|
{
|
||||||
d = [NSDataClass dataWithBytesNoCopy: b length: l];
|
d = [NSDataClass dataWithBytesNoCopy: b length: l freeWhenDone: YES];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue