mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
77 lines
1.9 KiB
C
77 lines
1.9 KiB
C
// Copyright 2018 plutoo
|
|
#pragma once
|
|
#include "kernel/svc.h"
|
|
#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;
|
|
};
|
|
|
|
struct WaitableMethods {
|
|
bool (* beginWait)(Waitable* ww, WaiterNode* w, u64 cur_tick, u64* next_tick);
|
|
Result (* onTimeout)(Waitable* ww, u64 old_tick);
|
|
Result (* onSignal)(Waitable* ww);
|
|
};
|
|
|
|
static inline void _waitableInitialize(Waitable* ww, const WaitableMethods* vt)
|
|
{
|
|
mutexInit(&ww->mutex);
|
|
ww->vt = vt;
|
|
ww->list.next = &ww->list;
|
|
ww->list.prev = &ww->list;
|
|
}
|
|
|
|
static inline void _waitableSignalAllListeners(Waitable* ww)
|
|
{
|
|
WaitableNode* node = &ww->list;
|
|
WaitableNode* end = node;
|
|
|
|
while (node->next != end) {
|
|
node = node->next;
|
|
WaiterNode* w = (WaiterNode*) node;
|
|
|
|
// Try to swap -1 => idx on the waiter thread.
|
|
// If another waitable signals simultaneously only one will win the race and insert its own idx.
|
|
s32 minus_one = -1;
|
|
bool sent_idx = __atomic_compare_exchange_n(
|
|
w->idx_out, &minus_one, w->idx, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
|
|
|
if (sent_idx)
|
|
svcCancelSynchronization(w->thread);
|
|
}
|
|
}
|
|
|
|
static inline void _waiterNodeInitialize(
|
|
WaiterNode* w, Waitable* parent, Handle thread,
|
|
s32 idx, s32* idx_out)
|
|
{
|
|
// Initialize WaiterNode fields
|
|
w->parent = parent;
|
|
w->thread = thread;
|
|
w->idx = idx;
|
|
w->idx_out = idx_out;
|
|
}
|
|
|
|
static inline void _waiterNodeAdd(WaiterNode* w)
|
|
{
|
|
// Add WaiterNode to the parent's linked list
|
|
w->node.next = w->parent->list.next;
|
|
w->parent->list.next = &w->node;
|
|
w->node.prev = &w->parent->list;
|
|
}
|
|
|
|
static inline void _waiterNodeRemove(WaiterNode* w)
|
|
{
|
|
mutexLock(&w->parent->mutex);
|
|
w->node.prev->next = w->node.next;
|
|
w->node.next->prev = w->node.prev;
|
|
mutexUnlock(&w->parent->mutex);
|
|
}
|