Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -448,10 +448,27 @@ AC_DEFINE(OF_THREADS, 1, [Whether we have threads]) AC_SUBST(OFTHREAD_M, "OFThread.m") AC_SUBST(OFTHREADTESTS_M, "OFThreadTests.m") AC_SUBST(OFHTTPREQUESTTESTS_M, "OFHTTPRequestTests.m") AC_SUBST(THREADING_H, "threading.h") + + AC_MSG_CHECKING(whether __thread works) + AC_TRY_LINK([ + /* It seems __thread is buggy with GCC 4.1 */ + #if __GNUC__ == 4 && __GNUC_MINOR__ < 2 + # error buggy + #endif + + __thread int x = 0; + ], [ + x++; + ], [ + AC_MSG_RESULT(yes) + AC_DEFINE(OF_COMPILER_TLS, 1, [Whether __thread works]) + ], [ + AC_MSG_RESULT(no) + ]) atomic_ops="none" AC_MSG_CHECKING(whether we have an atomic ops assembly implementation) AC_EGREP_CPP(yes, [ Index: src/OFAutoreleasePool.m ================================================================== --- src/OFAutoreleasePool.m +++ src/OFAutoreleasePool.m @@ -15,45 +15,87 @@ */ #include "config.h" #include + +#include #import "OFAutoreleasePool.h" #import "OFArray.h" + +#ifndef OF_COMPILER_TLS +# import "threading.h" + +# import "OFInitializationFailedException.h" +#endif #import "OFNotImplementedException.h" extern id _objc_rootAutorelease(id); extern void* objc_autoreleasePoolPush(void); extern void objc_autoreleasePoolPop(void*); +#ifdef OF_COMPILER_TLS static __thread void *first = NULL; +#else +static of_tlskey_t firstKey; +#endif @implementation OFAutoreleasePool +#ifndef OF_COMPILER_TLS ++ (void)initialize +{ + if (self != [OFAutoreleasePool class]) + return; + + if (!of_tlskey_new(&firstKey)) + @throw [OFInitializationFailedException + exceptionWithClass: self]; +} +#endif + + (id)addObject: (id)object { +#ifndef OF_COMPILER_TLS + void *first = of_tlskey_get(firstKey); +#endif + if (first == NULL) [[OFAutoreleasePool alloc] init]; return _objc_rootAutorelease(object); } + (void)_releaseAll { +#ifndef OF_COMPILER_TLS + void *first = of_tlskey_get(firstKey); +#endif + objc_autoreleasePoolPop(first); } - init { self = [super init]; @try { +#ifndef OF_COMPILER_TLS + void *first = of_tlskey_get(firstKey); +#endif + pool = objc_autoreleasePoolPush(); if (first == NULL) +#ifdef OF_COMPILER_TLS first = pool; +#else + if (!of_tlskey_set(firstKey, pool)) + @throw [OFInitializationFailedException + exceptionWithClass: [self class]]; +#endif _objc_rootAutorelease(self); } @catch (id e) { [self release]; @throw e; @@ -89,12 +131,17 @@ if (ignoreRelease) return; ignoreRelease = YES; +#ifdef OF_COMPILER_TLS if (first == pool) first = NULL; +#else + if (of_tlskey_get(firstKey) == pool) + assert(of_tlskey_set(firstKey, NULL)); +#endif objc_autoreleasePoolPop(pool); [super dealloc]; } Index: src/objfw-defs.h.in ================================================================== --- src/objfw-defs.h.in +++ src/objfw-defs.h.in @@ -1,8 +1,9 @@ #undef OF_APPLE_RUNTIME #undef OF_ATOMIC_OPS #undef OF_BIG_ENDIAN +#undef OF_COMPILER_TLS #undef OF_FLOAT_BIG_ENDIAN #undef OF_HAVE_ASPRINTF #undef OF_HAVE_BLOCKS #undef OF_HAVE_FAST_ENUMERATION #undef OF_HAVE_GCC_ATOMIC_OPS Index: src/runtime/autorelease.m ================================================================== --- src/runtime/autorelease.m +++ src/runtime/autorelease.m @@ -22,15 +22,30 @@ #import "runtime.h" #import "runtime-private.h" #import "OFObject.h" +#ifndef OF_COMPILER_TLS +# import "threading.h" +#endif #import "macros.h" +#ifdef OF_COMPILER_TLS static __thread id *objects = NULL; static __thread id *top = NULL; static __thread size_t size = 0; +#else +static of_tlskey_t objectsKey, topKey, sizeKey; + +static void __attribute__((constructor)) +init(void) +{ + if (!of_tlskey_new(&objectsKey) || !of_tlskey_new(&sizeKey) || + !of_tlskey_new(&topKey)) + ERROR("Unable to create TLS key for autorelease pools!") +} +#endif id objc_autorelease(id object) { return [object autorelease]; @@ -37,33 +52,59 @@ } void* objc_autoreleasePoolPush() { +#ifndef OF_COMPILER_TLS + id *top = of_tlskey_get(topKey); + id *objects = of_tlskey_get(objectsKey); +#endif ptrdiff_t offset = top - objects; return (void*)offset; } void objc_autoreleasePoolPop(void *offset) { +#ifndef OF_COMPILER_TLS + id *top = of_tlskey_get(topKey); + id *objects = of_tlskey_get(objectsKey); +#endif id *pool = objects + (ptrdiff_t)offset; id *iter; for (iter = pool; iter < top; iter++) [*iter release]; +#ifdef OF_COMPILER_TLS top = pool; +#else + if (!of_tlskey_set(topKey, pool)) + ERROR("Failed to set TLS key!") +#endif } id _objc_rootAutorelease(id object) { +#ifndef OF_COMPILER_TLS + id *top = of_tlskey_get(topKey); + id *objects = of_tlskey_get(objectsKey); + size_t size = (size_t)(uintptr_t)of_tlskey_get(sizeKey); +#endif + if (objects == NULL) { if ((objects = malloc(of_pagesize)) == NULL) ERROR("Out of memory for autorelease pools!") + +#ifndef OF_COMPILER_TLS + if (!of_tlskey_set(objectsKey, objects)) + ERROR("Failed to set TLS key!") + if (!of_tlskey_set(sizeKey, (void*)(uintptr_t)of_pagesize)) + ERROR("Failed to set TLS key!") +#endif top = objects; } if ((uintptr_t)top >= (uintptr_t)objects + size) { @@ -70,14 +111,26 @@ ptrdiff_t diff = top - objects; size += of_pagesize; if ((objects = realloc(objects, size)) == NULL) ERROR("Out of memory for autorelease pools!") + +#ifndef OF_COMPILER_TLS + if (!of_tlskey_set(objectsKey, objects)) + ERROR("Failed to set TLS key!") + if (!of_tlskey_set(sizeKey, (void*)(uintptr_t)size)) + ERROR("Failed to set TLS key!") +#endif top = objects + diff; } *top = object; top++; + +#ifndef OF_COMPILER_TLS + if (!of_tlskey_set(topKey, objects)) + ERROR("Failed to set TLS key!") +#endif return object; }