Index: src/OFAutoreleasePool.h ================================================================== --- src/OFAutoreleasePool.h +++ src/OFAutoreleasePool.h @@ -29,10 +29,12 @@ * stack. * * \param obj The object to add to the autorelease pool */ + (void)addObjectToTopmostPool: (OFObject*)obj; + ++ (void)releaseAll; /** * Adds an object to the specific autorelease pool. * * \param obj The object to add to the autorelease pool Index: src/OFAutoreleasePool.m ================================================================== --- src/OFAutoreleasePool.m +++ src/OFAutoreleasePool.m @@ -18,31 +18,19 @@ #import "OFThread.h" #import "OFExceptions.h" #import "threading.h" -/* - * Pay special attention to NULL and nil in this file, they might be different! - * Use NULL for TLS values and nil for instance variables. - */ - static of_tlskey_t first_key, last_key; -static void -release_all(id obj) -{ - [of_tlskey_get(first_key) release]; -} - @implementation OFAutoreleasePool + (void)initialize { if (self != [OFAutoreleasePool class]) return; - if (!of_tlskey_new(&first_key, release_all) || - !of_tlskey_new(&last_key, NULL)) + if (!of_tlskey_new(&first_key) || !of_tlskey_new(&last_key)) @throw [OFInitializationFailedException newWithClass: self]; } + (void)addObjectToTopmostPool: (OFObject*)obj { @@ -69,10 +57,15 @@ } @catch (OFException *e) { [obj release]; @throw e; } } + ++ (void)releaseAll +{ + [of_tlskey_get(first_key) release]; +} - init { id first; Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -8,10 +8,11 @@ * Q Public License 1.0, which can be found in the file LICENSE included in * the packaging of this file. */ #import "OFObject.h" +#import "OFList.h" #import "threading.h" /** * A Thread Local Storage key. @@ -18,10 +19,13 @@ */ @interface OFTLSKey: OFObject { @public of_tlskey_t key; +@protected + void (*destructor)(id); + of_list_object_t *listobj; } /** * \return A new autoreleased Thread Local Storage key */ @@ -30,10 +34,12 @@ /** * \param destructor A destructor that is called when the thread is terminated * \return A new autoreleased Thread Local Storage key */ + tlsKeyWithDestructor: (void(*)(id))destructor; + ++ (void)callAllDestructors; /** * \return An initialized Thread Local Storage key */ - init; Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -10,13 +10,17 @@ */ #include "config.h" #import "OFThread.h" +#import "OFList.h" +#import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "threading.h" + +static OFList *tlskeys; static id call_main(id obj) { /* @@ -23,10 +27,13 @@ * Nasty workaround for thread implementations which can't return a * value on join. */ ((OFThread*)obj)->retval = [obj main]; + [OFTLSKey callAllDestructors]; + [OFAutoreleasePool releaseAll]; + return 0; } @implementation OFThread + threadWithObject: (id)obj @@ -104,49 +111,80 @@ [super dealloc]; } @end @implementation OFTLSKey ++ (void)initialize +{ + if (self == [OFTLSKey class]) + tlskeys = [[OFList alloc] init]; +} + + tlsKey { return [[[self alloc] init] autorelease]; } + tlsKeyWithDestructor: (void(*)(id))destructor { return [[[self alloc] initWithDestructor: destructor] autorelease]; } + ++ (void)callAllDestructors +{ + of_list_object_t *iter; + + @synchronized (tlskeys) { + for (iter = [tlskeys first]; iter != NULL; iter = iter->next) + ((OFTLSKey*)iter->object)->destructor(iter->object); + } +} - init { self = [super init]; - if (!of_tlskey_new(&key, NULL)) { + if (!of_tlskey_new(&key)) { Class c = isa; [super dealloc]; @throw [OFInitializationFailedException newWithClass: c]; } + + destructor = NULL; + + @synchronized (tlskeys) { + @try { + listobj = [tlskeys append: self]; + } @catch (OFException *e) { + listobj = NULL; + [self dealloc]; + @throw e; + } + } return self; } -- initWithDestructor: (void(*)(id))destructor -{ - self = [super init]; - - if (!of_tlskey_new(&key, destructor)) { - Class c = isa; - [super dealloc]; - @throw [OFInitializationFailedException newWithClass: c]; - } +- initWithDestructor: (void(*)(id))destructor_ +{ + self = [self init]; + + destructor = destructor_; return self; } - (void)dealloc { + if (destructor != NULL) + destructor(self); + of_tlskey_free(key); + + @synchronized (tlskeys) { + [tlskeys remove: listobj]; + } [super dealloc]; } @end Index: src/threading.h ================================================================== --- src/threading.h +++ src/threading.h @@ -123,16 +123,15 @@ return YES; #endif } static OF_INLINE BOOL -of_tlskey_new(of_tlskey_t *key, void (*destructor)(id)) +of_tlskey_new(of_tlskey_t *key) { #ifndef _WIN32 - return (pthread_key_create(key, (void(*)(void*))destructor) ? NO : YES); + return (pthread_key_create(key, NULL) ? NO : YES); #else - /* FIXME: Call destructor */ return ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES ? NO : YES); #endif } static OF_INLINE id