Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -15,10 +15,36 @@ #include #endif #import "OFObject.h" +/** + * A Thread Local Storage key. + */ +@interface OFTLSKey: OFObject +{ +@public +#ifndef _WIN32 + pthread_key_t key; +#else + DWORD key; +#endif +} + +/** + * \param destructor A destructor that is called when the thread is terminated + * \return A new autoreleased Thread Local Storage key + */ ++ tlsKeyWithDestructor: (void(*)(void*))destructor; + +/** + * \param destructor A destructor that is called when the thread is terminated + * \return An initialized Thread Local Storage key + */ +- initWithDestructor: (void(*)(void*))destructor; +@end + /** * The OFThread class provides portable threads. * * To use it, you should create a new class derived from it and reimplement * main. @@ -40,10 +66,30 @@ * \param obj An object that is passed to the main method * \return A new, autoreleased thread */ + threadWithObject: (id)obj; +/** + * Sets the Thread Local Storage for the specified key. + * + * The specified object is first retained and then the object stored before is + * released. You can specify nil as object if you want the old object to be + * released and don't want any new object for the TLS key. + * + * \param key The Thread Local Storage key + * \param obj The object the Thread Local Storage key will be set to + */ ++ setObject: (id)obj + forTLSKey: (OFTLSKey*)key; + +/** + * Returns the object for the specified Thread Local Storage key. + * + * \param key The Thread Local Storage key + */ ++ (id)objectForTLSKey: (OFTLSKey*)key; + /** * \param obj An object that is passed to the main method * \return An initialized OFThread. */ - initWithObject: (id)obj; Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -42,10 +42,59 @@ * If OFThread instead of self would be used here, the reimplemented * main would never be called. */ return [[[self alloc] initWithObject: obj] autorelease]; } + ++ setObject: (id)obj + forTLSKey: (OFTLSKey*)key +{ + id old; + + @try { + old = [self objectForTLSKey: key]; + } @catch (OFNotInSetException *e) { + [e free]; + old = nil; + } + +#ifndef _WIN32 + if (pthread_setspecific(key->key, obj)) +#else + if (!TlsSetValue(key->key, obj)) +#endif + /* FIXME: Maybe another exception would be better */ + @throw [OFNotInSetException newWithClass: self]; + + if (obj != nil) + [obj retain]; + if (old != nil) + [old release]; + + return self; +} + ++ (id)objectForTLSKey: (OFTLSKey*)key +{ + void *ret; + +#ifndef _WIN32 + ret = pthread_getspecific(key->key); +#else + ret = TlsGetValue(key->key); +#endif + + /* + * NULL and nil might be different on some platforms. NULL is returned + * if the key is missing, nil can be returned if it was explicitly set + * to nil to release the old object. + */ + if (ret == NULL || (id)ret == nil) + @throw [OFNotInSetException newWithClass: self]; + + return (id)ret; +} - initWithObject: (id)obj { Class c; @@ -111,5 +160,32 @@ #endif return [super free]; } @end + +@implementation OFTLSKey ++ tlsKeyWithDestructor: (void(*)(void*))destructor +{ + return [[[OFTLSKey alloc] initWithDestructor: destructor] autorelease]; +} + +- initWithDestructor: (void(*)(void*))destructor +{ + Class c; + + self = [super init]; + + /* FIXME: Call destructor on Win32 */ +#ifndef _WIN32 + if (pthread_key_create(&key, destructor)) { +#else + if ((key = TlsAlloc()) == TLS_OUT_OF_INDEXES) { +#endif + c = isa; + [super free]; + @throw [OFInitializationFailedException newWithClass: c]; + } + + return self; +} +@end