Index: src/OFThread.h ================================================================== --- src/OFThread.h +++ src/OFThread.h @@ -283,10 +283,20 @@ * \brief Unlocks the mutex. */ - (void)unlock; @end +/** + * \brief A class for creating mutual exclusions which can be entered + * recursively. + */ +@interface OFRecursiveMutex: OFMutex +{ + of_rmutex_t rmutex; +} +@end + /** * \brief A class implementing a condition variable for thread synchronization. */ @interface OFCondition: OFMutex { Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -417,10 +417,15 @@ initialized = YES; return self; } + +- _initWithoutCreatingMutex +{ + return [super init]; +} - (void)lock { if (!of_mutex_lock(&mutex)) @throw [OFMutexLockFailedException @@ -443,10 +448,59 @@ - (void)dealloc { if (initialized) if (!of_mutex_free(&mutex)) + @throw [OFMutexStillLockedException + exceptionWithClass: [self class] + mutex: self]; + + [super dealloc]; +} +@end + +@implementation OFRecursiveMutex +- init +{ + self = [super _initWithoutCreatingMutex]; + + if (!of_rmutex_new(&rmutex)) { + Class c = [self class]; + [self release]; + @throw [OFInitializationFailedException exceptionWithClass: c]; + } + + initialized = YES; + + return self; +} + +- (void)lock +{ + if (!of_rmutex_lock(&rmutex)) + @throw [OFMutexLockFailedException + exceptionWithClass: [self class] + mutex: self]; +} + +- (BOOL)tryLock +{ + return of_rmutex_trylock(&rmutex); +} + +- (void)unlock +{ + if (!of_rmutex_unlock(&rmutex)) + @throw [OFMutexUnlockFailedException + exceptionWithClass: [self class] + mutex: self]; +} + +- (void)dealloc +{ + if (initialized) + if (!of_rmutex_free(&rmutex)) @throw [OFMutexStillLockedException exceptionWithClass: [self class] mutex: self]; [super dealloc]; Index: src/threading.h ================================================================== --- src/threading.h +++ src/threading.h @@ -393,10 +393,11 @@ return YES; } # define of_rmutex_lock of_mutex_lock +# define of_rmutex_trylock of_mutex_trylock # define of_rmutex_unlock of_mutex_unlock # define of_rmutex_free of_mutex_free #else static OF_INLINE BOOL of_rmutex_new(of_rmutex_t *rmutex) @@ -421,10 +422,32 @@ return YES; } if (!of_mutex_lock(&rmutex->mutex)) return NO; + + if (!of_tlskey_set(rmutex->count, (void*)1)) { + of_mutex_unlock(&rmutex->mutex); + return NO; + } + + return YES; +} + +static OF_INLINE BOOL +of_rmutex_trylock(of_rmutex_t *rmutex) +{ + uintptr_t count = (uintptr_t)of_tlskey_get(rmutex->count); + + if (count > 0) { + if (!of_tlskey_set(rmutex->count, (void*)(count + 1))) + return NO; + return YES; + } + + if (!of_mutex_trylock(&rmutex->mutex)) + return NO; if (!of_tlskey_set(rmutex->count, (void*)1)) { of_mutex_unlock(&rmutex->mutex); return NO; }