mirror of
https://github.com/switchbrew/libnx.git
synced 2025-07-06 11:22: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
|
#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);
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user