Move waiterForXyz() functions to Xyz's header file. Implement waiter for (kernel mode) Event, and use it instead.

This commit is contained in:
fincs 2018-12-14 22:32:50 +01:00
parent 9462acd55b
commit 04fff2fc3b
8 changed files with 70 additions and 85 deletions

View File

@ -2,7 +2,7 @@
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../result.h" #include "../result.h"
#include "../kernel/svc.h" #include "wait.h"
typedef struct { typedef struct {
Handle revent; Handle revent;
@ -10,6 +10,15 @@ typedef struct {
bool autoclear; bool autoclear;
} Event; } 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); Result eventCreate(Event* t, bool autoclear);
void eventLoadRemote(Event* t, Handle handle, bool autoclear); void eventLoadRemote(Event* t, Handle handle, bool autoclear);
void eventClose(Event* t); void eventClose(Event* t);

View File

@ -7,6 +7,7 @@
#pragma once #pragma once
#include "../types.h" #include "../types.h"
#include "../arm/thread_context.h" #include "../arm/thread_context.h"
#include "wait.h"
/// Thread information structure. /// Thread information structure.
typedef struct { typedef struct {
@ -16,6 +17,12 @@ typedef struct {
size_t stack_sz; ///< Stack size. size_t stack_sz; ///< Stack size.
} Thread; } Thread;
/// Creates a \ref Waiter for a \ref Thread.
static inline Waiter waiterForThread(Thread* t)
{
return waiterForHandle(t->handle);
}
/** /**
* @brief Creates a thread. * @brief Creates a thread.
* @param t Thread information structure which will be filled in. * @param t Thread information structure which will be filled in.

View File

@ -15,6 +15,15 @@ struct UEvent {
bool auto_clear; 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. * @brief Creates a user-mode event.
* @param[out] e UEvent object. * @param[out] e UEvent object.

View File

@ -21,6 +21,15 @@ struct UTimer {
u64 interval; 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. * @brief Creates a user-mode timer.
* @param[out] t UTimer object. * @param[out] t UTimer object.

View File

@ -6,12 +6,8 @@
*/ */
#pragma once #pragma once
#include "mutex.h" #include "mutex.h"
#include "event.h"
#include "thread.h"
// Implementation details. // Implementation details.
typedef struct UEvent UEvent;
typedef struct UTimer UTimer;
typedef struct Waitable Waitable; typedef struct Waitable Waitable;
typedef struct WaitableNode WaitableNode; typedef struct WaitableNode WaitableNode;
@ -26,24 +22,27 @@ struct Waitable {
Mutex mutex; Mutex mutex;
}; };
// User-facing API starts here.
typedef enum { typedef enum {
WaiterType_Handle, WaiterType_Handle,
WaiterType_HandleWithClear,
WaiterType_UTimer, WaiterType_UTimer,
WaiterType_UEvent, WaiterType_UEvent,
} WaiterType; } WaiterType;
// User-facing API starts here.
/// Waiter structure.
typedef struct { typedef struct {
WaiterType type; WaiterType type;
union { union {
Handle handle; Handle handle;
UTimer* timer; struct UTimer* timer;
UEvent* event; struct UEvent* event;
}; };
} Waiter; } 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) static inline Waiter waiterForHandle(Handle h)
{ {
Waiter wait_obj; Waiter wait_obj;
@ -52,36 +51,6 @@ static inline Waiter waiterForHandle(Handle h)
return wait_obj; 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 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); Result waitNHandle(s32* idx_out, Handle* handles, size_t num_handles, u64 timeout);

View File

@ -3,6 +3,7 @@
#include "result.h" #include "result.h"
#include "arm/counter.h" #include "arm/counter.h"
#include "kernel/svc.h" #include "kernel/svc.h"
#include "kernel/wait.h"
#include "kernel/event.h" #include "kernel/event.h"
Result eventCreate(Event* t, bool autoclear) 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 eventWait(Event* t, u64 timeout)
{ {
Result rc; return waitSingle(waiterForEvent(t), timeout);
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;
} }
Result eventFire(Event* t) Result eventFire(Event* t)

View File

@ -1,4 +1,5 @@
// Copyright 2018 plutoo // Copyright 2018 plutoo
#include "result.h"
#include "kernel/svc.h" #include "kernel/svc.h"
#include "kernel/mutex.h" #include "kernel/mutex.h"
#include "kernel/uevent.h" #include "kernel/uevent.h"
@ -33,7 +34,7 @@ Result _ueventTryAutoClear(UEvent* e)
mutexLock(&e->waitable.mutex); mutexLock(&e->waitable.mutex);
if (e->auto_clear) { if (e->auto_clear) {
if (e->signal) if (e->signal)
e->signal = 0; e->signal = false;
else else
rc = KERNELRESULT(Cancelled); rc = KERNELRESULT(Cancelled);
} }

View File

@ -5,9 +5,9 @@
#include "kernel/utimer.h" #include "kernel/utimer.h"
#include "kernel/uevent.h" #include "kernel/uevent.h"
#include "arm/counter.h" #include "arm/counter.h"
#include "wait.h"
#include "utimer.h" #include "utimer.h"
#include "uevent.h" #include "uevent.h"
#include "wait.h"
#include "../internal.h" #include "../internal.h"
#define MAX_WAIT 0x40 #define MAX_WAIT 0x40
@ -43,6 +43,12 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
bool added; bool added;
switch (obj->type) { switch (obj->type) {
case WaiterType_Handle:
case WaiterType_HandleWithClear:
// Add (real) handle to the array.
handles[i] = obj->handle;
break;
case WaiterType_UTimer: case WaiterType_UTimer:
timer_tick = _utimerGetNextTick(obj->timer); 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, obj->timer, &waiters[i], i, &triggered_idx,
own_thread_handle); own_thread_handle);
waiters_added |= 1ULL << i; waiters_added |= 1UL << i;
handles[i] = dummy_handle;
break; break;
case WaiterType_UEvent: 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. // If the event hasn't signalled, we added a listener.
waiters_added |= 1ULL << i; waiters_added |= 1UL << i;
break; handles[i] = dummy_handle;
case WaiterType_Handle:
break; 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. // Do the actual syscall.
rc = svcWaitSynchronization(idx_out, handles, num_objects, end_tick==UINT64_MAX ? UINT64_MAX : armTicksToNs(end_tick)); 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 we hit the user-supplied timeout, we return the timeout error back to caller.
if (end_tick_idx == -1) if (end_tick_idx == -1)
goto clean_up; 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; *idx_out = end_tick_idx;
rc = 0; 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. // 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. // This only happens if user for some reason manually does a svcCancelSynchronization.
// Check just in case. // Check just in case.
@ -145,7 +155,7 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
clean_up: clean_up:
// Remove listeners. // Remove listeners.
for (i = 0; i < num_objects; i ++) for (i = 0; i < num_objects; i ++)
if (waiters_added & (1ULL << i)) if (waiters_added & (1UL << i))
_waiterNodeRemove(&waiters[i]); _waiterNodeRemove(&waiters[i]);
return rc; return rc;