Index: src/OFCondition.m ================================================================== --- src/OFCondition.m +++ src/OFCondition.m @@ -14,10 +14,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFCondition.h" #import "OFDate.h" #import "OFConditionBroadcastFailedException.h" @@ -47,45 +49,60 @@ return self; } - (void)dealloc { - if (_conditionInitialized) - if (!of_condition_free(&_condition)) + if (_conditionInitialized) { + if (!of_condition_free(&_condition)) { + OF_ENSURE(errno == EBUSY); + @throw [OFConditionStillWaitingException exceptionWithCondition: self]; + } + } [super dealloc]; } - (void)wait { if (!of_condition_wait(&_condition, &_mutex)) @throw [OFConditionWaitFailedException - exceptionWithCondition: self]; + exceptionWithCondition: self + errNo: errno]; } - (bool)waitForTimeInterval: (of_time_interval_t)timeInterval { - return of_condition_timed_wait(&_condition, &_mutex, timeInterval); + if (!of_condition_timed_wait(&_condition, &_mutex, timeInterval)) { + if (errno == ETIMEDOUT) + return false; + else + @throw [OFConditionWaitFailedException + exceptionWithCondition: self + errNo: errno]; + } + + return true; } - (bool)waitUntilDate: (OFDate *)date { - return of_condition_timed_wait(&_condition, &_mutex, - date.timeIntervalSinceNow); + return [self waitForTimeInterval: date.timeIntervalSinceNow]; } - (void)signal { if (!of_condition_signal(&_condition)) @throw [OFConditionSignalFailedException - exceptionWithCondition: self]; + exceptionWithCondition: self + errNo: errno]; } - (void)broadcast { if (!of_condition_broadcast(&_condition)) @throw [OFConditionBroadcastFailedException - exceptionWithCondition: self]; + exceptionWithCondition: self + errNo: errno]; } @end Index: src/OFMutex.m ================================================================== --- src/OFMutex.m +++ src/OFMutex.m @@ -14,10 +14,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFMutex.h" #import "OFString.h" #import "OFInitializationFailedException.h" @@ -48,34 +50,48 @@ return self; } - (void)dealloc { - if (_initialized) - if (!of_mutex_free(&_mutex)) + if (_initialized) { + if (!of_mutex_free(&_mutex)) { + OF_ENSURE(errno == EBUSY); + @throw [OFStillLockedException exceptionWithLock: self]; + } + } [_name release]; [super dealloc]; } - (void)lock { if (!of_mutex_lock(&_mutex)) - @throw [OFLockFailedException exceptionWithLock: self]; + @throw [OFLockFailedException exceptionWithLock: self + errNo: errno]; } - (bool)tryLock { - return of_mutex_trylock(&_mutex); + if (!of_mutex_trylock(&_mutex)) { + if (errno == EBUSY) + return false; + else + @throw [OFLockFailedException exceptionWithLock: self + errNo: errno]; + } + + return true; } - (void)unlock { if (!of_mutex_unlock(&_mutex)) - @throw [OFUnlockFailedException exceptionWithLock: self]; + @throw [OFUnlockFailedException exceptionWithLock: self + errNo: errno]; } - (OFString *)description { if (_name == nil) Index: src/OFRecursiveMutex.m ================================================================== --- src/OFRecursiveMutex.m +++ src/OFRecursiveMutex.m @@ -14,10 +14,12 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFRecursiveMutex.h" #import "OFString.h" #import "OFInitializationFailedException.h" @@ -48,34 +50,48 @@ return self; } - (void)dealloc { - if (_initialized) - if (!of_rmutex_free(&_rmutex)) + if (_initialized) { + if (!of_rmutex_free(&_rmutex)) { + OF_ENSURE(errno == EBUSY); + @throw [OFStillLockedException exceptionWithLock: self]; + } + } [_name release]; [super dealloc]; } - (void)lock { if (!of_rmutex_lock(&_rmutex)) - @throw [OFLockFailedException exceptionWithLock: self]; + @throw [OFLockFailedException exceptionWithLock: self + errNo: errno]; } - (bool)tryLock { - return of_rmutex_trylock(&_rmutex); + if (!of_rmutex_trylock(&_rmutex)) { + if (errno == EBUSY) + return false; + else + @throw [OFLockFailedException exceptionWithLock: self + errNo: errno]; + } + + return true; } - (void)unlock { if (!of_rmutex_unlock(&_rmutex)) - @throw [OFUnlockFailedException exceptionWithLock: self]; + @throw [OFUnlockFailedException exceptionWithLock: self + errNo: errno]; } - (OFString *)description { if (_name == nil) Index: src/OFThread.m ================================================================== --- src/OFThread.m +++ src/OFThread.m @@ -18,10 +18,12 @@ #define OF_THREAD_M #define _POSIX_TIMERS #define __NO_EXT_QNX #include "config.h" + +#include #include #include #include @@ -413,18 +415,26 @@ _running = OF_THREAD_RUNNING; if (!of_thread_new(&_thread, callMain, self, &_attr)) { [self release]; - @throw [OFThreadStartFailedException exceptionWithThread: self]; + @throw [OFThreadStartFailedException + exceptionWithThread: self + errNo: errno]; } } - (id)join { - if (_running == OF_THREAD_NOT_RUNNING || !of_thread_join(_thread)) - @throw [OFThreadJoinFailedException exceptionWithThread: self]; + if (_running == OF_THREAD_NOT_RUNNING) + @throw [OFThreadJoinFailedException + exceptionWithThread: self + errNo: EINVAL]; + + if (!of_thread_join(_thread)) + @throw [OFThreadJoinFailedException exceptionWithThread: self + errNo: errno]; _running = OF_THREAD_NOT_RUNNING; return _returnValue; } Index: src/condition_amiga.m ================================================================== --- src/condition_amiga.m +++ src/condition_amiga.m @@ -12,10 +12,12 @@ * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ + +#include #include #include #ifndef OF_AMIGAOS4 # include @@ -76,12 +78,14 @@ .task = FindTask(NULL), .sigBit = AllocSignal(-1) }; bool ret; - if (waitingTask.sigBit == -1) + if (waitingTask.sigBit == -1) { + errno = EAGAIN; return false; + } Forbid(); if (!of_mutex_unlock(mutex)) { FreeSignal(waitingTask.sigBit); @@ -148,16 +152,20 @@ ULONG mask; bool ret; NewList(&port.mp_MsgList); - if (waitingTask.sigBit == -1 || port.mp_SigBit == -1) + if (waitingTask.sigBit == -1 || port.mp_SigBit == -1) { + errno = EAGAIN; goto fail; + } if (OpenDevice("timer.device", UNIT_MICROHZ, - (struct IORequest *)&request, 0) != 0) + (struct IORequest *)&request, 0) != 0) { + errno = EAGAIN; goto fail; + } Forbid(); if (!of_mutex_unlock(mutex)) { Permit(); @@ -167,12 +175,24 @@ waitingTask.next = condition->waitingTasks; condition->waitingTasks = &waitingTask; SendIO((struct IORequest *)&request); - mask = Wait((1 << waitingTask.sigBit) | (1 << port.mp_SigBit)); - ret = of_mutex_lock(mutex); + mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit)); + if (mask & (1ul << waitingTask.sigBit)) + ret = of_mutex_lock(mutex); + else if (mask & (1ul << port.mp_SigBit)) { + ret = false; + errno = ETIMEDOUT; + } else { + /* + * This should not happen - it means something interrupted the + * Wait(), so the best we can do is return EINTR. + */ + ret = false; + errno = EINTR; + } condition->waitingTasks = waitingTask.next; if (!CheckIO((struct IORequest *)&request)) { AbortIO((struct IORequest *)&request); @@ -180,13 +200,10 @@ } CloseDevice((struct IORequest *)&request); Permit(); - if (!(mask & (1 << waitingTask.sigBit))) - goto fail; - FreeSignal(waitingTask.sigBit); FreeSignal(port.mp_SigBit); return ret; @@ -202,13 +219,15 @@ bool of_condition_free(of_condition_t *condition) { Forbid(); @try { - if (condition->waitingTasks != NULL) + if (condition->waitingTasks != NULL) { + errno = EBUSY; return false; + } } @finally { Permit(); } return true; } Index: src/condition_winapi.m ================================================================== --- src/condition_winapi.m +++ src/condition_winapi.m @@ -13,35 +13,57 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ +#include + bool of_condition_new(of_condition_t *condition) { condition->count = 0; - if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) + if ((condition->event = CreateEvent(NULL, FALSE, 0, NULL)) == NULL) { + errno = EAGAIN; return false; + } return true; } bool of_condition_signal(of_condition_t *condition) { - return SetEvent(condition->event); + if (!SetEvent(condition->event)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + errno = EINVAL; + return false; + default: + OF_ENSURE(0); + } + } + + return true; } bool of_condition_broadcast(of_condition_t *condition) { int count = condition->count; - for (int i = 0; i < count; i++) - if (!SetEvent(condition->event)) - return false; + for (int i = 0; i < count; i++) { + if (!SetEvent(condition->event)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + errno = EINVAL; + return false; + default: + OF_ENSURE(0); + } + } + } return true; } bool @@ -54,14 +76,24 @@ of_atomic_int_inc(&condition->count); status = WaitForSingleObject(condition->event, INFINITE); of_atomic_int_dec(&condition->count); - if (!of_mutex_lock(mutex)) - return false; - - return (status == WAIT_OBJECT_0); + switch (status) { + case WAIT_OBJECT_0: + return of_mutex_lock(mutex); + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + errno = EINVAL; + return false; + default: + OF_ENSURE(0); + } + default: + OF_ENSURE(0); + } } bool of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, of_time_interval_t timeout) @@ -73,19 +105,34 @@ of_atomic_int_inc(&condition->count); status = WaitForSingleObject(condition->event, timeout * 1000); of_atomic_int_dec(&condition->count); - if (!of_mutex_lock(mutex)) + switch (status) { + case WAIT_OBJECT_0: + return of_mutex_lock(mutex); + case WAIT_TIMEOUT: + errno = ETIMEDOUT; return false; - - return (status == WAIT_OBJECT_0); + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + errno = EINVAL; + return false; + default: + OF_ENSURE(0); + } + default: + OF_ENSURE(0); + } } bool of_condition_free(of_condition_t *condition) { - if (condition->count != 0) + if (condition->count != 0) { + errno = EBUSY; return false; + } return CloseHandle(condition->event); } Index: src/exceptions/OFConditionBroadcastFailedException.h ================================================================== --- src/exceptions/OFConditionBroadcastFailedException.h +++ src/exceptions/OFConditionBroadcastFailedException.h @@ -33,31 +33,42 @@ * @brief An exception indicating broadcasting a condition failed. */ @interface OFConditionBroadcastFailedException: OFException { OFCondition *_condition; + int _errNo; } /*! * @brief The condition which could not be broadcasted. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +/*! + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + /*! * @brief Returns a new, autoreleased condition broadcast failed exception. * * @param condition The condition which could not be broadcasted + * @param errNo The errno of the error that occurred * @return A new, autoreleased condition broadcast failed exception */ -+ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition; ++ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition + errNo: (int)errNo; /*! * @brief Initializes an already allocated condition broadcast failed exception. * * @param condition The condition which could not be broadcasted + * @param errNo The errno of the error that occurred * @return An initialized condition broadcast failed exception */ - (instancetype)initWithCondition: (nullable OFCondition *)condition - OF_DESIGNATED_INITIALIZER; + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionBroadcastFailedException.m ================================================================== --- src/exceptions/OFConditionBroadcastFailedException.m +++ src/exceptions/OFConditionBroadcastFailedException.m @@ -14,36 +14,42 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFConditionBroadcastFailedException.h" #import "OFString.h" #import "OFCondition.h" @implementation OFConditionBroadcastFailedException -@synthesize condition = _condition; +@synthesize condition = _condition, errNo = _errNo; + (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo { - return [[[self alloc] initWithCondition: condition] autorelease]; -} - -- (instancetype)init -{ - return [self initWithCondition: nil]; + return [[[self alloc] initWithCondition: condition + errNo: errNo] autorelease]; } - (instancetype)initWithCondition: (OFCondition *)condition + errNo: (int)errNo { self = [super init]; _condition = [condition retain]; + _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_condition release]; @@ -50,13 +56,10 @@ [super dealloc]; } - (OFString *)description { - if (_condition != nil) - return [OFString stringWithFormat: - @"Broadcasting a condition of type %@ failed!", - _condition.class]; - else - return @"Broadcasting a condition failed!"; + return [OFString stringWithFormat: + @"Broadcasting a condition of type %@ failed: %s", + _condition.class, strerror(_errNo)]; } @end Index: src/exceptions/OFConditionSignalFailedException.h ================================================================== --- src/exceptions/OFConditionSignalFailedException.h +++ src/exceptions/OFConditionSignalFailedException.h @@ -33,31 +33,42 @@ * @brief An exception indicating signaling a condition failed. */ @interface OFConditionSignalFailedException: OFException { OFCondition *_condition; + int _errNo; } /*! * @brief The condition which could not be signaled. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +/*! + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + /*! * @brief Creates a new, autoreleased condition signal failed exception. * * @param condition The condition which could not be signaled + * @param errNo The errno of the error that occurred * @return A new, autoreleased condition signal failed exception */ -+ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition; ++ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition + errNo: (int)errNo; /*! * @brief Initializes an already allocated condition signal failed exception. * * @param condition The condition which could not be signaled + * @param errNo The errno of the error that occurred * @return An initialized condition signal failed exception */ - (instancetype)initWithCondition: (nullable OFCondition *)condition - OF_DESIGNATED_INITIALIZER; + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionSignalFailedException.m ================================================================== --- src/exceptions/OFConditionSignalFailedException.m +++ src/exceptions/OFConditionSignalFailedException.m @@ -14,36 +14,42 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFConditionSignalFailedException.h" #import "OFString.h" #import "OFCondition.h" @implementation OFConditionSignalFailedException -@synthesize condition = _condition; +@synthesize condition = _condition, errNo = _errNo; + (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo { - return [[[self alloc] initWithCondition: condition] autorelease]; -} - -- (instancetype)init -{ - return [self initWithCondition: nil]; + return [[[self alloc] initWithCondition: condition + errNo: errNo] autorelease]; } - (instancetype)initWithCondition: (OFCondition *)condition + errNo: (int)errNo { self = [super init]; _condition = [condition retain]; + _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_condition release]; @@ -50,13 +56,10 @@ [super dealloc]; } - (OFString *)description { - if (_condition != nil) - return [OFString stringWithFormat: - @"Signaling a condition of type %@ failed!", - _condition.class]; - else - return @"Signaling a condition failed!"; + return [OFString stringWithFormat: + @"Signaling a condition of type %@ failed: %s", + _condition.class, strerror(_errNo)]; } @end Index: src/exceptions/OFConditionWaitFailedException.h ================================================================== --- src/exceptions/OFConditionWaitFailedException.h +++ src/exceptions/OFConditionWaitFailedException.h @@ -33,31 +33,42 @@ * @brief An exception indicating waiting for a condition failed. */ @interface OFConditionWaitFailedException: OFException { OFCondition *_condition; + int _errNo; } /*! * @brief The condition for which could not be waited. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFCondition *condition; +/*! + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + /*! * @brief Creates a new, autoreleased condition wait failed exception. * * @param condition The condition for which could not be waited + * @param errNo The errno of the error that occurred * @return A new, autoreleased condition wait failed exception */ -+ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition; ++ (instancetype)exceptionWithCondition: (nullable OFCondition *)condition + errNo: (int)errNo; /*! * @brief Initializes an already allocated condition wait failed exception. * * @param condition The condition for which could not be waited + * @param errNo The errno of the error that occurred * @return An initialized condition wait failed exception */ - (instancetype)initWithCondition: (nullable OFCondition *)condition - OF_DESIGNATED_INITIALIZER; + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFConditionWaitFailedException.m ================================================================== --- src/exceptions/OFConditionWaitFailedException.m +++ src/exceptions/OFConditionWaitFailedException.m @@ -14,36 +14,42 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFConditionWaitFailedException.h" #import "OFString.h" #import "OFCondition.h" @implementation OFConditionWaitFailedException -@synthesize condition = _condition; +@synthesize condition = _condition, errNo = _errNo; + (instancetype)exceptionWithCondition: (OFCondition *)condition + errNo: (int)errNo { - return [[[self alloc] initWithCondition: condition] autorelease]; -} - -- (instancetype)init -{ - return [self initWithCondition: nil]; + return [[[self alloc] initWithCondition: condition + errNo: errNo] autorelease]; } - (instancetype)initWithCondition: (OFCondition *)condition + errNo: (int)errNo { self = [super init]; _condition = [condition retain]; + _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_condition release]; @@ -50,13 +56,10 @@ [super dealloc]; } - (OFString *)description { - if (_condition != nil) - return [OFString stringWithFormat: - @"Waiting for a condition of type %@ failed!", - _condition.class]; - else - return @"Waiting for a condition failed!"; + return [OFString stringWithFormat: + @"Waiting for a condition of type %@ failed: %s", + _condition.class, strerror(_errNo)]; } @end Index: src/exceptions/OFLockFailedException.h ================================================================== --- src/exceptions/OFLockFailedException.h +++ src/exceptions/OFLockFailedException.h @@ -27,31 +27,42 @@ * @brief An exception indicating that locking a lock failed. */ @interface OFLockFailedException: OFException { id _lock; + int _errNo; } /*! * @brief The lock which could not be locked. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) id lock; +/*! + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + /*! * @brief Creates a new, autoreleased lock failed exception. * * @param lock The lock which could not be locked + * @param errNo The errno of the error that occurred * @return A new, autoreleased lock failed exception */ -+ (instancetype)exceptionWithLock: (nullable id )lock; ++ (instancetype)exceptionWithLock: (nullable id )lock + errNo: (int)errNo; /*! * @brief Initializes an already allocated lock failed exception. * * @param lock The lock which could not be locked + * @param errNo The errno of the error that occurred * @return An initialized lock failed exception */ - (instancetype)initWithLock: (nullable id )lock - OF_DESIGNATED_INITIALIZER; + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFLockFailedException.m ================================================================== --- src/exceptions/OFLockFailedException.m +++ src/exceptions/OFLockFailedException.m @@ -14,35 +14,41 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFLockFailedException.h" #import "OFString.h" @implementation OFLockFailedException -@synthesize lock = _lock; +@synthesize lock = _lock, errNo = _errNo; + (instancetype)exceptionWithLock: (id )lock + errNo: (int)errNo { - return [[[self alloc] initWithLock: lock] autorelease]; -} - -- (instancetype)init -{ - return [self initWithLock: nil]; + return [[[self alloc] initWithLock: lock + errNo: errNo] autorelease]; } - (instancetype)initWithLock: (id )lock + errNo: (int)errNo { self = [super init]; _lock = [lock retain]; + _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_lock release]; @@ -49,12 +55,10 @@ [super dealloc]; } - (OFString *)description { - if (_lock != nil) - return [OFString stringWithFormat: - @"A lock of type %@ could not be locked!", _lock.class]; - else - return @"A lock could not be locked!"; + return [OFString stringWithFormat: + @"A lock of type %@ could not be locked: %s", + _lock.class, strerror(_errNo)]; } @end Index: src/exceptions/OFThreadJoinFailedException.h ================================================================== --- src/exceptions/OFThreadJoinFailedException.h +++ src/exceptions/OFThreadJoinFailedException.h @@ -32,31 +32,42 @@ * @brief An exception indicating that joining a thread failed. */ @interface OFThreadJoinFailedException: OFException { OFThread *_thread; + int _errNo; } /*! * @brief The thread which could not be joined. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFThread *thread; +/*! + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + /*! * @brief Creates a new, autoreleased thread join failed exception. * * @param thread The thread which could not be joined + * @param errNo The errno of the error that occurred * @return A new, autoreleased thread join failed exception */ -+ (instancetype)exceptionWithThread: (nullable OFThread *)thread; ++ (instancetype)exceptionWithThread: (nullable OFThread *)thread + errNo: (int)errNo; /*! * @brief Initializes an already allocated thread join failed exception. * * @param thread The thread which could not be joined + * @param errNo The errno of the error that occurred * @return An initialized thread join failed exception */ - (instancetype)initWithThread: (nullable OFThread *)thread - OF_DESIGNATED_INITIALIZER; + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFThreadJoinFailedException.m ================================================================== --- src/exceptions/OFThreadJoinFailedException.m +++ src/exceptions/OFThreadJoinFailedException.m @@ -14,36 +14,42 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFThreadJoinFailedException.h" #import "OFString.h" #import "OFThread.h" @implementation OFThreadJoinFailedException -@synthesize thread = _thread; +@synthesize thread = _thread, errNo = _errNo; + (instancetype)exceptionWithThread: (OFThread *)thread + errNo: (int)errNo { - return [[[self alloc] initWithThread: thread] autorelease]; -} - -- (instancetype)init -{ - return [self initWithThread: nil]; + return [[[self alloc] initWithThread: thread + errNo: errNo] autorelease]; } - (instancetype)initWithThread: (OFThread *)thread + errNo: (int)errNo { self = [super init]; _thread = [thread retain]; + _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_thread release]; @@ -50,15 +56,10 @@ [super dealloc]; } - (OFString *)description { - if (_thread != nil) - return [OFString stringWithFormat: - @"Joining a thread of type %@ failed! Most likely, another " - @"thread already waits for the thread to join.", - _thread.class]; - else - return @"Joining a thread failed! Most likely, another thread " - @"already waits for the thread to join."; + return [OFString stringWithFormat: + @"Joining a thread of type %@ failed: %s", + _thread.class, strerror(_errNo)]; } @end Index: src/exceptions/OFThreadStartFailedException.h ================================================================== --- src/exceptions/OFThreadStartFailedException.h +++ src/exceptions/OFThreadStartFailedException.h @@ -32,31 +32,42 @@ * @brief An exception indicating that starting a thread failed. */ @interface OFThreadStartFailedException: OFException { OFThread *_thread; + int _errNo; } /*! * @brief The thread which could not be started. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFThread *thread; +/*! + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + /*! * @brief Creates a new, autoreleased thread start failed exception. * * @param thread The thread which could not be started + * @param errNo The errno of the error that occurred * @return A new, autoreleased thread start failed exception */ -+ (instancetype)exceptionWithThread: (nullable OFThread *)thread; ++ (instancetype)exceptionWithThread: (nullable OFThread *)thread + errNo: (int)errNo; /*! * @brief Initializes an already allocated thread start failed exception. * * @param thread The thread which could not be started + * @param errNo The errno of the error that occurred * @return An initialized thread start failed exception */ - (instancetype)initWithThread: (nullable OFThread *)thread - OF_DESIGNATED_INITIALIZER; + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFThreadStartFailedException.m ================================================================== --- src/exceptions/OFThreadStartFailedException.m +++ src/exceptions/OFThreadStartFailedException.m @@ -14,36 +14,42 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFThreadStartFailedException.h" #import "OFString.h" #import "OFThread.h" @implementation OFThreadStartFailedException -@synthesize thread = _thread; +@synthesize thread = _thread, errNo = _errNo; + (instancetype)exceptionWithThread: (OFThread *)thread + errNo: (int)errNo { - return [[[self alloc] initWithThread: thread] autorelease]; -} - -- (instancetype)init -{ - return [self initWithThread: nil]; + return [[[self alloc] initWithThread: thread + errNo: errNo] autorelease]; } - (instancetype)initWithThread: (OFThread *)thread + errNo: (int)errNo { self = [super init]; _thread = [thread retain]; + _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_thread release]; @@ -50,12 +56,10 @@ [super dealloc]; } - (OFString *)description { - if (_thread != nil) - return [OFString stringWithFormat: - @"Starting a thread of type %@ failed!", _thread.class]; - else - return @"Starting a thread failed!"; + return [OFString stringWithFormat: + @"Starting a thread of type %@ failed: %s", + _thread.class, strerror(_errNo)]; } @end Index: src/exceptions/OFUnlockFailedException.h ================================================================== --- src/exceptions/OFUnlockFailedException.h +++ src/exceptions/OFUnlockFailedException.h @@ -27,31 +27,42 @@ * @brief An exception indicating that unlocking a lock failed. */ @interface OFUnlockFailedException: OFException { id _lock; + int _errNo; } /*! * @brief The lock which could not be unlocked. */ @property OF_NULLABLE_PROPERTY (readonly, nonatomic) id lock; +/*! + * @brief The errno of the error that occurred. + */ +@property (readonly, nonatomic) int errNo; + /*! * @brief Creates a new, autoreleased unlock failed exception. * * @param lock The lock which could not be unlocked + * @param errNo The errno of the error that occurred * @return A new, autoreleased unlock failed exception */ -+ (instancetype)exceptionWithLock: (nullable id )lock; ++ (instancetype)exceptionWithLock: (nullable id )lock + errNo: (int)errNo; /*! * @brief Initializes an already allocated unlock failed exception. * * @param lock The lock which could not be unlocked + * @param errNo The errno of the error that occurred * @return An initialized unlock failed exception */ - (instancetype)initWithLock: (nullable id )lock - OF_DESIGNATED_INITIALIZER; + errNo: (int)errNo OF_DESIGNATED_INITIALIZER; + +- (instancetype)init OF_UNAVAILABLE; @end OF_ASSUME_NONNULL_END Index: src/exceptions/OFUnlockFailedException.m ================================================================== --- src/exceptions/OFUnlockFailedException.m +++ src/exceptions/OFUnlockFailedException.m @@ -14,35 +14,41 @@ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" + +#include #import "OFUnlockFailedException.h" #import "OFString.h" @implementation OFUnlockFailedException -@synthesize lock = _lock; +@synthesize lock = _lock, errNo = _errNo; + (instancetype)exceptionWithLock: (id )lock + errNo: (int)errNo { - return [[[self alloc] initWithLock: lock] autorelease]; -} - -- (instancetype)init -{ - return [self initWithLock: nil]; + return [[[self alloc] initWithLock: lock + errNo: errNo] autorelease]; } - (instancetype)initWithLock: (id )lock + errNo: (int)errNo { self = [super init]; _lock = [lock retain]; + _errNo = errNo; return self; } + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} - (void)dealloc { [_lock release]; @@ -49,12 +55,10 @@ [super dealloc]; } - (OFString *)description { - if (_lock != nil) - return [OFString stringWithFormat: - @"A lock of type %@ could not be unlocked!", _lock.class]; - else - return @"A lock could not be unlocked!"; + return [OFString stringWithFormat: + @"A lock of type %@ could not be unlocked: %s", + _lock.class, strerror(_errNo)]; } @end Index: src/mutex_amiga.m ================================================================== --- src/mutex_amiga.m +++ src/mutex_amiga.m @@ -12,10 +12,12 @@ * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ + +#include #include bool of_mutex_new(of_mutex_t *mutex) @@ -34,11 +36,16 @@ } bool of_mutex_trylock(of_mutex_t *mutex) { - return AttemptSemaphore(mutex); + if (!AttemptSemaphore(mutex)) { + errno = EBUSY; + return false; + } + + return true; } bool of_mutex_unlock(of_mutex_t *mutex) { Index: src/mutex_winapi.m ================================================================== --- src/mutex_winapi.m +++ src/mutex_winapi.m @@ -13,10 +13,12 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ +#include + bool of_mutex_new(of_mutex_t *mutex) { InitializeCriticalSection(mutex); @@ -32,11 +34,16 @@ } bool of_mutex_trylock(of_mutex_t *mutex) { - return TryEnterCriticalSection(mutex); + if (!TryEnterCriticalSection(mutex)) { + errno = EBUSY; + return false; + } + + return true; } bool of_mutex_unlock(of_mutex_t *mutex) { Index: src/thread_amiga.m ================================================================== --- src/thread_amiga.m +++ src/thread_amiga.m @@ -12,10 +12,13 @@ * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ + +#include +#include #include #include #include @@ -72,12 +75,14 @@ of_thread_new(of_thread_t *thread, void (*function)(id), id object, const of_thread_attr_t *attr) { OFMutableData *tags = nil; - if ((*thread = calloc(1, sizeof(**thread))) == NULL) + if ((*thread = calloc(1, sizeof(**thread))) == NULL) { + errno = ENOMEM; return false; + } @try { (*thread)->function = function; (*thread)->object = object; InitSemaphore(&(*thread)->semaphore); @@ -108,12 +113,14 @@ ADD_TAG(NP_CloseInput, FALSE) ADD_TAG(NP_CloseOutput, FALSE) ADD_TAG(NP_CloseError, FALSE) if (attr != NULL && attr->priority != 0) { - if (attr->priority < 1 || attr->priority > 1) + if (attr->priority < 1 || attr->priority > 1) { + errno = EINVAL; return false; + } /* * -1 should be -128 (lowest possible priority) while * +1 should be +127 (highest possible priority). */ @@ -131,10 +138,11 @@ #undef ADD_TAG (*thread)->task = (struct Task *)CreateNewProc(tags.items); if ((*thread)->task == NULL) { free(*thread); + errno = EAGAIN; return false; } } @catch (id e) { free(*thread); @throw e; @@ -152,37 +160,39 @@ } bool of_thread_join(of_thread_t thread) { - bool ret; - ObtainSemaphore(&thread->semaphore); @try { if (thread->done) { free(thread); return true; } - if (thread->detached || thread->joinTask != NULL) + if (thread->detached || thread->joinTask != NULL) { + errno = EINVAL; return false; + } - if ((thread->joinSigBit = AllocSignal(-1)) == -1) + if ((thread->joinSigBit = AllocSignal(-1)) == -1) { + errno = EAGAIN; return false; + } thread->joinTask = FindTask(NULL); } @finally { ReleaseSemaphore(&thread->semaphore); } - Wait(1 << thread->joinSigBit); + Wait(1ul << thread->joinSigBit); FreeSignal(thread->joinSigBit); - ret = thread->done; + assert(thread->done); free(thread); - return ret; + return true; } bool of_thread_detach(of_thread_t thread) { Index: src/thread_pthread.m ================================================================== --- src/thread_pthread.m +++ src/thread_pthread.m @@ -12,10 +12,12 @@ * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ + +#include #ifdef HAVE_PTHREAD_NP_H # include #endif @@ -112,12 +114,14 @@ struct thread_ctx *ctx; if (attr != NULL) { struct sched_param param; - if (attr->priority < -1 || attr->priority > 1) + if (attr->priority < -1 || attr->priority > 1) { + errno = EINVAL; return false; + } #ifdef HAVE_PTHREAD_ATTR_SETINHERITSCHED if (pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED) != 0) return false; @@ -139,12 +143,14 @@ attr->stackSize) != 0) return false; } } - if ((ctx = malloc(sizeof(*ctx))) == NULL) + if ((ctx = malloc(sizeof(*ctx))) == NULL) { + errno = ENOMEM; return false; + } ctx->function = function; ctx->object = object; ret = (pthread_create(thread, &pattr, @@ -159,18 +165,11 @@ bool of_thread_join(of_thread_t thread) { void *ret; - if (pthread_join(thread, &ret) != 0) - return false; - -#ifdef PTHREAD_CANCELED - return (ret != PTHREAD_CANCELED); -#else - return true; -#endif + return (pthread_join(thread, &ret) == 0); } bool of_thread_detach(of_thread_t thread) { Index: src/thread_winapi.m ================================================================== --- src/thread_winapi.m +++ src/thread_winapi.m @@ -13,10 +13,12 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ +#include + #import "macros.h" bool of_thread_attr_init(of_thread_attr_t *attr) { @@ -31,18 +33,30 @@ const of_thread_attr_t *attr) { *thread = CreateThread(NULL, (attr != NULL ? attr->stackSize : 0), (LPTHREAD_START_ROUTINE)function, (void *)object, 0, NULL); - if (thread == NULL) - return false; + if (thread == NULL) { + switch (GetLastError()) { + case ERROR_NOT_ENOUGH_MEMORY: + errno = ENOMEM; + return false; + case ERROR_ACCESS_DENIED: + errno = EACCES; + return false; + default: + OF_ENSURE(0); + } + } if (attr != NULL && attr->priority != 0) { DWORD priority; - if (attr->priority < -1 || attr->priority > 1) + if (attr->priority < -1 || attr->priority > 1) { + errno = EINVAL; return false; + } if (attr->priority < 0) priority = THREAD_PRIORITY_LOWEST + (1.0 + attr->priority) * (THREAD_PRIORITY_NORMAL - THREAD_PRIORITY_LOWEST); @@ -49,26 +63,34 @@ else priority = THREAD_PRIORITY_NORMAL + attr->priority * (THREAD_PRIORITY_HIGHEST - THREAD_PRIORITY_NORMAL); - if (!SetThreadPriority(*thread, priority)) - return false; + OF_ENSURE(!SetThreadPriority(*thread, priority)); } return true; } bool of_thread_join(of_thread_t thread) { - if (WaitForSingleObject(thread, INFINITE)) - return false; - - CloseHandle(thread); - - return true; + switch (WaitForSingleObject(thread, INFINITE)) { + case WAIT_OBJECT_0: + CloseHandle(thread); + return true; + case WAIT_FAILED: + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + errno = EINVAL; + return false; + default: + OF_ENSURE(0); + } + default: + OF_ENSURE(0); + } } bool of_thread_detach(of_thread_t thread) {