mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-06 22:25:41 +12:00
[Kernel] Implement thread sleeping
This commit is contained in:
parent
db0adc55c1
commit
2a4709dcfa
6 changed files with 60 additions and 7 deletions
|
@ -107,6 +107,8 @@ class CPU {
|
|||
Memory& mem;
|
||||
|
||||
public:
|
||||
static constexpr u64 ticksPerSec = 268111856;
|
||||
|
||||
CPU(Memory& mem, Kernel& kernel);
|
||||
void reset();
|
||||
|
||||
|
@ -161,7 +163,7 @@ public:
|
|||
}
|
||||
|
||||
void runFrame() {
|
||||
env.ticksLeft = 268111856 / 60;
|
||||
env.ticksLeft = ticksPerSec / 60;
|
||||
|
||||
const auto exitReason = jit->Run();
|
||||
if (static_cast<u32>(exitReason) != 0) [[unlikely]] {
|
||||
|
|
|
@ -66,6 +66,7 @@ class Kernel {
|
|||
Handle makeThread(u32 entrypoint, u32 initialSP, u32 priority, s32 id, u32 arg,ThreadStatus status = ThreadStatus::Dormant);
|
||||
|
||||
void signalArbiter(u32 waitingAddress, s32 threadCount);
|
||||
void sleepThread(s64 ns);
|
||||
void sleepThreadOnArbiter(u32 waitingAddress);
|
||||
void switchThread(int newThreadIndex);
|
||||
void sortThreads();
|
||||
|
@ -116,6 +117,7 @@ class Kernel {
|
|||
void sendSyncRequest();
|
||||
void signalEvent();
|
||||
void svcCloseHandle();
|
||||
void svcSleepThread();
|
||||
void connectToPort();
|
||||
void outputDebugString();
|
||||
void waitSynchronization1();
|
||||
|
|
|
@ -116,6 +116,11 @@ struct Thread {
|
|||
// The waiting address for threads that are waiting on an AddressArbiter
|
||||
u32 waitingAddress;
|
||||
|
||||
// The nanoseconds until a thread wakes up from being asleep or from timing out while waiting on an arbiter
|
||||
s64 waitingNanoseconds;
|
||||
// The tick this thread went to sleep on
|
||||
u64 sleepTick;
|
||||
|
||||
// Thread context used for switching between threads
|
||||
std::array<u32, 16> gprs;
|
||||
std::array<u32, 32> fprs; // Stored as u32 because dynarmic does it
|
||||
|
|
|
@ -94,5 +94,14 @@ void Kernel::waitSynchronizationN() {
|
|||
|
||||
printf("Hacky WaitSync stuff for OoT triggered!!!\n");
|
||||
threads[currentThreadIndex].status = ThreadStatus::Ready;
|
||||
switchThread(rand() % threadCount);
|
||||
|
||||
while (1) {
|
||||
auto index = rand() % threadCount;
|
||||
auto& thread = threads[index];
|
||||
|
||||
if (canThreadRun(thread)) {
|
||||
switchThread(rand() % threadCount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@ void Kernel::serviceSVC(u32 svc) {
|
|||
case 0x01: controlMemory(); break;
|
||||
case 0x02: queryMemory(); break;
|
||||
case 0x08: createThread(); break;
|
||||
case 0x0A: svcSleepThread(); break;
|
||||
case 0x14: releaseMutex(); break;
|
||||
case 0x17: createEvent(); break;
|
||||
case 0x18: signalEvent(); break;
|
||||
|
@ -95,6 +96,10 @@ void Kernel::reset() {
|
|||
arbiterCount = 0;
|
||||
threadCount = 0;
|
||||
|
||||
for (auto& t : threads) {
|
||||
t.status = ThreadStatus::Dead;
|
||||
}
|
||||
|
||||
for (auto& object : objects) {
|
||||
deleteObjectData(object);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,14 @@ void Kernel::sortThreads() {
|
|||
bool Kernel::canThreadRun(const Thread& t) {
|
||||
if (t.status == ThreadStatus::Ready) {
|
||||
return true;
|
||||
} else if (t.status == ThreadStatus::WaitSleep) {
|
||||
const u64 elapsedTicks = cpu.getTicks() - t.sleepTick;
|
||||
|
||||
constexpr double ticksPerSec = double(CPU::ticksPerSec);
|
||||
constexpr double nsPerTick = ticksPerSec / 1000000000.0;
|
||||
|
||||
const s64 elapsedNs = s64(double(elapsedTicks) * nsPerTick);
|
||||
return elapsedNs >= t.waitingNanoseconds;
|
||||
}
|
||||
|
||||
// Handle timeouts and stuff here
|
||||
|
@ -129,6 +137,28 @@ Handle Kernel::makeThread(u32 entrypoint, u32 initialSP, u32 priority, s32 id, u
|
|||
return ret;
|
||||
}
|
||||
|
||||
void Kernel::sleepThreadOnArbiter(u32 waitingAddress) {
|
||||
Thread& t = threads[currentThreadIndex];
|
||||
t.status = ThreadStatus::WaitArbiter;
|
||||
t.waitingAddress = waitingAddress;
|
||||
|
||||
switchToNextThread();
|
||||
}
|
||||
|
||||
// Make a thread sleep for a certain amount of nanoseconds at minimum
|
||||
void Kernel::sleepThread(s64 ns) {
|
||||
if (ns < 0) {
|
||||
Helpers::panic("Sleeping a thread for a negative amount of ns");
|
||||
} else if (ns == 0) { // Used when we want to force a thread switch
|
||||
switchToNextThread();
|
||||
} else { // If we're sleeping for > 0 ns
|
||||
Thread& t = threads[currentThreadIndex];
|
||||
t.status = ThreadStatus::WaitSleep;
|
||||
t.waitingNanoseconds = ns;
|
||||
t.sleepTick = cpu.getTicks();
|
||||
}
|
||||
}
|
||||
|
||||
// Result CreateThread(s32 priority, ThreadFunc entrypoint, u32 arg, u32 stacktop, s32 threadPriority, s32 processorID)
|
||||
void Kernel::createThread() {
|
||||
u32 priority = regs[0];
|
||||
|
@ -150,12 +180,12 @@ void Kernel::createThread() {
|
|||
regs[1] = makeThread(entrypoint, initialSP, priority, id, arg, ThreadStatus::Ready);
|
||||
}
|
||||
|
||||
void Kernel::sleepThreadOnArbiter(u32 waitingAddress) {
|
||||
Thread& t = threads[currentThreadIndex];
|
||||
t.status = ThreadStatus::WaitArbiter;
|
||||
t.waitingAddress = waitingAddress;
|
||||
// void SleepThread(s64 nanoseconds)
|
||||
void Kernel::svcSleepThread() {
|
||||
const s64 ns = s64(u64(regs[0]) | (u64(regs[1]) << 32));
|
||||
logSVC("SleepThread(ns = %lld)\n", ns);
|
||||
|
||||
switchToNextThread();
|
||||
sleepThread(ns);
|
||||
}
|
||||
|
||||
void Kernel::getThreadID() {
|
||||
|
|
Loading…
Add table
Reference in a new issue