[Kernel] Make WaitSyncN better

This commit is contained in:
wheremyfoodat 2023-04-21 01:08:13 +03:00
parent f575d4db82
commit 33158c7908
6 changed files with 128 additions and 56 deletions

View file

@ -1,5 +1,6 @@
#include "kernel.hpp"
#include "cpu.hpp"
#include <utility>
const char* Kernel::resetTypeToString(u32 type) {
switch (type) {
@ -16,8 +17,45 @@ Handle Kernel::makeEvent(ResetType resetType) {
return ret;
}
bool Kernel::signalEvent(Handle handle) {
KernelObject* object = getObject(handle, KernelObjectType::Event);
if (object == nullptr) [[unlikely]] {
Helpers::panic("Tried to signal non-existent event");
return false;
}
Event* event = object->getData<Event>();
event->fired = true;
if (event->waitlist != 0) {
Helpers::panic("Tried to signal event with a waitlist");
}
/*
switch (event->resetType) {
case ResetType::OneShot:
for (int i = 0; i < threadCount; i++) {
Thread& t = threads[i];
if (t.status == ThreadStatus::WaitSync1 && t.waitList[0] == handle) {
t.status = ThreadStatus::Ready;
break;
}
else if (t.status == ThreadStatus::WaitSyncAll) {
Helpers::panic("Trying to SignalEvent when a thread is waiting on multiple objects");
}
}
break;
default:
Helpers::panic("Signaled event of unimplemented type: %d", event->resetType);
}
*/
return true;
}
// Result CreateEvent(Handle* event, ResetType resetType)
void Kernel::createEvent() {
void Kernel::svcCreateEvent() {
const u32 outPointer = regs[0];
const u32 resetType = regs[1];
@ -31,7 +69,7 @@ void Kernel::createEvent() {
}
// Result ClearEvent(Handle event)
void Kernel::clearEvent() {
void Kernel::svcClearEvent() {
const Handle handle = regs[0];
const auto event = getObject(handle, KernelObjectType::Event);
logSVC("ClearEvent(event handle = %X)\n", handle);
@ -47,38 +85,15 @@ void Kernel::clearEvent() {
}
// Result SignalEvent(Handle event)
void Kernel::signalEvent() {
void Kernel::svcSignalEvent() {
const Handle handle = regs[0];
const auto event = getObject(handle, KernelObjectType::Event);
logSVC("SignalEvent(event handle = %X)\n", handle);
if (event == nullptr) [[unlikely]] {
logThread("Signalled non-existent event: %X\n", handle);
if (!signalEvent(handle)) {
Helpers::panic("Signalled non-existent event: %X\n", handle);
regs[0] = SVCResult::BadHandle;
} else {
regs[0] = SVCResult::Success;
//regs[0] = SVCResult::BadHandle;
return;
}
regs[0] = SVCResult::Success;
auto eventData = event->getData<Event>();
eventData->fired = true;
switch (eventData->resetType) {
case ResetType::OneShot:
for (int i = 0; i < threadCount; i++) {
Thread& t = threads[i];
if (t.status == ThreadStatus::WaitSync1 && t.waitList[0] == handle) {
t.status = ThreadStatus::Ready;
break;
} else if (t.status == ThreadStatus::WaitSyncAll) {
Helpers::panic("Trying to SignalEvent when a thread is waiting on multiple objects");
}
}
break;
default:
Helpers::panic("Signaled event of unimplemented type: %d", eventData->resetType);
}
}
@ -131,7 +146,7 @@ void Kernel::waitSynchronizationN() {
// TODO: Are these arguments even correct?
s32 ns1 = regs[0];
u32 handles = regs[1];
u32 handleCount = regs[2];
s32 handleCount = regs[2];
bool waitAll = regs[3] != 0;
u32 ns2 = regs[4];
s32 outPointer = regs[5]; // "out" pointer - shows which object got bonked if we're waiting on multiple objects
@ -142,37 +157,78 @@ void Kernel::waitSynchronizationN() {
if (waitAll && handleCount > 1)
Helpers::panic("Trying to wait on more than 1 object");
auto& t = threads[currentThreadIndex];
t.waitList.resize(handleCount);
for (uint i = 0; i < handleCount; i++) {
if (handleCount < 0)
Helpers::panic("WaitSyncN: Invalid handle count");
using WaitObject = std::pair<Handle, KernelObject*>;
std::vector<WaitObject> waitObjects(handleCount);
// We don't actually need to wait if waitAll == true unless one of the objects is not ready
bool allReady = true; // Default initialize to true, set to fault if one of the objects is not ready
// Tracks whether at least one object is ready, + the index of the first ready object
// This is used when waitAll == false, because if one object is already available then we can skip the sleeping
bool oneObjectReady = false;
s32 firstReadyObjectIndex = 0;
for (s32 i = 0; i < handleCount; i++) {
Handle handle = mem.read32(handles);
handles += sizeof(Handle);
t.waitList[i] = handle;
auto object = getObject(handle);
// Panic if one of the objects is not even an object
if (object == nullptr) [[unlikely]] {
Helpers::panic("WaitSynchronizationN: Bad object handle %X\n", handle);
regs[0] = SVCResult::BadHandle;
return;
}
// Panic if one of the objects is not a valid sync object
if (!isWaitable(object)) [[unlikely]] {
Helpers::panic("Tried to wait on a non waitable object in WaitSyncN. Type: %s, handle: %X\n",
Helpers::panic("Tried to wait on a non waitable object in WaitSyncN. Type: %s, handle: %X\n",
object->getTypeName(), handle);
}
// Add the current thread to the object's wait list
object->getWaitlist() |= (1ull << currentThreadIndex);
if (shouldWaitOnObject(object)) {
allReady = false; // Derp, not all objects are ready :(
} else { /// At least one object is ready to be acquired ahead of time. If it's the first one, write it down
if (!oneObjectReady) {
oneObjectReady = true;
firstReadyObjectIndex = i;
}
}
waitObjects[i] = {handle, object};
}
regs[0] = SVCResult::Success;
regs[1] = waitAll ? handleCount - 1 : 0; // Index of the handle that triggered the exit. STUBBED
t.status = ThreadStatus::WaitSyncAll;
t.waitAll = waitAll;
t.outPointer = outPointer;
t.waitingNanoseconds = ns;
t.sleepTick = cpu.getTicks();
switchToNextThread();
auto& t = threads[currentThreadIndex];
// We only need to wait on one object. Easy...?!
if (!waitAll) {
// If there's ready objects, acquire the first one and return
if (oneObjectReady) {
regs[0] = SVCResult::Success;
regs[1] = firstReadyObjectIndex; // Return index of the acquired object
acquireSyncObject(waitObjects[firstReadyObjectIndex].second, t); // Acquire object
return;
}
Helpers::panic("WaitSyncAny can't instantly acquire :(");
regs[0] = SVCResult::Success;
regs[1] = handleCount - 1; // FIX THIS
t.waitList.resize(handleCount);
t.status = ThreadStatus::WaitSyncAny;
t.outPointer = outPointer;
t.waitingNanoseconds = ns;
t.sleepTick = cpu.getTicks();
for (s32 i = 0; i < handleCount; i++) {
t.waitList[i] = waitObjects[i].first; // Add object to this thread's waitlist
waitObjects[i].second->getWaitlist() |= (1ull << currentThreadIndex); // And add the thread to the object's waitlist
}
switchToNextThread();
} else {
Helpers::panic("WaitSynchronizatioN with waitAll");
}
}