Index: src/OFCondition.h ================================================================== --- src/OFCondition.h +++ src/OFCondition.h @@ -48,10 +48,23 @@ * @note Waiting might have been interrupted by a signal. It is thus recommended * to check the condition again after @ref wait returned! */ - (void)wait; +#ifdef OF_AMIGAOS +/*! + * @brief Blocks the current thread until another thread calls @ref signal, + * @ref broadcast or an Exec Signal is received. + * + * @note This is only available on AmigaOS! + * + * @param signalMask A pointer to a signal mask of Exec Signals to receive. + * This is modified and set to the mask of signals received. + */ +- (void)waitForConditionOrExecSignal: (ULONG *)signalMask; +#endif + /*! * @brief Blocks the current thread until another thread calls @ref signal, * @ref broadcast or the timeout is reached. * * @note Waiting might have been interrupted by a signal. It is thus recommended @@ -60,10 +73,26 @@ * @param timeInterval The time interval until the timeout is reached * @return Whether the condition has been signaled */ - (bool)waitForTimeInterval: (of_time_interval_t)timeInterval; +#ifdef OF_AMIGAOS +/*! + * @brief Blocks the current thread until another thread calls @ref signal, + * @ref broadcast, the timeout is reached or an Exec Signal is received. + * + * @note This is only available on AmigaOS! + * + * @param timeInterval The time interval until the timeout is reached + * @param signalMask A pointer to a signal mask of Exec Signals to receive. + * This is modified and set to the mask of signals received. + * @return Whether the condition has been signaled or a signal received + */ +- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval + orExecSignal: (ULONG *)signalMask; +#endif + /*! * @brief Blocks the current thread until another thread calls @ref signal, * @ref broadcast or the timeout is reached. * * @note Waiting might have been interrupted by a signal. It is thus recommended @@ -71,10 +100,26 @@ * * @param date The date at which the timeout is reached * @return Whether the condition has been signaled */ - (bool)waitUntilDate: (OFDate *)date; + +#ifdef OF_AMIGAOS +/*! + * @brief Blocks the current thread until another thread calls @ref signal, + * @ref broadcast, the timeout is reached or an Exec Signal is received. + * + * @note This is only available on AmigaOS! + * + * @param date The date at which the timeout is reached + * @param signalMask A pointer to a signal mask of Exec Signals to receive. + * This is modified and set to the mask of signals received. + * @return Whether the condition has been signaled or a signal received + */ +- (bool)waitUntilDate: (OFDate *)date + orExecSignal: (ULONG *)signalMask; +#endif /*! * @brief Signals the next waiting thread to continue. */ - (void)signal; Index: src/OFCondition.m ================================================================== --- src/OFCondition.m +++ src/OFCondition.m @@ -68,10 +68,20 @@ if (!of_condition_wait(&_condition, &_mutex)) @throw [OFConditionWaitFailedException exceptionWithCondition: self errNo: errno]; } + +#ifdef OF_AMIGAOS +- (void)waitForConditionOrExecSignal: (ULONG *)signalMask +{ + if (!of_condition_wait_or_signal(&_condition, &_mutex, signalMask)) + @throw [OFConditionWaitFailedException + exceptionWithCondition: self + errNo: errno]; +} +#endif - (bool)waitForTimeInterval: (of_time_interval_t)timeInterval { if (!of_condition_timed_wait(&_condition, &_mutex, timeInterval)) { if (errno == ETIMEDOUT) @@ -82,15 +92,42 @@ errNo: errno]; } return true; } + +#ifdef OF_AMIGAOS +- (bool)waitForTimeInterval: (of_time_interval_t)timeInterval + orExecSignal: (ULONG *)signalMask +{ + if (!of_condition_timed_wait_or_signal(&_condition, &_mutex, + timeInterval, signalMask)) { + if (errno == ETIMEDOUT) + return false; + else + @throw [OFConditionWaitFailedException + exceptionWithCondition: self + errNo: errno]; + } + + return true; +} +#endif - (bool)waitUntilDate: (OFDate *)date { return [self waitForTimeInterval: date.timeIntervalSinceNow]; } + +#ifdef OF_AMIGAOS +- (bool)waitUntilDate: (OFDate *)date + orExecSignal: (ULONG *)signalMask +{ + return [self waitForTimeInterval: date.timeIntervalSinceNow + orExecSignal: signalMask]; +} +#endif - (void)signal { if (!of_condition_signal(&_condition)) @throw [OFConditionSignalFailedException Index: src/condition.h ================================================================== --- src/condition.h +++ src/condition.h @@ -47,18 +47,28 @@ struct of_condition_waiting_task *next; } *waitingTasks; } of_condition_t; #endif +OF_ASSUME_NONNULL_BEGIN + #ifdef __cplusplus extern "C" { #endif extern bool of_condition_new(of_condition_t *condition); extern bool of_condition_signal(of_condition_t *condition); extern bool of_condition_broadcast(of_condition_t *condition); extern bool of_condition_wait(of_condition_t *condition, of_mutex_t *mutex); extern bool of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, of_time_interval_t timeout); +#ifdef OF_AMIGAOS +extern bool of_condition_wait_or_signal(of_condition_t *condition, + of_mutex_t *mutex, ULONG *signalMask); +extern bool of_condition_timed_wait_or_signal(of_condition_t *condition, + of_mutex_t *mutex, of_time_interval_t timeout, ULONG *signalMask); +#endif extern bool of_condition_free(of_condition_t *condition); #ifdef __cplusplus } #endif + +OF_ASSUME_NONNULL_END Index: src/condition_amiga.m ================================================================== --- src/condition_amiga.m +++ src/condition_amiga.m @@ -71,16 +71,26 @@ return true; } bool of_condition_wait(of_condition_t *condition, of_mutex_t *mutex) +{ + ULONG signalMask = 0; + + return of_condition_wait_or_signal(condition, mutex, &signalMask); +} + +bool +of_condition_wait_or_signal(of_condition_t *condition, of_mutex_t *mutex, + ULONG *signalMask) { struct of_condition_waiting_task waitingTask = { .task = FindTask(NULL), .sigBit = AllocSignal(-1) }; bool ret; + ULONG mask; if (waitingTask.sigBit == -1) { errno = EAGAIN; return false; } @@ -93,14 +103,26 @@ } waitingTask.next = condition->waitingTasks; condition->waitingTasks = &waitingTask; - Wait(1 << waitingTask.sigBit); - FreeSignal(waitingTask.sigBit); + mask = Wait((1ul << waitingTask.sigBit) | *signalMask); + + if (mask & (1ul << waitingTask.sigBit)) + ret = of_mutex_lock(mutex); + else if (*signalMask &= mask) + ret = true; + else { + /* + * This should not happen - it means something interrupted the + * Wait(), so the best we can do is return EINTR. + */ + ret = false; + errno = EINTR; + } - ret = of_mutex_lock(mutex); + FreeSignal(waitingTask.sigBit); Permit(); return ret; } @@ -107,10 +129,20 @@ bool of_condition_timed_wait(of_condition_t *condition, of_mutex_t *mutex, of_time_interval_t timeout) { + ULONG signalMask = 0; + + return of_condition_timed_wait_or_signal(condition, mutex, timeout, + &signalMask); +} + +bool +of_condition_timed_wait_or_signal(of_condition_t *condition, of_mutex_t *mutex, + of_time_interval_t timeout, ULONG *signalMask) +{ struct of_condition_waiting_task waitingTask = { .task = FindTask(NULL), .sigBit = AllocSignal(-1) }; struct MsgPort port = { @@ -175,17 +207,20 @@ waitingTask.next = condition->waitingTasks; condition->waitingTasks = &waitingTask; SendIO((struct IORequest *)&request); - mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit)); + mask = Wait((1ul << waitingTask.sigBit) | (1ul << port.mp_SigBit) | + *signalMask); if (mask & (1ul << waitingTask.sigBit)) ret = of_mutex_lock(mutex); else if (mask & (1ul << port.mp_SigBit)) { ret = false; errno = ETIMEDOUT; - } else { + } else if (*signalMask &= mask) + ret = true; + else { /* * This should not happen - it means something interrupted the * Wait(), so the best we can do is return EINTR. */ ret = false;