From 91e008ad1dac6f766c35c5caba460ce7cae712ac Mon Sep 17 00:00:00 2001 From: wheremyfoodat Date: Fri, 21 Apr 2023 21:39:59 +0300 Subject: [PATCH] [Kernel] New event signalling, better Mootex --- include/kernel/kernel_types.hpp | 6 +++- src/core/kernel/events.cpp | 49 ++++++++++++++++++++------------- src/core/kernel/kernel.cpp | 1 + src/core/kernel/threads.cpp | 26 ++++++++++++----- 4 files changed, 55 insertions(+), 27 deletions(-) diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index db9f9494..927e2a3a 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -26,6 +26,9 @@ namespace SVCResult { // Returned when a thread stops waiting due to timing out Timeout = 0x9401BFE, + + // Returned when a thread releases a mutex it does not own + InvalidMutexRelease = 0xD8E0041F }; } @@ -171,9 +174,10 @@ static const char* kernelObjectTypeToString(KernelObjectType t) { struct Mutex { u64 waitlist; // Refer to the getWaitlist function below for documentation Handle ownerThread = 0; // Index of the thread that holds the mutex if it's locked + u32 lockCount; // Number of times this mutex has been locked by its daddy. 0 = not locked bool locked; - Mutex(bool lock = false) : locked(lock), waitlist(0) {} + Mutex(bool lock = false) : locked(lock), waitlist(0), lockCount(0) {} }; struct Semaphore { diff --git a/src/core/kernel/events.cpp b/src/core/kernel/events.cpp index 54773345..1ab195c0 100644 --- a/src/core/kernel/events.cpp +++ b/src/core/kernel/events.cpp @@ -1,5 +1,6 @@ #include "kernel.hpp" #include "cpu.hpp" +#include #include const char* Kernel::resetTypeToString(u32 type) { @@ -27,29 +28,39 @@ bool Kernel::signalEvent(Handle handle) { Event* event = object->getData(); event->fired = true; - if (event->waitlist != 0) { - Helpers::panic("Tried to signal event with a waitlist"); + // One shot events go back to being not fired once they wake up one or more thread + if (event->waitlist != 0 && event->resetType == ResetType::OneShot) { + event->fired = false; } - /* - 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; + // Wake up every single thread in the waitlist using a bit scanning algorithm + while (event->waitlist != 0) { + const uint index = std::countr_zero(event->waitlist); // Get one of the set bits to see which thread is waiting + event->waitlist ^= (1ull << index); // Remove thread from waitlist by toggling its bit - default: - Helpers::panic("Signaled event of unimplemented type: %d", event->resetType); + // Get the thread we'll be signalling + Thread& t = threads[index]; + switch (t.status) { + case ThreadStatus::WaitSync1: + t.status = ThreadStatus::Ready; + break; + + case ThreadStatus::WaitSyncAny: + t.status = ThreadStatus::Ready; + // Get the index of the event in the object's waitlist, write it to r1 + for (size_t i = 0; i < t.waitList.size(); i++) { + if (t.waitList[i] == handle) { + t.gprs[1] = i; + break; + } + } + break; + + case ThreadStatus::WaitSyncAll: + Helpers::panic("SignalEvent: Thread on WaitSyncAll"); + break; + } } - */ return true; } diff --git a/src/core/kernel/kernel.cpp b/src/core/kernel/kernel.cpp index 730886ac..78c858c6 100644 --- a/src/core/kernel/kernel.cpp +++ b/src/core/kernel/kernel.cpp @@ -15,6 +15,7 @@ Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu) t.index = i; t.tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize; t.status = ThreadStatus::Dead; + t.waitList.clear(); t.waitList.reserve(10); // Reserve some space for the wait list to avoid further memory allocs later // The state below isn't necessary to initialize but we do it anyways out of caution t.outPointer = 0; diff --git a/src/core/kernel/threads.cpp b/src/core/kernel/threads.cpp index f997c77d..9c9608b8 100644 --- a/src/core/kernel/threads.cpp +++ b/src/core/kernel/threads.cpp @@ -165,18 +165,26 @@ Handle Kernel::makeMutex(bool locked) { Handle ret = makeObject(KernelObjectType::Mutex); objects[ret].data = new Mutex(locked); - // If the mutex is initially locked, store the index of the thread that owns it + // If the mutex is initially locked, store the index of the thread that owns it and set lock count to 1 if (locked) { - objects[ret].getData()->ownerThread = currentThreadIndex; + Mutex* moo = objects[ret].getData(); + moo->ownerThread = currentThreadIndex; + moo->lockCount = 1; } return ret; } void Kernel::releaseMutex(Mutex* moo) { - moo->locked = false; - if (moo->waitlist != 0) { - Helpers::panic("Mutex got freed while it's got more threads waiting for it. Must make a new thread claim it."); + // TODO: Assert lockCount > 0 before release, maybe. The SVC should be safe at least. + moo->lockCount--; // Decrement lock count + + // If the lock count reached 0 then the thread no longer owns the mootex and it can be given to a new one + if (moo->lockCount == 0) { + moo->locked = false; + if (moo->waitlist != 0) { + Helpers::panic("Mutex got freed while it's got more threads waiting for it. Must make a new thread claim it."); + } } } @@ -200,7 +208,10 @@ void Kernel::acquireSyncObject(KernelObject* object, const Thread& thread) { switch (object->type) { case KernelObjectType::Mutex: { Mutex* moo = object->getData(); - moo->locked = true; + moo->locked = true; // Set locked to true, whether it's false or not because who cares + // Increment lock count by 1. If a thread acquires a mootex multiple times, it needs to release it until count == 0 + // For the mootex to be free. + moo->lockCount++; moo->ownerThread = thread.index; break; } @@ -375,7 +386,8 @@ void Kernel::svcReleaseMutex() { Mutex* moo = object->getData(); // A thread can't release a mutex it does not own if (!moo->locked || moo->ownerThread != currentThreadIndex) { - Helpers::panic("[ReleaseMutex] Tried to release mutex that does not belong to thread"); + regs[0] = SVCResult::InvalidMutexRelease; + return; } releaseMutex(moo);