wait: Introduce wait for raw handles too

This commit is contained in:
plutooo 2018-12-13 22:50:00 +01:00 committed by fincs
parent 68b4d323a0
commit 376add30a4
4 changed files with 53 additions and 10 deletions

View File

@ -362,6 +362,7 @@ Result svcResetSignal(Handle handle);
* @brief Waits on one or more synchronization objects, optionally with a timeout. * @brief Waits on one or more synchronization objects, optionally with a timeout.
* @return Result code. * @return Result code.
* @note Syscall number 0x18. * @note Syscall number 0x18.
* @note Please use \ref waitMultiHandle instead. That function handles sporadical interrupts caused by usermode synchronization primitives.
*/ */
Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout); Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount, u64 timeout);
@ -369,6 +370,7 @@ Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount
* @brief Waits on a single synchronization object, optionally with a timeout. * @brief Waits on a single synchronization object, optionally with a timeout.
* @return Result code. * @return Result code.
* @note Wrapper for \ref svcWaitSynchronization. * @note Wrapper for \ref svcWaitSynchronization.
* @note Please use \ref waitSingleHandle instead. That function handles sporadical interrupts caused by usermode synchronization primitives.
*/ */
static inline Result svcWaitSynchronizationSingle(Handle handle, u64 timeout) { static inline Result svcWaitSynchronizationSingle(Handle handle, u64 timeout) {
s32 tmp; s32 tmp;

View File

@ -95,6 +95,9 @@ static inline Waiter waiterForThreadExit(Thread* t) {
return waiterForHandle(t->handle); return waiterForHandle(t->handle);
} }
Result waitN(s32* idx_out, Waiter* objects, size_t num_objects, u64 timeout);
Result waitNHandle(s32* idx_out, Handle* handles, size_t num_handles, u64 timeout);
/** /**
* @brief Waits for an arbitrary number of waiters. This is a macro that uses var-args. * @brief Waits for an arbitrary number of waiters. This is a macro that uses var-args.
* @param[out] idx_out The index of the signalled waiter. * @param[out] idx_out The index of the signalled waiter.
@ -102,6 +105,33 @@ static inline Waiter waiterForThreadExit(Thread* t) {
* @note The number of waiters must be less than 64. This is a Horizon kernel limitation. * @note The number of waiters must be less than 64. This is a Horizon kernel limitation.
*/ */
#define waitMulti(idx_out, timeout, ...) \ #define waitMulti(idx_out, timeout, ...) \
waitN((idx_out), (timeout), (Waiter[]) { __VA_ARGS__ }, sizeof((Waiter[]) { __VA_ARGS__ }) / sizeof(Waiter)) waitN((idx_out), (Waiter[]) { __VA_ARGS__ }, sizeof((Waiter[]) { __VA_ARGS__ }) / sizeof(Waiter), (timeout))
Result waitN(s32* idx_out, u64 timeout, Waiter* objects, size_t num_objects); /**
* @brief Waits for an arbitrary number of handles. This is a macro that uses var-args.
* @param[out] idx_out The index of the signalled handle.
* @param[in] timeout Timeout (in nanoseconds).
* @note The number of handles must be less than 64. This is a Horizon kernel limitation.
*/
#define waitMultiHandle(idx_out, timeout, ...) \
waitNHandle((idx_out), (Handle[]) { __VA_ARGS__ }, sizeof((Handle[]) { __VA_ARGS__ }) / sizeof(Handle), (timeout))
/**
* @brief Waits for a single waiter.
* @param[in] w The waiter to wait for.
* @param[in] timeout Timeout (in nanoseconds).
*/
static inline Result waitSingle(Waiter w, u64 timeout) {
s32 idx;
return waitMulti(&idx, timeout, w);
}
/**
* @brief Waits for a single handle.
* @param[in] h The handle to wait for.
* @param[in] timeout Timeout (in nanoseconds).
*/
static inline Result waitSingleHandle(Handle h, u64 timeout) {
s32 idx;
return waitMultiHandle(&idx, timeout, h);
}

View File

@ -6,6 +6,7 @@
#include "kernel/svc.h" #include "kernel/svc.h"
#include "kernel/virtmem.h" #include "kernel/virtmem.h"
#include "kernel/thread.h" #include "kernel/thread.h"
#include "kernel/wait.h"
#include "../internal.h" #include "../internal.h"
extern const u8 __tdata_lma[]; extern const u8 __tdata_lma[];
@ -113,7 +114,7 @@ Result threadStart(Thread* t) {
} }
Result threadWaitForExit(Thread* t) { Result threadWaitForExit(Thread* t) {
return svcWaitSynchronizationSingle(t->handle, -1); return waitSingleHandle(t->handle, -1);
} }
Result threadClose(Thread* t) { Result threadClose(Thread* t) {

View File

@ -13,9 +13,11 @@
#define MAX_WAIT 0x40 #define MAX_WAIT 0x40
#define KernelError_Timeout 0xEA01 #define KernelError_Timeout 0xEA01
#define KernelError_Interrupt 0xEC01 #define KernelError_Canceled 0xEC01
static Result waitImpl(s32* idx_out, u64 timeout, Waiter* objects, size_t num_objects) typedef Result (*WaitImplFunc)(s32* idx_out, void* objects, size_t num_objects, u64 timeout);
static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 timeout)
{ {
if (num_objects > MAX_WAIT) if (num_objects > MAX_WAIT)
return MAKERESULT(Module_Libnx, LibnxError_TooManyWaitables); return MAKERESULT(Module_Libnx, LibnxError_TooManyWaitables);
@ -121,7 +123,7 @@ static Result waitImpl(s32* idx_out, u64 timeout, Waiter* objects, size_t num_ob
*idx_out = end_tick_idx; *idx_out = end_tick_idx;
rc = 0; rc = 0;
} }
else if (rc == KernelError_Interrupt) else if (rc == KernelError_Canceled)
{ {
// If no listener filled in its own index, we return the interrupt error back to caller. // If no listener filled in its own index, we return the interrupt error back to caller.
// This only happens if user for some reason manually does a svcCancelSynchronization. // This only happens if user for some reason manually does a svcCancelSynchronization.
@ -141,7 +143,7 @@ static Result waitImpl(s32* idx_out, u64 timeout, Waiter* objects, size_t num_ob
break; break;
case WaiterNodeType_Timer: case WaiterNodeType_Timer:
rc = KernelError_Interrupt; rc = KernelError_Canceled;
break; break;
} }
} }
@ -156,14 +158,14 @@ clean_up:
return rc; return rc;
} }
Result waitN(s32* idx_out, u64 timeout, Waiter* objects, size_t num_objects) static Result _waitLoop(WaitImplFunc wait, s32* idx_out, void* objects, size_t num_objects, u64 timeout)
{ {
while (1) while (1)
{ {
u64 cur_tick = armGetSystemTick(); u64 cur_tick = armGetSystemTick();
Result rc = waitImpl(idx_out, timeout, objects, num_objects); Result rc = wait(idx_out, objects, num_objects, timeout);
if (rc == KernelError_Interrupt) if (rc == KernelError_Canceled)
{ {
// On timer stop/start an interrupt is sent to listeners. // On timer stop/start an interrupt is sent to listeners.
// It means the timer state has changed, and we should restart the wait. // It means the timer state has changed, and we should restart the wait.
@ -185,3 +187,11 @@ Result waitN(s32* idx_out, u64 timeout, Waiter* objects, size_t num_objects)
} }
} }
} }
Result waitN(s32* idx_out, Waiter* objects, size_t num_objects, u64 timeout) {
return _waitLoop((WaitImplFunc) &waitImpl, idx_out, (void*) objects, num_objects, timeout);
}
Result waitNHandle(s32* idx_out, Handle* handles, size_t num_handles, u64 timeout) {
return _waitLoop((WaitImplFunc) &svcWaitSynchronization, idx_out, (void*) handles, num_handles, timeout);
}