mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 20:42:44 +02:00
Stylefixes, part 1
This commit is contained in:
parent
eb7d835a79
commit
9144d78031
@ -1,29 +1,35 @@
|
||||
// Copyright 2018 plutoo
|
||||
/**
|
||||
* @file uevent.h
|
||||
* @brief User-mode event synchronization primitive.
|
||||
* @author plutoo
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../kernel/wait.h"
|
||||
#include "wait.h"
|
||||
|
||||
typedef struct UEvent UEvent;
|
||||
|
||||
struct UEvent
|
||||
{
|
||||
struct UEvent {
|
||||
Waitable waitable;
|
||||
bool signal;
|
||||
bool auto_clear;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a usermode event.
|
||||
* @brief Creates a user-mode event.
|
||||
* @param[out] e UEvent object.
|
||||
* @param[in] bool auto_clear Whether to automatically clear the event.
|
||||
* @note It is safe to wait on this event with several threads simultaneously.
|
||||
* @note If more than one thread is listening on it, at least one thread will get the signal. No other guarantees.
|
||||
*/
|
||||
void ueventCreate(UEvent* e, bool auto_clear);
|
||||
|
||||
/**
|
||||
* @brief Clears the event signal.
|
||||
* @param[in] e UEvent object.
|
||||
*/
|
||||
void ueventClear(UEvent* e);
|
||||
|
||||
/**
|
||||
* @brief Signals the event.
|
||||
* @param[in] e UEvent object.
|
||||
|
@ -1,16 +1,20 @@
|
||||
// Copyright 2018 plutoo
|
||||
/**
|
||||
* @file uevent.h
|
||||
* @brief User-mode timer synchronization primitive.
|
||||
* @author plutoo
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../kernel/wait.h"
|
||||
#include "wait.h"
|
||||
|
||||
typedef struct UTimer UTimer;
|
||||
|
||||
typedef enum {
|
||||
TimerType_OneShot,
|
||||
TimerType_Repeating
|
||||
TimerType_Repeating,
|
||||
} TimerType;
|
||||
|
||||
struct UTimer
|
||||
{
|
||||
struct UTimer {
|
||||
Waitable waitable;
|
||||
TimerType type;
|
||||
u64 next_tick;
|
||||
@ -18,7 +22,7 @@ struct UTimer
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates a usermode timer.
|
||||
* @brief Creates a user-mode timer.
|
||||
* @param[out] t UTimer object.
|
||||
* @param[in] interval Interval (in nanoseconds).
|
||||
* @param[in] type Timer type (repeating or one-shot)
|
||||
@ -27,11 +31,13 @@ struct UTimer
|
||||
* @note For a repeating timer: If the timer triggers twice before you wait on it, you will only get one signal.
|
||||
*/
|
||||
void utimerCreate(UTimer* t, u64 interval, TimerType type);
|
||||
|
||||
/**
|
||||
* @brief Starts the timer.
|
||||
* @param[in] t UTimer object.
|
||||
*/
|
||||
void utimerStart(UTimer* t);
|
||||
|
||||
/**
|
||||
* @brief Stops the timer.
|
||||
* @param[in] t UTimer object.
|
||||
|
@ -1,8 +1,13 @@
|
||||
// Copyright 2018 plutoo
|
||||
/**
|
||||
* @file wait.h
|
||||
* @brief User mode synchronization primitive waiting operations.
|
||||
* @author plutoo
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
#pragma once
|
||||
#include "../kernel/mutex.h"
|
||||
#include "../kernel/event.h"
|
||||
#include "../kernel/thread.h"
|
||||
#include "mutex.h"
|
||||
#include "event.h"
|
||||
#include "thread.h"
|
||||
|
||||
// Implementation details.
|
||||
typedef struct UEvent UEvent;
|
||||
@ -10,14 +15,13 @@ typedef struct UTimer UTimer;
|
||||
|
||||
typedef enum {
|
||||
WaiterNodeType_Event,
|
||||
WaiterNodeType_Timer
|
||||
WaiterNodeType_Timer,
|
||||
} WaiterNodeType;
|
||||
|
||||
typedef struct Waitable Waitable;
|
||||
typedef struct WaitableNode WaitableNode;
|
||||
|
||||
struct WaitableNode
|
||||
{
|
||||
struct WaitableNode {
|
||||
WaitableNode* prev;
|
||||
WaitableNode* next;
|
||||
};
|
||||
@ -35,8 +39,7 @@ typedef struct {
|
||||
size_t* idx_out;
|
||||
} WaiterNode;
|
||||
|
||||
struct Waitable
|
||||
{
|
||||
struct Waitable {
|
||||
WaitableNode list;
|
||||
Mutex mutex;
|
||||
};
|
||||
@ -58,7 +61,7 @@ typedef struct {
|
||||
};
|
||||
} Waiter;
|
||||
|
||||
/// Creates a waiter for a kernelmode handle.
|
||||
/// Creates a waiter for a kernel-mode handle.
|
||||
static inline Waiter waiterForHandle(Handle h)
|
||||
{
|
||||
Waiter wait_obj;
|
||||
@ -67,7 +70,7 @@ static inline Waiter waiterForHandle(Handle h)
|
||||
return wait_obj;
|
||||
}
|
||||
|
||||
/// Creates a waiter for a usermode timer.
|
||||
/// Creates a waiter for a user-mode timer.
|
||||
static inline Waiter waiterForUTimer(UTimer* t)
|
||||
{
|
||||
Waiter wait_obj;
|
||||
@ -76,7 +79,7 @@ static inline Waiter waiterForUTimer(UTimer* t)
|
||||
return wait_obj;
|
||||
}
|
||||
|
||||
/// Creates a waiter for a usermode event.
|
||||
/// Creates a waiter for a user-mode event.
|
||||
static inline Waiter waiterForUEvent(UEvent* e)
|
||||
{
|
||||
Waiter wait_obj;
|
||||
@ -85,13 +88,15 @@ static inline Waiter waiterForUEvent(UEvent* e)
|
||||
return wait_obj;
|
||||
}
|
||||
|
||||
/// Creates a waiter for a kernelmode event.
|
||||
static inline Waiter waiterForEvent(Event* e) {
|
||||
/// 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) {
|
||||
static inline Waiter waiterForThreadExit(Thread* t)
|
||||
{
|
||||
return waiterForHandle(t->handle);
|
||||
}
|
||||
|
||||
@ -121,7 +126,8 @@ Result waitNHandle(s32* idx_out, Handle* handles, size_t num_handles, u64 timeou
|
||||
* @param[in] w The waiter to wait for.
|
||||
* @param[in] timeout Timeout (in nanoseconds).
|
||||
*/
|
||||
static inline Result waitSingle(Waiter w, u64 timeout) {
|
||||
static inline Result waitSingle(Waiter w, u64 timeout)
|
||||
{
|
||||
s32 idx;
|
||||
return waitMulti(&idx, timeout, w);
|
||||
}
|
||||
@ -131,7 +137,8 @@ static inline Result waitSingle(Waiter w, u64 timeout) {
|
||||
* @param[in] h The handle to wait for.
|
||||
* @param[in] timeout Timeout (in nanoseconds).
|
||||
*/
|
||||
static inline Result waitSingleHandle(Handle h, u64 timeout) {
|
||||
static inline Result waitSingleHandle(Handle h, u64 timeout)
|
||||
{
|
||||
s32 idx;
|
||||
return waitMultiHandle(&idx, timeout, h);
|
||||
}
|
||||
|
@ -31,9 +31,8 @@ void ueventSignal(UEvent* e)
|
||||
void _ueventTryAutoClear(UEvent* e)
|
||||
{
|
||||
mutexLock(&e->waitable.mutex);
|
||||
if (e->auto_clear) {
|
||||
if (e->auto_clear)
|
||||
e->signal = false;
|
||||
}
|
||||
mutexUnlock(&e->waitable.mutex);
|
||||
}
|
||||
|
||||
@ -44,21 +43,13 @@ bool _ueventAddListener(UEvent* e, WaiterNode* w, size_t idx, size_t* idx_out, H
|
||||
mutexLock(&e->waitable.mutex);
|
||||
|
||||
bool signalled = e->signal;
|
||||
bool ret;
|
||||
|
||||
if (signalled)
|
||||
{
|
||||
if (e->auto_clear) {
|
||||
if (signalled) {
|
||||
if (e->auto_clear)
|
||||
e->signal = false;
|
||||
}
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
_waiterNodeAddToWaitable(w, &e->waitable);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
mutexUnlock(&e->waitable.mutex);
|
||||
return ret;
|
||||
return !signalled;
|
||||
}
|
||||
|
@ -20,8 +20,7 @@ void utimerStart(UTimer* t)
|
||||
{
|
||||
mutexLock(&t->waitable.mutex);
|
||||
|
||||
if (t->next_tick == STOPPED)
|
||||
{
|
||||
if (t->next_tick == STOPPED) {
|
||||
u64 new_tick = armGetSystemTick() + t->interval;
|
||||
t->next_tick = new_tick;
|
||||
_waitableSignalAllListeners(&t->waitable);
|
||||
@ -34,8 +33,7 @@ void utimerStop(UTimer* t)
|
||||
{
|
||||
mutexLock(&t->waitable.mutex);
|
||||
|
||||
if (t->next_tick != STOPPED)
|
||||
{
|
||||
if (t->next_tick != STOPPED) {
|
||||
t->next_tick = STOPPED;
|
||||
_waitableSignalAllListeners(&t->waitable);
|
||||
}
|
||||
@ -47,19 +45,17 @@ void _utimerRecalculate(UTimer* t, u64 old_tick)
|
||||
{
|
||||
mutexLock(&t->waitable.mutex);
|
||||
|
||||
if (t->next_tick == old_tick)
|
||||
{
|
||||
if (t->next_tick == old_tick) {
|
||||
u64 interval = t->interval;
|
||||
u64 new_tick = 0;
|
||||
|
||||
switch (t->type)
|
||||
{
|
||||
case TimerType_OneShot:
|
||||
new_tick = STOPPED;
|
||||
break;
|
||||
case TimerType_Repeating:
|
||||
new_tick = old_tick + ((svcGetSystemTick() - old_tick + interval - 1)/interval)*interval;
|
||||
break;
|
||||
switch (t->type) {
|
||||
case TimerType_OneShot:
|
||||
new_tick = STOPPED;
|
||||
break;
|
||||
case TimerType_Repeating:
|
||||
new_tick = old_tick + ((svcGetSystemTick() - old_tick + interval - 1)/interval)*interval;
|
||||
break;
|
||||
}
|
||||
|
||||
t->next_tick = new_tick;
|
||||
|
@ -37,69 +37,61 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
|
||||
s32 end_tick_idx = -1;
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<num_objects; i++)
|
||||
{
|
||||
for (i = 0; i < num_objects; i ++) {
|
||||
Waiter* obj = &objects[i];
|
||||
u64 timer_tick;
|
||||
bool added;
|
||||
|
||||
switch (obj->type)
|
||||
{
|
||||
case WaiterType_UTimer:
|
||||
switch (obj->type) {
|
||||
case WaiterType_UTimer:
|
||||
timer_tick = _utimerGetNextTick(obj->timer);
|
||||
|
||||
timer_tick = _utimerGetNextTick(obj->timer);
|
||||
// Skip timer if stopped.
|
||||
if (timer_tick != 0) {
|
||||
// If the timer already signalled, we're done.
|
||||
if (timer_tick < cur_tick) {
|
||||
_utimerRecalculate(obj->timer, timer_tick);
|
||||
|
||||
// Skip timer if stopped.
|
||||
if (timer_tick != 0)
|
||||
{
|
||||
// If the timer already signalled, we're done.
|
||||
if (timer_tick < cur_tick)
|
||||
{
|
||||
_utimerRecalculate(obj->timer, timer_tick);
|
||||
*idx_out = i;
|
||||
rc = 0;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
// Override the user-supplied timeout if timer would fire before that.
|
||||
if ((timer_tick - cur_tick) < end_tick) {
|
||||
end_tick = timer_tick - cur_tick;
|
||||
end_tick_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Always add a listener on the timer,
|
||||
// If the timer is started/stopped we want to detect that.
|
||||
_utimerAddListener(
|
||||
obj->timer, &waiters[num_waiters], num_waiters, &triggered_idx,
|
||||
own_thread_handle);
|
||||
|
||||
num_waiters++;
|
||||
break;
|
||||
|
||||
case WaiterType_UEvent:
|
||||
// Try to add a listener to the event, if it hasn't already signalled.
|
||||
added = _ueventAddListener(
|
||||
obj->event, &waiters[num_waiters], num_waiters, &triggered_idx,
|
||||
own_thread_handle);
|
||||
|
||||
// If the event already happened, we're done.
|
||||
if (!added) {
|
||||
*idx_out = i;
|
||||
rc = 0;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
// Override the user-supplied timeout if timer would fire before that.
|
||||
if ((timer_tick - cur_tick) < end_tick)
|
||||
{
|
||||
end_tick = timer_tick - cur_tick;
|
||||
end_tick_idx = i;
|
||||
}
|
||||
}
|
||||
// If the event hasn't signalled, we added a listener.
|
||||
num_waiters++;
|
||||
break;
|
||||
|
||||
// Always add a listener on the timer,
|
||||
// If the timer is started/stopped we want to detect that.
|
||||
_utimerAddListener(
|
||||
obj->timer, &waiters[num_waiters], num_waiters, &triggered_idx,
|
||||
own_thread_handle);
|
||||
|
||||
num_waiters++;
|
||||
break;
|
||||
|
||||
case WaiterType_UEvent:
|
||||
|
||||
// Try to add a listener to the event, if it hasn't already signalled.
|
||||
added = _ueventAddListener(
|
||||
obj->event, &waiters[num_waiters], num_waiters, &triggered_idx,
|
||||
own_thread_handle);
|
||||
|
||||
// If the event already happened, we're done.
|
||||
if (!added)
|
||||
{
|
||||
*idx_out = i;
|
||||
rc = 0;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
// If the event hasn't signalled, we added a listener.
|
||||
num_waiters++;
|
||||
break;
|
||||
|
||||
case WaiterType_Handle:
|
||||
break;
|
||||
case WaiterType_Handle:
|
||||
break;
|
||||
}
|
||||
|
||||
// Add handle for i:th object.
|
||||
@ -110,21 +102,17 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
|
||||
// Do the actual syscall.
|
||||
rc = svcWaitSynchronization(idx_out, handles, num_objects, armTicksToNs(end_tick));
|
||||
|
||||
if (rc == KernelError_Timeout)
|
||||
{
|
||||
if (rc == KernelError_Timeout) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// If not, it means a timer triggered the timeout.
|
||||
_utimerRecalculate(objects[end_tick_idx].timer, end_tick + cur_tick);
|
||||
|
||||
*idx_out = end_tick_idx;
|
||||
rc = 0;
|
||||
}
|
||||
else if (rc == KernelError_Canceled)
|
||||
{
|
||||
} 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.
|
||||
// Check just in case.
|
||||
@ -133,65 +121,60 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
|
||||
|
||||
// An event was signalled, or a timer was updated.
|
||||
// So.. which is it?
|
||||
switch (waiters[triggered_idx].type)
|
||||
{
|
||||
case WaiterNodeType_Event:
|
||||
_ueventTryAutoClear(waiters[triggered_idx].parent_event);
|
||||
switch (waiters[triggered_idx].type) {
|
||||
case WaiterNodeType_Event:
|
||||
_ueventTryAutoClear(waiters[triggered_idx].parent_event);
|
||||
|
||||
*idx_out = triggered_idx;
|
||||
rc = 0;
|
||||
break;
|
||||
*idx_out = triggered_idx;
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
case WaiterNodeType_Timer:
|
||||
rc = KernelError_Canceled;
|
||||
break;
|
||||
case WaiterNodeType_Timer:
|
||||
rc = KernelError_Canceled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
clean_up:
|
||||
|
||||
// Remove listeners.
|
||||
for (i=0; i<num_waiters; i++) {
|
||||
for (i = 0; i < num_waiters; i ++)
|
||||
_waiterNodeFree(&waiters[i]);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static Result _waitLoop(WaitImplFunc wait, s32* idx_out, void* objects, size_t num_objects, u64 timeout)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
Result rc;
|
||||
do {
|
||||
u64 cur_tick = armGetSystemTick();
|
||||
Result rc = wait(idx_out, objects, num_objects, timeout);
|
||||
rc = wait(idx_out, objects, num_objects, timeout);
|
||||
|
||||
if (rc == KernelError_Canceled)
|
||||
{
|
||||
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.
|
||||
|
||||
// Adjust timeout..
|
||||
if (timeout != -1)
|
||||
{
|
||||
if (timeout != -1) {
|
||||
u64 time_spent = armTicksToNs(armGetSystemTick() - cur_tick);
|
||||
|
||||
if (time_spent >= timeout) {
|
||||
return KernelError_Timeout;
|
||||
}
|
||||
|
||||
timeout -= time_spent;
|
||||
if (time_spent < timeout)
|
||||
timeout -= time_spent;
|
||||
else
|
||||
rc = KernelError_Timeout;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
} while (rc == KernelError_Canceled);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
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 waitN(s32* idx_out, Waiter* objects, size_t num_objects, u64 timeout)
|
||||
{
|
||||
return _waitLoop((WaitImplFunc)waitImpl, idx_out, 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);
|
||||
Result waitNHandle(s32* idx_out, Handle* handles, size_t num_handles, u64 timeout)
|
||||
{
|
||||
return _waitLoop((WaitImplFunc)svcWaitSynchronization, idx_out, handles, num_handles, timeout);
|
||||
}
|
||||
|
@ -15,8 +15,7 @@ static inline void _waitableSignalAllListeners(Waitable* ww)
|
||||
WaitableNode* node = &ww->list;
|
||||
WaitableNode* end = node;
|
||||
|
||||
while (node->next != end)
|
||||
{
|
||||
while (node->next != end) {
|
||||
node = node->next;
|
||||
WaiterNode* w = (WaiterNode*) node;
|
||||
|
||||
@ -26,9 +25,8 @@ static inline void _waitableSignalAllListeners(Waitable* ww)
|
||||
bool sent_idx = __atomic_compare_exchange_n(
|
||||
w->idx_out, &minus_one, w->idx, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
|
||||
if (sent_idx) {
|
||||
if (sent_idx)
|
||||
svcCancelSynchronization(w->thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user