mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-12 09:09:47 +12:00
[Kernel] New event signalling, better Mootex
This commit is contained in:
parent
5daade05d8
commit
91e008ad1d
4 changed files with 55 additions and 27 deletions
|
@ -26,6 +26,9 @@ namespace SVCResult {
|
||||||
|
|
||||||
// Returned when a thread stops waiting due to timing out
|
// Returned when a thread stops waiting due to timing out
|
||||||
Timeout = 0x9401BFE,
|
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 {
|
struct Mutex {
|
||||||
u64 waitlist; // Refer to the getWaitlist function below for documentation
|
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
|
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;
|
bool locked;
|
||||||
|
|
||||||
Mutex(bool lock = false) : locked(lock), waitlist(0) {}
|
Mutex(bool lock = false) : locked(lock), waitlist(0), lockCount(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Semaphore {
|
struct Semaphore {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
#include "cpu.hpp"
|
#include "cpu.hpp"
|
||||||
|
#include <bit>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
const char* Kernel::resetTypeToString(u32 type) {
|
const char* Kernel::resetTypeToString(u32 type) {
|
||||||
|
@ -27,29 +28,39 @@ bool Kernel::signalEvent(Handle handle) {
|
||||||
Event* event = object->getData<Event>();
|
Event* event = object->getData<Event>();
|
||||||
event->fired = true;
|
event->fired = true;
|
||||||
|
|
||||||
if (event->waitlist != 0) {
|
// One shot events go back to being not fired once they wake up one or more thread
|
||||||
Helpers::panic("Tried to signal event with a waitlist");
|
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) {
|
// Wake up every single thread in the waitlist using a bit scanning algorithm
|
||||||
t.status = ThreadStatus::Ready;
|
while (event->waitlist != 0) {
|
||||||
break;
|
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
|
||||||
else if (t.status == ThreadStatus::WaitSyncAll) {
|
|
||||||
Helpers::panic("Trying to SignalEvent when a thread is waiting on multiple objects");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
// Get the thread we'll be signalling
|
||||||
Helpers::panic("Signaled event of unimplemented type: %d", event->resetType);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu)
|
||||||
t.index = i;
|
t.index = i;
|
||||||
t.tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
t.tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
||||||
t.status = ThreadStatus::Dead;
|
t.status = ThreadStatus::Dead;
|
||||||
|
t.waitList.clear();
|
||||||
t.waitList.reserve(10); // Reserve some space for the wait list to avoid further memory allocs later
|
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
|
// The state below isn't necessary to initialize but we do it anyways out of caution
|
||||||
t.outPointer = 0;
|
t.outPointer = 0;
|
||||||
|
|
|
@ -165,18 +165,26 @@ Handle Kernel::makeMutex(bool locked) {
|
||||||
Handle ret = makeObject(KernelObjectType::Mutex);
|
Handle ret = makeObject(KernelObjectType::Mutex);
|
||||||
objects[ret].data = new Mutex(locked);
|
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) {
|
if (locked) {
|
||||||
objects[ret].getData<Mutex>()->ownerThread = currentThreadIndex;
|
Mutex* moo = objects[ret].getData<Mutex>();
|
||||||
|
moo->ownerThread = currentThreadIndex;
|
||||||
|
moo->lockCount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Kernel::releaseMutex(Mutex* moo) {
|
void Kernel::releaseMutex(Mutex* moo) {
|
||||||
moo->locked = false;
|
// TODO: Assert lockCount > 0 before release, maybe. The SVC should be safe at least.
|
||||||
if (moo->waitlist != 0) {
|
moo->lockCount--; // Decrement lock count
|
||||||
Helpers::panic("Mutex got freed while it's got more threads waiting for it. Must make a new thread claim it.");
|
|
||||||
|
// 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) {
|
switch (object->type) {
|
||||||
case KernelObjectType::Mutex: {
|
case KernelObjectType::Mutex: {
|
||||||
Mutex* moo = object->getData<Mutex>();
|
Mutex* moo = object->getData<Mutex>();
|
||||||
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;
|
moo->ownerThread = thread.index;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -375,7 +386,8 @@ void Kernel::svcReleaseMutex() {
|
||||||
Mutex* moo = object->getData<Mutex>();
|
Mutex* moo = object->getData<Mutex>();
|
||||||
// A thread can't release a mutex it does not own
|
// A thread can't release a mutex it does not own
|
||||||
if (!moo->locked || moo->ownerThread != currentThreadIndex) {
|
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);
|
releaseMutex(moo);
|
||||||
|
|
Loading…
Add table
Reference in a new issue