Simplify WaiterNode, make it private. Improve UEvent autoclear logic.

This commit is contained in:
fincs 2018-12-14 21:27:15 +01:00 committed by fincs
parent 47b786bcea
commit c9ee12ce20
7 changed files with 53 additions and 56 deletions

View File

@ -13,11 +13,6 @@
typedef struct UEvent UEvent; typedef struct UEvent UEvent;
typedef struct UTimer UTimer; typedef struct UTimer UTimer;
typedef enum {
WaiterNodeType_Event,
WaiterNodeType_Timer,
} WaiterNodeType;
typedef struct Waitable Waitable; typedef struct Waitable Waitable;
typedef struct WaitableNode WaitableNode; typedef struct WaitableNode WaitableNode;
@ -26,19 +21,6 @@ struct WaitableNode {
WaitableNode* next; WaitableNode* next;
}; };
typedef struct {
WaitableNode node;
WaiterNodeType type;
Handle thread;
union {
Waitable* parent;
UEvent* parent_event;
UTimer* parent_timer;
};
s32 idx;
s32* idx_out;
} WaiterNode;
struct Waitable { struct Waitable {
WaitableNode list; WaitableNode list;
Mutex mutex; Mutex mutex;

View File

@ -2,7 +2,6 @@
#include "kernel/svc.h" #include "kernel/svc.h"
#include "kernel/mutex.h" #include "kernel/mutex.h"
#include "kernel/uevent.h" #include "kernel/uevent.h"
#include "wait.h"
#include "uevent.h" #include "uevent.h"
void ueventCreate(UEvent* e, bool auto_clear) void ueventCreate(UEvent* e, bool auto_clear)
@ -28,28 +27,31 @@ void ueventSignal(UEvent* e)
mutexUnlock(&e->waitable.mutex); mutexUnlock(&e->waitable.mutex);
} }
void _ueventTryAutoClear(UEvent* e) Result _ueventTryAutoClear(UEvent* e)
{ {
Result rc = 0;
mutexLock(&e->waitable.mutex); mutexLock(&e->waitable.mutex);
if (e->auto_clear) if (e->auto_clear) {
e->signal = false; if (e->signal)
e->signal = 0;
else
rc = KERNELRESULT(Cancelled);
}
mutexUnlock(&e->waitable.mutex); mutexUnlock(&e->waitable.mutex);
return rc;
} }
bool _ueventAddListener(UEvent* e, WaiterNode* w, s32 idx, s32* idx_out, Handle thread) bool _ueventAddListener(UEvent* e, WaiterNode* w, s32 idx, s32* idx_out, Handle thread)
{ {
mutexLock(&e->waitable.mutex); mutexLock(&e->waitable.mutex);
bool signalled = e->signal; bool can_add = !e->signal;
if (signalled) { if (can_add)
if (e->auto_clear) _waiterNodeAdd(w, &e->waitable, thread, idx, idx_out);
e->signal = false; else if (e->auto_clear)
} else { e->signal = false;
_waiterNodeCreate(w, WaiterNodeType_Event, &e->waitable, thread, idx, idx_out);
_waiterNodeAddToWaitable(w, &e->waitable);
}
mutexUnlock(&e->waitable.mutex); mutexUnlock(&e->waitable.mutex);
return !signalled; return can_add;
} }

View File

@ -1,6 +1,7 @@
// Copyright 2018 plutoo // Copyright 2018 plutoo
#pragma once #pragma once
#include "kernel/uevent.h" #include "kernel/uevent.h"
#include "wait.h"
void _ueventTryAutoClear(UEvent* e); Result _ueventTryAutoClear(UEvent* e);
bool _ueventAddListener(UEvent* e, WaiterNode* w, s32 idx, s32* idx_out, Handle thread); bool _ueventAddListener(UEvent* e, WaiterNode* w, s32 idx, s32* idx_out, Handle thread);

View File

