mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-23 21:32:39 +02:00
Simplify WaiterNode, make it private. Improve UEvent autoclear logic.
This commit is contained in:
parent
47b786bcea
commit
c9ee12ce20
@ -13,11 +13,6 @@
|
||||
typedef struct UEvent UEvent;
|
||||
typedef struct UTimer UTimer;
|
||||
|
||||
typedef enum {
|
||||
WaiterNodeType_Event,
|
||||
WaiterNodeType_Timer,
|
||||
} WaiterNodeType;
|
||||
|
||||
typedef struct Waitable Waitable;
|
||||
typedef struct WaitableNode WaitableNode;
|
||||
|
||||
@ -26,19 +21,6 @@ struct WaitableNode {
|
||||
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 {
|
||||
WaitableNode list;
|
||||
Mutex mutex;
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "kernel/svc.h"
|
||||
#include "kernel/mutex.h"
|
||||
#include "kernel/uevent.h"
|
||||
#include "wait.h"
|
||||
#include "uevent.h"
|
||||
|
||||
void ueventCreate(UEvent* e, bool auto_clear)
|
||||
@ -28,28 +27,31 @@ void ueventSignal(UEvent* e)
|
||||
mutexUnlock(&e->waitable.mutex);
|
||||
}
|
||||
|
||||
void _ueventTryAutoClear(UEvent* e)
|
||||
Result _ueventTryAutoClear(UEvent* e)
|
||||
{
|
||||
Result rc = 0;
|
||||
mutexLock(&e->waitable.mutex);
|
||||
if (e->auto_clear)
|
||||
e->signal = false;
|
||||
if (e->auto_clear) {
|
||||
if (e->signal)
|
||||
e->signal = 0;
|
||||
else
|
||||
rc = KERNELRESULT(Cancelled);
|
||||
}
|
||||
mutexUnlock(&e->waitable.mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool _ueventAddListener(UEvent* e, WaiterNode* w, s32 idx, s32* idx_out, Handle thread)
|
||||
{
|
||||
mutexLock(&e->waitable.mutex);
|
||||
|
||||
bool signalled = e->signal;
|
||||
bool can_add = !e->signal;
|
||||
|
||||
if (signalled) {
|
||||
if (e->auto_clear)
|
||||
e->signal = false;
|
||||
} else {
|
||||
_waiterNodeCreate(w, WaiterNodeType_Event, &e->waitable, thread, idx, idx_out);
|
||||
_waiterNodeAddToWaitable(w, &e->waitable);
|
||||
}
|
||||
if (can_add)
|
||||
_waiterNodeAdd(w, &e->waitable, thread, idx, idx_out);
|
||||
else if (e->auto_clear)
|
||||
e->signal = false;
|
||||
|
||||
mutexUnlock(&e->waitable.mutex);
|
||||
return !signalled;
|
||||
return can_add;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright 2018 plutoo
|
||||
#pragma once
|
||||
#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);
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "kernel/svc.h"
|
||||
#include "kernel/utimer.h"
|
||||
#include "arm/counter.h"
|
||||
#include "utimer.h"
|
||||
#include "wait.h"
|
||||
|
||||
#define STOPPED 0
|
||||
@ -77,9 +76,7 @@ u64 _utimerGetNextTick(UTimer* t)
|
||||
|
||||
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);
|
||||
_waiterNodeAddToWaitable(w, &t->waitable);
|
||||
_waiterNodeAdd(w, &t->waitable, thread, idx, idx_out);
|
||||
mutexUnlock(&t->waitable.mutex);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Copyright 2018 plutoo
|
||||
#pragma once
|
||||
#include "kernel/utimer.h"
|
||||
#include "wait.h"
|
||||
|
||||
void _utimerRecalculate(UTimer* t, u64 old_tick);
|
||||
u64 _utimerGetNextTick(UTimer* t);
|
||||
|
@ -114,7 +114,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)) {
|
||||
// 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.
|
||||
// Check just in case.
|
||||
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.
|
||||
// So.. which is it?
|
||||
switch (waiters[triggered_idx].type) {
|
||||
case WaiterNodeType_Event:
|
||||
_ueventTryAutoClear(waiters[triggered_idx].parent_event);
|
||||
|
||||
*idx_out = triggered_idx;
|
||||
rc = 0;
|
||||
switch (objects[triggered_idx].type) {
|
||||
default:
|
||||
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);
|
||||
break;
|
||||
}
|
||||
@ -140,7 +146,7 @@ clean_up:
|
||||
// Remove listeners.
|
||||
for (i = 0; i < num_objects; i ++)
|
||||
if (waiters_added & (1ULL << i))
|
||||
_waiterNodeFree(&waiters[i]);
|
||||
_waiterNodeRemove(&waiters[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -3,6 +3,16 @@
|
||||
#include "kernel/mutex.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)
|
||||
{
|
||||
mutexInit(&ww->mutex);
|
||||
@ -30,25 +40,23 @@ static inline void _waitableSignalAllListeners(Waitable* ww)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _waiterNodeCreate(
|
||||
WaiterNode* w, WaiterNodeType type, Waitable* parent, Handle thread,
|
||||
static inline void _waiterNodeAdd(
|
||||
WaiterNode* w, Waitable* parent, Handle thread,
|
||||
s32 idx, s32* idx_out)
|
||||
{
|
||||
w->type = type;
|
||||
// Initialize WaiterNode fields
|
||||
w->parent = parent;
|
||||
w->thread = thread;
|
||||
w->idx = idx;
|
||||
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)
|
||||
{
|
||||
w->node.next = ww->list.next;
|
||||
ww->list.next = &w->node;
|
||||
w->node.prev = &ww->list;
|
||||
}
|
||||
|
||||
static inline void _waiterNodeFree(WaiterNode* w)
|
||||
static inline void _waiterNodeRemove(WaiterNode* w)
|
||||
{
|
||||
mutexLock(&w->parent->mutex);
|
||||
w->node.prev->next = w->node.next;
|
||||
|
Loading…
Reference in New Issue
Block a user