Stylefixes, part 1

This commit is contained in:
fincs 2018-12-14 13:57:44 +01:00 committed by fincs
parent eb7d835a79
commit 9144d78031
7 changed files with 137 additions and 150 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}
}
}