From 04fff2fc3b6b0fb9413a43e493c19571d859d5df Mon Sep 17 00:00:00 2001 From: fincs Date: Fri, 14 Dec 2018 22:32:50 +0100 Subject: [PATCH] Move waiterForXyz() functions to Xyz's header file. Implement waiter for (kernel mode) Event, and use it instead. --- nx/include/switch/kernel/event.h | 11 +++++++- nx/include/switch/kernel/thread.h | 7 +++++ nx/include/switch/kernel/uevent.h | 9 +++++++ nx/include/switch/kernel/utimer.h | 9 +++++++ nx/include/switch/kernel/wait.h | 45 +++++-------------------------- nx/source/kernel/event.c | 33 ++--------------------- nx/source/kernel/uevent.c | 3 ++- nx/source/kernel/wait.c | 38 ++++++++++++++++---------- 8 files changed, 70 insertions(+), 85 deletions(-) diff --git a/nx/include/switch/kernel/event.h b/nx/include/switch/kernel/event.h index 5f311931..867fea24 100644 --- a/nx/include/switch/kernel/event.h +++ b/nx/include/switch/kernel/event.h @@ -2,7 +2,7 @@ #pragma once #include "../types.h" #include "../result.h" -#include "../kernel/svc.h" +#include "wait.h" typedef struct { Handle revent; @@ -10,6 +10,15 @@ typedef struct { bool autoclear; } Event; +/// Creates a \ref Waiter for a kernel-mode event. +static inline Waiter waiterForEvent(Event* t) +{ + Waiter wait_obj; + wait_obj.type = t->autoclear ? WaiterType_HandleWithClear : WaiterType_Handle; + wait_obj.handle = t->revent; + return wait_obj; +} + Result eventCreate(Event* t, bool autoclear); void eventLoadRemote(Event* t, Handle handle, bool autoclear); void eventClose(Event* t); diff --git a/nx/include/switch/kernel/thread.h b/nx/include/switch/kernel/thread.h index 2b6c488c..e3e4ea15 100644 --- a/nx/include/switch/kernel/thread.h +++ b/nx/include/switch/kernel/thread.h @@ -7,6 +7,7 @@ #pragma once #include "../types.h" #include "../arm/thread_context.h" +#include "wait.h" /// Thread information structure. typedef struct { @@ -16,6 +17,12 @@ typedef struct { size_t stack_sz; ///< Stack size. } Thread; +/// Creates a \ref Waiter for a \ref Thread. +static inline Waiter waiterForThread(Thread* t) +{ + return waiterForHandle(t->handle); +} + /** * @brief Creates a thread. * @param t Thread information structure which will be filled in. diff --git a/nx/include/switch/kernel/uevent.h b/nx/include/switch/kernel/uevent.h index 4ea6d4b9..e26896c7 100644 --- a/nx/include/switch/kernel/uevent.h +++ b/nx/include/switch/kernel/uevent.h @@ -15,6 +15,15 @@ struct UEvent { bool auto_clear; }; +/// Creates a waiter for a user-mode event. +static inline Waiter waiterForUEvent(UEvent* e) +{ + Waiter wait_obj; + wait_obj.type = WaiterType_UEvent; + wait_obj.event = e; + return wait_obj; +} + /** * @brief Creates a user-mode event. * @param[out] e UEvent object. diff --git a/nx/include/switch/kernel/utimer.h b/nx/include/switch/kernel/utimer.h index 621ee3b6..fb7b98bd 100644 --- a/nx/include/switch/kernel/utimer.h +++ b/nx/include/switch/kernel/utimer.h @@ -21,6 +21,15 @@ struct UTimer { u64 interval; }; +/// Creates a waiter for a user-mode timer. +static inline Waiter waiterForUTimer(UTimer* t) +{ + Waiter wait_obj; + wait_obj.type = WaiterType_UTimer; + wait_obj.timer = t; + return wait_obj; +} + /** * @brief Creates a user-mode timer. * @param[out] t UTimer object. diff --git a/nx/include/switch/kernel/wait.h b/nx/include/switch/kernel/wait.h index 73cef748..d35d6476 100644 --- a/nx/include/switch/kernel/wait.h +++ b/nx/include/switch/kernel/wait.h @@ -6,12 +6,8 @@ */ #pragma once #include "mutex.h" -#include "event.h" -#include "thread.h" // Implementation details. -typedef struct UEvent UEvent; -typedef struct UTimer UTimer; typedef struct Waitable Waitable; typedef struct WaitableNode WaitableNode; @@ -26,24 +22,27 @@ struct Waitable { Mutex mutex; }; -// User-facing API starts here. typedef enum { WaiterType_Handle, + WaiterType_HandleWithClear, WaiterType_UTimer, WaiterType_UEvent, } WaiterType; +// User-facing API starts here. + +/// Waiter structure. typedef struct { WaiterType type; union { Handle handle; - UTimer* timer; - UEvent* event; + struct UTimer* timer; + struct UEvent* event; }; } Waiter; -/// Creates a waiter for a kernel-mode handle. +/// Creates a \ref Waiter for a kernel-mode \ref Handle. static inline Waiter waiterForHandle(Handle h) { Waiter wait_obj; @@ -52,36 +51,6 @@ static inline Waiter waiterForHandle(Handle h) return wait_obj; } -/// Creates a waiter for a user-mode timer. -static inline Waiter waiterForUTimer(UTimer* t) -{ - Waiter wait_obj; - wait_obj.type = WaiterType_UTimer; - wait_obj.timer = t; - return wait_obj; -} - -/// Creates a waiter for a user-mode event. -static inline Waiter waiterForUEvent(UEvent* e) -{ - Waiter wait_obj; - wait_obj.type = WaiterType_UEvent; - wait_obj.event = e; - return wait_obj; -} - -/// Creates a waiter for a kernel-mode event. -static inline Waiter waiterForEvent(Event* e) -{ - return waiterForHandle(e->revent); -} - -/// Creates a waiter for a thread exit. -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); diff --git a/nx/source/kernel/event.c b/nx/source/kernel/event.c index 29c378c5..81cf6bf9 100644 --- a/nx/source/kernel/event.c +++ b/nx/source/kernel/event.c @@ -3,6 +3,7 @@ #include "result.h" #include "arm/counter.h" #include "kernel/svc.h" +#include "kernel/wait.h" #include "kernel/event.h" Result eventCreate(Event* t, bool autoclear) @@ -29,37 +30,7 @@ void eventLoadRemote(Event* t, Handle handle, bool autoclear) Result eventWait(Event* t, u64 timeout) { - Result rc; - bool has_timeout = timeout != UINT64_MAX; - u64 deadline = 0; - - if (t->revent == INVALID_HANDLE) - return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - - if (has_timeout) - deadline = armGetSystemTick() + armNsToTicks(timeout); // timeout: ns->ticks - - do { - do { - u64 this_timeout = UINT64_MAX; - if (has_timeout) { - s64 remaining = deadline - armGetSystemTick(); - this_timeout = remaining > 0 ? armTicksToNs(remaining) : 0; // ticks->ns - } - - rc = svcWaitSynchronizationSingle(t->revent, this_timeout); - if (has_timeout && R_VALUE(rc) == KERNELRESULT(TimedOut)) - return rc; - } while (R_VALUE(rc) == KERNELRESULT(Cancelled)); - - if (R_FAILED(rc)) - break; - - if (t->autoclear) - rc = svcResetSignal(t->revent); - } while (R_VALUE(rc) == KERNELRESULT(InvalidState)); - - return rc; + return waitSingle(waiterForEvent(t), timeout); } Result eventFire(Event* t) diff --git a/nx/source/kernel/uevent.c b/nx/source/kernel/uevent.c index 6bfcbca9..64c9b31a 100644 --- a/nx/source/kernel/uevent.c +++ b/nx/source/kernel/uevent.c @@ -1,4 +1,5 @@ // Copyright 2018 plutoo +#include "result.h" #include "kernel/svc.h" #include "kernel/mutex.h" #include "kernel/uevent.h" @@ -33,7 +34,7 @@ Result _ueventTryAutoClear(UEvent* e) mutexLock(&e->waitable.mutex); if (e->auto_clear) { if (e->signal) - e->signal = 0; + e->signal = false; else rc = KERNELRESULT(Cancelled); } diff --git a/nx/source/kernel/wait.c b/nx/source/kernel/wait.c index 7944b1f9..5a2f7d46 100644 --- a/nx/source/kernel/wait.c +++ b/nx/source/kernel/wait.c @@ -5,9 +5,9 @@ #include "kernel/utimer.h" #include "kernel/uevent.h" #include "arm/counter.h" +#include "wait.h" #include "utimer.h" #include "uevent.h" -#include "wait.h" #include "../internal.h" #define MAX_WAIT 0x40 @@ -43,6 +43,12 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti bool added; switch (obj->type) { + case WaiterType_Handle: + case WaiterType_HandleWithClear: + // Add (real) handle to the array. + handles[i] = obj->handle; + break; + case WaiterType_UTimer: timer_tick = _utimerGetNextTick(obj->timer); @@ -70,7 +76,8 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti obj->timer, &waiters[i], i, &triggered_idx, own_thread_handle); - waiters_added |= 1ULL << i; + waiters_added |= 1UL << i; + handles[i] = dummy_handle; break; case WaiterType_UEvent: @@ -87,23 +94,26 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti } // If the event hasn't signalled, we added a listener. - waiters_added |= 1ULL << i; - break; - - case WaiterType_Handle: + waiters_added |= 1UL << i; + handles[i] = dummy_handle; break; } - - // Add handle for i:th object. - // If that object has no handle, add a dummy handle. - handles[i] = (obj->type == WaiterType_Handle) ? obj->handle : dummy_handle; } // Do the actual syscall. rc = svcWaitSynchronization(idx_out, handles, num_objects, end_tick==UINT64_MAX ? UINT64_MAX : armTicksToNs(end_tick)); - rc = R_VALUE(rc); - if (rc == KERNELRESULT(TimedOut)) { + if (R_SUCCEEDED(rc)) { + // Wait succeded, so that means an object having a real handle was signalled. + // Perform autoclear if needed. + if (objects[*idx_out].type == WaiterType_HandleWithClear) { + // Try to auto-clear the event. If it is not signalled, the kernel + // will return an error and thus we need to retry the wait. + rc = svcResetSignal(handles[*idx_out]); + if (R_VALUE(rc) == KERNELRESULT(InvalidState)) + rc = KERNELRESULT(Cancelled); + } + } else if (R_VALUE(rc) == KERNELRESULT(TimedOut)) { // If we hit the user-supplied timeout, we return the timeout error back to caller. if (end_tick_idx == -1) goto clean_up; @@ -113,7 +123,7 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti *idx_out = end_tick_idx; rc = 0; - } else if (rc == KERNELRESULT(Cancelled)) { + } else if (R_VALUE(rc) == KERNELRESULT(Cancelled)) { // If no listener filled in its own index, we return the cancelled error back to caller. // This only happens if user for some reason manually does a svcCancelSynchronization. // Check just in case. @@ -145,7 +155,7 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti clean_up: // Remove listeners. for (i = 0; i < num_objects; i ++) - if (waiters_added & (1ULL << i)) + if (waiters_added & (1UL << i)) _waiterNodeRemove(&waiters[i]); return rc;