libnx/nx/source/kernel/uevent.c

82 lines
1.9 KiB
C

// Copyright 2018 plutoo
#include "result.h"
#include "kernel/svc.h"
#include "kernel/mutex.h"
#include "kernel/uevent.h"
#include "wait.h"
static bool _ueventBeginWait(Waitable* ww, WaiterNode* w, u64 cur_tick, u64* next_tick);
static Result _ueventOnTimeout(Waitable* ww, u64 old_tick);
static Result _ueventOnSignal(Waitable* ww);
static const WaitableMethods g_ueventVt = {
.beginWait = _ueventBeginWait,
.onTimeout = _ueventOnTimeout,
.onSignal = _ueventOnSignal,
};
void ueventCreate(UEvent* e, bool auto_clear)
{
_waitableInitialize(&e->waitable, &g_ueventVt);
e->signal = false;
e->auto_clear = auto_clear;
}
void ueventClear(UEvent* e)
{
mutexLock(&e->waitable.mutex);
e->signal = false;
mutexUnlock(&e->waitable.mutex);
}
void ueventSignal(UEvent* e)
{
mutexLock(&e->waitable.mutex);
e->signal = true;
_waitableSignalAllListeners(&e->waitable);
mutexUnlock(&e->waitable.mutex);
}
Result _ueventOnSignal(Waitable* ww)
{
UEvent* e = (UEvent*)ww;
Result rc = 0;
mutexLock(&e->waitable.mutex);
// 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.
if (e->auto_clear) {
if (e->signal)
e->signal = false;
else
rc = KERNELRESULT(Cancelled);
}
mutexUnlock(&e->waitable.mutex);
return rc;
}
bool _ueventBeginWait(Waitable* ww, WaiterNode* w, u64 cur_tick, u64* next_tick)
{
UEvent* e = (UEvent*)ww;
mutexLock(&e->waitable.mutex);
bool can_add = !e->signal;
if (can_add)
_waiterNodeAdd(w);
else if (e->auto_clear)
e->signal = false;
mutexUnlock(&e->waitable.mutex);
return can_add;
}
Result _ueventOnTimeout(Waitable* ww, u64 old_tick)
{
// This is not supposed to happen.
return KERNELRESULT(Cancelled);
}