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.
* @return Result code.
* @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);
@ -369,6 +370,7 @@ Result svcWaitSynchronization(s32* index, const Handle* handles, s32 handleCount
* @brief Waits on a single synchronization object, optionally with a timeout.
* @return Result code.
* @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) {
s32 tmp;

View File

@ -95,6 +95,9 @@ static inline Waiter waiterForThreadExit(Thread* t) {
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.
* @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.
*/
#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/virtmem.h"
#include "kernel/thread.h"
#include "kernel/wait.h"
#include "../internal.h"
extern const u8 __tdata_lma[];
@ -113,7 +114,7 @@ Result threadStart(Thread* t) {
}
Result threadWaitForExit(Thread* t) {
return svcWaitSynchronizationSingle(t->handle, -1);
return waitSingleHandle(t->handle, -1);
}
Result threadClose(Thread* t) {

View File

@ -13,9 +13,11 @@
#define MAX_WAIT 0x40
#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)
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;
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.
// 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;
case WaiterNodeType_Timer:
rc = KernelError_Interrupt;
rc = KernelError_Canceled;
break;
}
}
@ -156,14 +158,14 @@ clean_up:
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)
{
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.
// 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);
}