@ -2,7 +2,6 @@
#include "kernel/svc.h" #include "kernel/svc.h"
#include "kernel/utimer.h" #include "kernel/utimer.h"
#include "arm/counter.h" #include "arm/counter.h"
#include "utimer.h"
#include "wait.h" #include "wait.h"
#define STOPPED 0 #define STOPPED 0
@ -77,9 +76,7 @@ u64 _utimerGetNextTick(UTimer* t)
void _utimerAddListener(UTimer* t, WaiterNode* w, s32 idx, s32* idx_out, Handle thread) void _utimerAddListener(UTimer* t, WaiterNode* w, s32 idx, s32* idx_out, Handle thread)
{ {
_waiterNodeCreate(w, WaiterNodeType_Timer, &t->waitable, thread, idx, idx_out);
mutexLock(&t->waitable.mutex); mutexLock(&t->waitable.mutex);
_waiterNodeAddToWaitable(w, &t->waitable); _waiterNodeAdd(w, &t->waitable, thread, idx, idx_out);
mutexUnlock(&t->waitable.mutex); mutexUnlock(&t->waitable.mutex);
} }

View File

@ -1,6 +1,7 @@
// Copyright 2018 plutoo // Copyright 2018 plutoo
#pragma once #pragma once
#include "kernel/utimer.h" #include "kernel/utimer.h"
#include "wait.h"
void _utimerRecalculate(UTimer* t, u64 old_tick); void _utimerRecalculate(UTimer* t, u64 old_tick);
u64 _utimerGetNextTick(UTimer* t); u64 _utimerGetNextTick(UTimer* t);

View File

@ -114,7 +114,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 (rc == KERNELRESULT(Cancelled)) {
// If no listener filled in its own index, we return the interrupt 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.
if (triggered_idx == -1) if (triggered_idx == -1)
@ -122,15 +122,21 @@ static Result waitImpl(s32* idx_out, Waiter* objects, size_t num_objects, u64 ti
// An event was signalled, or a timer was updated. // An event was signalled, or a timer was updated.
// So.. which is it? // So.. which is it?
switch (waiters[triggered_idx].type) { switch (objects[triggered_idx].type) {
case WaiterNodeType_Event: default:
_ueventTryAutoClear(waiters[triggered_idx].parent_event);
*idx_out = triggered_idx;
rc = 0;
break; break;
case WaiterNodeType_Timer: case WaiterType_UEvent:
// Try to auto-clear the event. If auto-clear is enabled but
// the event is not signalled, that means the state of the
// event has changed and thus we need to retry the wait.
rc = _ueventTryAutoClear(objects[triggered_idx].event);
if (R_SUCCEEDED(rc))
*idx_out = triggered_idx;
break;
case WaiterType_UTimer:
// Timer state changed, so we need to retry the wait.
rc = KERNELRESULT(Cancelled); rc = KERNELRESULT(Cancelled);
break; break;
} }
@ -140,7 +146,7 @@ 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 & (1ULL << i))
_waiterNodeFree(&waiters[i]); _waiterNodeRemove(&waiters[i]);
return rc; return rc;
} }

View File

@ -3,6 +3,16 @@
#include "kernel/mutex.h" #include "kernel/mutex.h"
#include "kernel/wait.h" #include "kernel/wait.h"
typedef struct WaiterNode WaiterNode;
struct WaiterNode {
WaitableNode node;
Waitable* parent;
Handle thread;
s32* idx_out;
s32 idx;
};
static inline void _waitableInitialize(Waitable* ww) static inline void _waitableInitialize(Waitable* ww)
{ {
mutexInit(&ww->mutex); mutexInit(&ww->mutex);
@ -30,25 +40,23 @@ static inline void _waitableSignalAllListeners(Waitable* ww)
} }
} }
static inline void _waiterNodeCreate( static inline void _waiterNodeAdd(
WaiterNode* w, WaiterNodeType type, Waitable* parent, Handle thread, WaiterNode* w, Waitable* parent, Handle thread,
s32 idx, s32* idx_out) s32 idx, s32* idx_out)
{ {
w->type = type; // Initialize WaiterNode fields
w->parent = parent; w->parent = parent;
w->thread = thread; w->thread = thread;
w->idx = idx; w->idx = idx;
w->idx_out = idx_out; w->idx_out = idx_out;
// Add WaiterNode to the parent's linked list
w->node.next = parent->list.next;
parent->list.next = &w->node;
w->node.prev = &parent->list;
} }
static inline void _waiterNodeAddToWaitable(WaiterNode* w, Waitable* ww) static inline void _waiterNodeRemove(WaiterNode* w)
{
w->node.next = ww->list.next;
ww->list.next = &w->node;
w->node.prev = &ww->list;
}
static inline void _waiterNodeFree(WaiterNode* w)
{ {
mutexLock(&w->parent->mutex); mutexLock(&w->parent->mutex);
w->node.prev->next = w->node.next; w->node.prev->next = w->node.next;