mirror of
https://github.com/switchbrew/libnx.git
synced 2025-07-06 03:12:15 +02:00
Move waiterForXyz() functions to Xyz's header file. Implement waiter for (kernel mode) Event, and use it instead.
This commit is contained in:
parent
9462acd55b
commit
04fff2fc3b
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user