mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-17 19:21:30 +12:00
More thread work
This commit is contained in:
parent
7547159a48
commit
ca4726aba1
6 changed files with 82 additions and 28 deletions
|
@ -60,6 +60,7 @@ private:
|
||||||
void switchToNextThread();
|
void switchToNextThread();
|
||||||
void rescheduleThreads();
|
void rescheduleThreads();
|
||||||
bool canThreadRun(const Thread& t);
|
bool canThreadRun(const Thread& t);
|
||||||
|
bool shouldWaitOnObject(KernelObject* object);
|
||||||
|
|
||||||
std::optional<Handle> getPortHandle(const char* name);
|
std::optional<Handle> getPortHandle(const char* name);
|
||||||
void deleteObjectData(KernelObject& object);
|
void deleteObjectData(KernelObject& object);
|
||||||
|
|
|
@ -121,8 +121,12 @@ struct Thread {
|
||||||
u64 waitingNanoseconds;
|
u64 waitingNanoseconds;
|
||||||
// The tick this thread went to sleep on
|
// The tick this thread went to sleep on
|
||||||
u64 sleepTick;
|
u64 sleepTick;
|
||||||
// For WaitSynchronization: A vector of objects this thread is waiting for
|
// For WaitSynchronization(N): A vector of objects this thread is waiting for
|
||||||
std::vector<Handle> waitList;
|
std::vector<Handle> waitList;
|
||||||
|
// For WaitSynchronizationN: Shows whether the object should wait for all objects in the wait list or just one
|
||||||
|
bool waitAll;
|
||||||
|
// For WaitSynchronizationN: The "out" pointer
|
||||||
|
u32 outPointer;
|
||||||
|
|
||||||
// Thread context used for switching between threads
|
// Thread context used for switching between threads
|
||||||
std::array<u32, 16> gprs;
|
std::array<u32, 16> gprs;
|
||||||
|
|
|
@ -37,6 +37,7 @@ void Kernel::clearEvent() {
|
||||||
logSVC("ClearEvent(event handle = %X)\n", handle);
|
logSVC("ClearEvent(event handle = %X)\n", handle);
|
||||||
|
|
||||||
if (event == nullptr) [[unlikely]] {
|
if (event == nullptr) [[unlikely]] {
|
||||||
|
Helpers::panic("Tried to clear non-existent event");
|
||||||
regs[0] = SVCResult::BadHandle;
|
regs[0] = SVCResult::BadHandle;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -52,16 +53,34 @@ void Kernel::signalEvent() {
|
||||||
logSVC("SignalEvent(event handle = %X)\n", handle);
|
logSVC("SignalEvent(event handle = %X)\n", handle);
|
||||||
printf("Stubbed SignalEvent!!\n");
|
printf("Stubbed SignalEvent!!\n");
|
||||||
|
|
||||||
/*
|
|
||||||
if (event == nullptr) [[unlikely]] {
|
if (event == nullptr) [[unlikely]] {
|
||||||
regs[0] = SVCResult::BadHandle;
|
Helpers::warn("Signalled non-existent event: %X\n", handle);
|
||||||
|
regs[0] = SVCResult::Success;
|
||||||
|
//regs[0] = SVCResult::BadHandle;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event->getData<Event>()->fired = true;
|
|
||||||
*/
|
|
||||||
|
|
||||||
regs[0] = SVCResult::Success;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result WaitSynchronization1(Handle handle, s64 timeout_nanoseconds)
|
// Result WaitSynchronization1(Handle handle, s64 timeout_nanoseconds)
|
||||||
|
@ -82,6 +101,9 @@ void Kernel::waitSynchronization1() {
|
||||||
Helpers::panic("Tried to wait on a non waitable object. Type: %s, handle: %X\n", object->getTypeName(), handle);
|
Helpers::panic("Tried to wait on a non waitable object. Type: %s, handle: %X\n", object->getTypeName(), handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!shouldWaitOnObject(object)) {
|
||||||
|
regs[0] = SVCResult::Success;
|
||||||
|
} else {
|
||||||
regs[0] = SVCResult::Success;
|
regs[0] = SVCResult::Success;
|
||||||
|
|
||||||
auto& t = threads[currentThreadIndex];
|
auto& t = threads[currentThreadIndex];
|
||||||
|
@ -92,6 +114,7 @@ void Kernel::waitSynchronization1() {
|
||||||
t.waitList[0] = handle;
|
t.waitList[0] = handle;
|
||||||
switchToNextThread();
|
switchToNextThread();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 timeout_nanoseconds)
|
// Result WaitSynchronizationN(s32* out, Handle* handles, s32 handlecount, bool waitAll, s64 timeout_nanoseconds)
|
||||||
void Kernel::waitSynchronizationN() {
|
void Kernel::waitSynchronizationN() {
|
||||||
|
@ -101,11 +124,13 @@ void Kernel::waitSynchronizationN() {
|
||||||
u32 handleCount = regs[2];
|
u32 handleCount = regs[2];
|
||||||
bool waitAll = regs[3] != 0;
|
bool waitAll = regs[3] != 0;
|
||||||
u32 ns2 = regs[4];
|
u32 ns2 = regs[4];
|
||||||
s32 pointer = regs[5];
|
s32 outPointer = regs[5]; // "out" pointer - shows which object got bonked if we're waiting on multiple objects
|
||||||
s64 ns = s64(ns1) | (s64(ns2) << 32);
|
s64 ns = s64(ns1) | (s64(ns2) << 32);
|
||||||
|
|
||||||
logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d, timeout = %lld)\n", handles, handleCount, ns);
|
logSVC("WaitSynchronizationN (handle pointer: %08X, count: %d, timeout = %lld)\n", handles, handleCount, ns);
|
||||||
ThreadStatus newStatus = waitAll ? ThreadStatus::WaitSyncAll : ThreadStatus::WaitSync1;
|
|
||||||
|
if (waitAll && handleCount > 1)
|
||||||
|
Helpers::panic("Trying to wait on more than 1 object");
|
||||||
|
|
||||||
auto& t = threads[currentThreadIndex];
|
auto& t = threads[currentThreadIndex];
|
||||||
t.waitList.resize(handleCount);
|
t.waitList.resize(handleCount);
|
||||||
|
@ -124,12 +149,14 @@ void Kernel::waitSynchronizationN() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isWaitable(object)) [[unlikely]] {
|
if (!isWaitable(object)) [[unlikely]] {
|
||||||
Helpers::panic("Tried to wait on a non waitable object. Type: %s, handle: %X\n", object->getTypeName(), handle);
|
//Helpers::panic("Tried to wait on a non waitable object. Type: %s, handle: %X\n", object->getTypeName(), handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
regs[0] = SVCResult::Success;
|
regs[0] = SVCResult::Success;
|
||||||
t.status = newStatus;
|
t.status = ThreadStatus::WaitSyncAll;
|
||||||
|
t.waitAll = waitAll;
|
||||||
|
t.outPointer = outPointer;
|
||||||
t.waitingNanoseconds = ns;
|
t.waitingNanoseconds = ns;
|
||||||
t.sleepTick = cpu.getTicks();
|
t.sleepTick = cpu.getTicks();
|
||||||
switchToNextThread();
|
switchToNextThread();
|
||||||
|
|
|
@ -10,10 +10,15 @@ Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu)
|
||||||
threadIndices.reserve(appResourceLimits.maxThreads);
|
threadIndices.reserve(appResourceLimits.maxThreads);
|
||||||
|
|
||||||
for (int i = 0; i < threads.size(); i++) {
|
for (int i = 0; i < threads.size(); i++) {
|
||||||
threads[i].index = i;
|
Thread& t = threads[i];
|
||||||
threads[i].tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
|
||||||
threads[i].status = ThreadStatus::Dead;
|
t.index = i;
|
||||||
threads[i].waitList.reserve(10); // Reserve some space for the wait list to avoid further memory allocs later
|
t.tlsBase = VirtualAddrs::TLSBase + i * VirtualAddrs::TLSSize;
|
||||||
|
t.status = ThreadStatus::Dead;
|
||||||
|
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;
|
||||||
|
t.waitAll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setVersion(1, 69);
|
setVersion(1, 69);
|
||||||
|
|
|
@ -82,8 +82,8 @@ void Kernel::switchToNextThread() {
|
||||||
std::optional<int> newThreadIndex = getNextThread();
|
std::optional<int> newThreadIndex = getNextThread();
|
||||||
|
|
||||||
if (!newThreadIndex.has_value()) {
|
if (!newThreadIndex.has_value()) {
|
||||||
Helpers::warn("Kernel tried to switch to the next thread but none found. Switching to thread 0\n");
|
Helpers::warn("Kernel tried to switch to the next thread but none found. Switching to random thread\n");
|
||||||
switchThread(0);
|
switchThread(rand() % threadCount);
|
||||||
} else {
|
} else {
|
||||||
switchThread(newThreadIndex.value());
|
switchThread(newThreadIndex.value());
|
||||||
}
|
}
|
||||||
|
@ -302,3 +302,15 @@ bool Kernel::isWaitable(const KernelObject* object) {
|
||||||
|
|
||||||
return type == Event || type == Mutex || type == Port || type == Semaphore || type == Timer || type == Thread;
|
return type == Event || type == Mutex || type == Port || type == Semaphore || type == Timer || type == Thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns whether we should wait on a sync object or not
|
||||||
|
bool Kernel::shouldWaitOnObject(KernelObject* object) {
|
||||||
|
switch (object->type) {
|
||||||
|
case KernelObjectType::Event: // We should wait on an event only if it has not been signalled
|
||||||
|
return !object->getData<Event>()->fired;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Helpers::warn("Not sure whether to wait on object (type: %s)", object->getTypeName());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -117,6 +117,11 @@ u32 Memory::read32(u32 vaddr) {
|
||||||
case ConfigMem::AppMemAlloc: return appResourceLimits.maxCommit;
|
case ConfigMem::AppMemAlloc: return appResourceLimits.maxCommit;
|
||||||
case 0x1FF81000: return 0; // TODO: Figure out what this config mem address does
|
case 0x1FF81000: return 0; // TODO: Figure out what this config mem address does
|
||||||
default:
|
default:
|
||||||
|
if (vaddr >= VirtualAddrs::VramStart && vaddr < VirtualAddrs::VramStart + VirtualAddrs::VramSize) {
|
||||||
|
Helpers::warn("VRAM read!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Helpers::panic("Unimplemented 32-bit read, addr: %08X", vaddr);
|
Helpers::panic("Unimplemented 32-bit read, addr: %08X", vaddr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue