Index: src/OFArray.h ================================================================== --- src/OFArray.h +++ src/OFArray.h @@ -68,11 +68,11 @@ - (void*)last; /** * Adds an item to the OFArray. * - * \param item An arbitrary item + * \param item A pointer to an arbitrary item */ - add: (void*)item; /** * Adds items from a C array to the OFArray. Index: src/OFAutoreleasePool.h ================================================================== --- src/OFAutoreleasePool.h +++ src/OFAutoreleasePool.h @@ -8,20 +8,22 @@ * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ #import "OFObject.h" +#import "OFArray.h" +#import "OFList.h" /** * The OFAutoreleasePool class provides a class that keeps track of objects * that will be released when the autorelease pool is released. * Every thread has its own stack of autorelease pools. */ @interface OFAutoreleasePool: OFObject { - OFObject **objects; - size_t size; + OFArray *objects; + of_list_object_t *listobj; } /** * Adds an object to the autorelease pool at the top of the thread-specific * stack. @@ -39,12 +41,7 @@ - addToPool: (OFObject*)obj; /** * Releases all objects in the autorelease pool. */ -- release; - -/** - * \returns All objects in the autorelease pool - */ -- (OFObject**)objects; +- releaseObjects; @end Index: src/OFAutoreleasePool.m ================================================================== --- src/OFAutoreleasePool.m +++ src/OFAutoreleasePool.m @@ -15,190 +15,122 @@ #import #endif #import "OFAutoreleasePool.h" #import "OFExceptions.h" +#import "OFList.h" #ifdef _WIN32 #import #endif #ifndef _WIN32 -static pthread_key_t pool_stack_key; -static pthread_key_t pool_index_key; +#define get_tls(t) pthread_getspecific(pool_list_key) +#define set_tls(t, v) pthread_setspecific(t, v) +static pthread_key_t pool_list_key; #else -static DWORD pool_stack_key; -static DWORD pool_index_key; +#define get_tls(t) TlsGetValue(t) +#define set_tls(t, v) TlsSetValue(t, v) +static DWORD pool_list_key; #endif #ifndef _WIN32 static void -free_each(void *ptr) -{ - OFAutoreleasePool **p; - OFObject **o; - - for (p = (OFAutoreleasePool**)ptr; *p != nil; p++) { - for (o = [*p objects]; *o != nil; o++) - [*o release]; - [*p free]; - } +release_obj(void *obj) +{ + [(OFObject*)obj release]; } #endif @implementation OFAutoreleasePool + (void)initialize { #ifndef _WIN32 - if (pthread_key_create(&pool_stack_key, free_each)) + if (pthread_key_create(&pool_list_key, release_obj)) @throw [OFInitializationFailedException newWithClass: self]; - if (pthread_key_create(&pool_index_key, free)) { - pthread_key_delete(pool_stack_key); - @throw [OFInitializationFailedException newWithClass: self]; - } #else /* FIXME: Free stuff when thread is terminated! */ - if ((pool_stack_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) + if ((pool_list_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) @throw [OFInitializationFailedException newWithClass: self]; - if ((pool_index_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) { - TlsFree(pool_stack_key); - @throw [OFInitializationFailedException newWithClass: self]; - } - #endif } + (void)addToPool: (OFObject*)obj { - OFAutoreleasePool **pool_stack; - int *pool_index; - -#ifndef _WIN32 - pool_stack = pthread_getspecific(pool_stack_key); - pool_index = pthread_getspecific(pool_index_key); -#else - pool_stack = TlsGetValue(pool_stack_key); - pool_index = TlsGetValue(pool_index_key); -#endif - - if (pool_stack == NULL || pool_index == NULL) { - [[self alloc] init]; - -#ifndef _WIN32 - pool_stack = pthread_getspecific(pool_stack_key); - pool_index = pthread_getspecific(pool_index_key); -#else - pool_stack = TlsGetValue(pool_stack_key); - pool_index = TlsGetValue(pool_index_key); -#endif - } - - if (*pool_stack == nil || *pool_index == -1) - @throw [OFInitializationFailedException newWithClass: self]; - - [pool_stack[*pool_index] addToPool: obj]; + OFList *pool_list = get_tls(pool_list_key); + + if (pool_list == nil) { + [[self alloc] init]; + pool_list = get_tls(pool_list_key); + } + + if (pool_list == nil || [pool_list last] == NULL) + @throw [OFInitializationFailedException newWithClass: self]; + + [[pool_list last]->object addToPool: obj]; } - init { - OFAutoreleasePool **pool_stack, **pool_stack2; - int *pool_index; - Class c; + OFList *pool_list; if ((self = [super init])) { - objects = NULL; - size = 0; - -#ifndef _WIN32 - pool_stack = pthread_getspecific(pool_stack_key); - pool_index = pthread_getspecific(pool_index_key); -#else - pool_stack = TlsGetValue(pool_stack_key); - pool_index = TlsGetValue(pool_index_key); -#endif - - if (pool_index == NULL) { - if ((pool_index = malloc(sizeof(int))) == NULL) { - c = [self class]; - [super free]; - @throw [OFNoMemException newWithClass: c]; - } - - *pool_index = -1; -#ifndef _WIN32 - pthread_setspecific(pool_index_key, pool_index); -#else - TlsSetValue(pool_index_key, pool_index); -#endif - } - - if ((pool_stack2 = realloc(pool_stack, - (*pool_index + 3) * sizeof(OFAutoreleasePool*))) == NULL) { - c = [self class]; - [super free]; - @throw [OFNoMemException newWithClass: c]; - } - pool_stack = pool_stack2; -#ifndef _WIN32 - pthread_setspecific(pool_stack_key, pool_stack); -#else - TlsSetValue(pool_stack_key, pool_stack); -#endif - (*pool_index)++; - - pool_stack[*pool_index] = self; - pool_stack[*pool_index + 1] = nil; + objects = nil; + + pool_list = get_tls(pool_list_key); + + if (pool_list == nil) { + pool_list = [[OFList alloc] + initWithRetainAndReleaseEnabled: NO]; + set_tls(pool_list_key, pool_list); + } + + listobj = [pool_list append: self]; } return self; } - free { - [self release]; + [(OFList*)get_tls(pool_list_key) remove: listobj]; return [super free]; } - addToPool: (OFObject*)obj { - OFObject **objects2; - size_t size2; - - size2 = size + 1; - - if (SIZE_MAX - size < 1 || size2 > SIZE_MAX / sizeof(OFObject*)) - @throw [OFOutOfRangeException newWithClass: [self class]]; - - if ((objects2 = realloc(objects, size2 * sizeof(OFObject*))) == NULL) - @throw [OFNoMemException newWithClass: [self class] - andSize: size2]; - - objects = objects2; - objects[size] = obj; - size = size2; + if (objects == nil) + objects = [OFArray newWithItemSize: sizeof(char*)]; + + [objects add: &obj]; return self; } - release { - size_t i; - - if (objects != NULL) { - for (i = 0; size < i; i++) - [objects[i] release]; - - free(objects); - } - - objects = NULL; - size = 0; + [self releaseObjects]; + + return [super release]; +} + +- releaseObjects +{ + size_t i, size; + IMP get_item; + + if (objects == nil) + return self; + + size = [objects items]; + get_item = [objects methodFor: @selector(item:)]; + + for (i = 0; i < size; i++) + [*((OFObject**)get_item(objects, @selector(item:), i)) release]; + + [objects release]; + objects = nil; return self; } - -- (OFObject**)objects -{ - return objects; -} @end Index: src/OFList.h ================================================================== --- src/OFList.h +++ src/OFList.h @@ -23,12 +23,22 @@ */ @interface OFList: OFObject { of_list_object_t *first; of_list_object_t *last; + BOOL retain_and_release; } +/** + * Initializes an already allocated OFList. + * + * \param enabled Whether release / retain should be called when an object is + * added / removed. Default: YES + * \return An initialized OFList + */ +- initWithRetainAndReleaseEnabled: (BOOL)enabled; + /** * \return The first object in the list */ - (of_list_object_t*)first; Index: src/OFList.m ================================================================== --- src/OFList.m +++ src/OFList.m @@ -16,11 +16,23 @@ @implementation OFList - init { if ((self = [super init])) { first = NULL; - last = NULL; + last = NULL; + retain_and_release = YES; + } + + return self; +} + +- initWithRetainAndReleaseEnabled: (BOOL)enabled +{ + if ((self = [super init])) { + first = NULL; + last = NULL; + retain_and_release = enabled; } return self; } @@ -57,11 +69,13 @@ last = o; if (first == NULL) first = o; - [obj retain]; + if (retain_and_release) + [obj retain]; + return o; } - (of_list_object_t*)prepend: (id)obj { @@ -76,11 +90,13 @@ first = o; if (last == NULL) last = o; - [obj retain]; + if (retain_and_release) + [obj retain]; + return o; } - (of_list_object_t*)insert: (id)obj before: (of_list_object_t*)listobj @@ -97,11 +113,13 @@ listobj->prev = o; if (listobj == first) first = o; - [obj retain]; + if (retain_and_release) + [obj retain]; + return o; } - (of_list_object_t*)insert: (id)obj after: (of_list_object_t*)listobj @@ -118,11 +136,13 @@ listobj->next = o; if (listobj == last) last = o; - [obj retain]; + if (retain_and_release) + [obj retain]; + return o; } - remove: (of_list_object_t*)listobj { @@ -134,9 +154,13 @@ if (first == listobj) first = listobj->next; if (last == listobj) last = listobj->prev; + if (retain_and_release) + [listobj->object release]; + [self freeMem: listobj]; + return self; } @end Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -44,10 +44,15 @@ /** * Adds the object to the autorelease pool that is on top of the thread's stack. */ - autorelease; +/** + * \return The retain count + */ +- (size_t)retainCount; + /** * Adds a pointer to the memory pool. * This is useful to add memory allocated by functions such as asprintf to the * pool so it gets freed automatically when the object is freed. * Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -64,10 +64,15 @@ { [OFAutoreleasePool addToPool: self]; return self; } + +- (size_t)retainCount +{ + return __retain_count; +} - addToMemoryPool: (void*)ptr { void **memchunks; size_t memchunks_size; Index: tests/OFArray/OFArray.m ================================================================== --- tests/OFArray/OFArray.m +++ tests/OFArray/OFArray.m @@ -97,11 +97,11 @@ \ puts("Creating new array and using it to build a string..."); \ a = [type newWithItemSize: 1]; \ \ for (i = 0; i < strlen(str); i++) \ - [a add: (void*)(str + i)]; \ + [a add: (void*)&str[i]]; \ [a add: ""]; \ \ if (!strcmp([a data], str)) \ puts("Built string matches!"); \ else { \ Index: tests/OFAutoreleasePool/OFAutoreleasePool.m ================================================================== --- tests/OFAutoreleasePool/OFAutoreleasePool.m +++ tests/OFAutoreleasePool/OFAutoreleasePool.m @@ -11,23 +11,67 @@ #import "config.h" #import "OFAutoreleasePool.h" -/* FIXME: Just crashtests */ +#import + +#ifndef _WIN32 +#define ZD "%zd" +#else +#define ZD "%u" +#endif + +@interface TestObject: OFObject +- init; +- retain; +- release; +@end + +@implementation TestObject +- init +{ + id ret; + + ret = [super init]; + printf("New %s with retain cnt " ZD "\n", [self name], + [ret retainCount]); + + return ret; +} + +- retain +{ + id ret; + + ret = [super retain]; + printf("Retaining %s to " ZD "\n", [self name], [ret retainCount]); + + return ret; +} + +- release +{ + printf("Releasing %s to " ZD "\n", [self name], [self retainCount] - 1); + + return [super release]; +} +@end int main() { + [TestObject poseAs: [OFObject class]]; + OFObject *o1, *o2, *o3; OFAutoreleasePool *pool1, *pool2; o1 = [[OFObject new] autorelease]; pool1 = [OFAutoreleasePool new]; o2 = [[OFObject new] autorelease]; - [pool1 release]; + [pool1 releaseObjects]; o2 = [[OFObject new] autorelease]; pool2 = [OFAutoreleasePool new]; o3 = [[OFObject new] autorelease];