mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-24 05:42:40 +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 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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user