mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 07:05:40 +12:00
Add thread preemption when a thread wakes up from a timeout
This commit is contained in:
parent
86d1bde845
commit
54cdcacd5a
6 changed files with 54 additions and 3 deletions
|
@ -58,6 +58,7 @@ class Kernel {
|
||||||
// Top 8 bits are the major version, bottom 8 are the minor version
|
// Top 8 bits are the major version, bottom 8 are the minor version
|
||||||
u16 kernelVersion = 0;
|
u16 kernelVersion = 0;
|
||||||
|
|
||||||
|
u64 nextScheduledWakeupTick = std::numeric_limits<u64>::max();
|
||||||
// Shows whether a reschedule will be need
|
// Shows whether a reschedule will be need
|
||||||
bool needReschedule = false;
|
bool needReschedule = false;
|
||||||
|
|
||||||
|
@ -214,6 +215,8 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addWakeupEvent(u64 tick);
|
||||||
|
|
||||||
Handle makeObject(KernelObjectType type) {
|
Handle makeObject(KernelObjectType type) {
|
||||||
if (handleCounter > KernelHandles::Max) [[unlikely]] {
|
if (handleCounter > KernelHandles::Max) [[unlikely]] {
|
||||||
Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
|
Helpers::panic("Hlep we somehow created enough kernel objects to overflow this thing");
|
||||||
|
@ -253,5 +256,7 @@ public:
|
||||||
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
|
void sendGPUInterrupt(GPUInterrupt type) { serviceManager.sendGPUInterrupt(type); }
|
||||||
void clearInstructionCache();
|
void clearInstructionCache();
|
||||||
void clearInstructionCacheRange(u32 start, u32 size);
|
void clearInstructionCacheRange(u32 start, u32 size);
|
||||||
|
void pollThreadWakeups();
|
||||||
|
|
||||||
u32 getSharedFontVaddr();
|
u32 getSharedFontVaddr();
|
||||||
};
|
};
|
|
@ -11,7 +11,8 @@ struct Scheduler {
|
||||||
VBlank = 0, // End of frame event
|
VBlank = 0, // End of frame event
|
||||||
UpdateTimers = 1, // Update kernel timer objects
|
UpdateTimers = 1, // Update kernel timer objects
|
||||||
RunDSP = 2, // Make the emulated DSP run for one audio frame
|
RunDSP = 2, // Make the emulated DSP run for one audio frame
|
||||||
SignalY2R = 3, // Signal that a Y2R conversion has finished
|
ThreadWakeup = 3, // A thread is going to wake up and we need to reschedule threads
|
||||||
|
SignalY2R = 4, // Signal that a Y2R conversion has finished
|
||||||
Panic = 4, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX)
|
Panic = 4, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX)
|
||||||
TotalNumberOfEvents // How many event types do we have in total?
|
TotalNumberOfEvents // How many event types do we have in total?
|
||||||
};
|
};
|
||||||
|
|
|
@ -137,6 +137,7 @@ void Kernel::waitSynchronization1() {
|
||||||
// Add the current thread to the object's wait list
|
// Add the current thread to the object's wait list
|
||||||
object->getWaitlist() |= (1ull << currentThreadIndex);
|
object->getWaitlist() |= (1ull << currentThreadIndex);
|
||||||
|
|
||||||
|
addWakeupEvent(t.wakeupTick);
|
||||||
requireReschedule();
|
requireReschedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,6 +232,7 @@ void Kernel::waitSynchronizationN() {
|
||||||
waitObjects[i].second->getWaitlist() |= (1ull << currentThreadIndex); // And add the thread to the object's waitlist
|
waitObjects[i].second->getWaitlist() |= (1ull << currentThreadIndex); // And add the thread to the object's waitlist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addWakeupEvent(t.wakeupTick);
|
||||||
requireReschedule();
|
requireReschedule();
|
||||||
} else {
|
} else {
|
||||||
Helpers::panic("WaitSynchronizationN with waitAll");
|
Helpers::panic("WaitSynchronizationN with waitAll");
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
#include <cassert>
|
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
#include "kernel_types.hpp"
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "cpu.hpp"
|
#include "cpu.hpp"
|
||||||
|
#include "kernel_types.hpp"
|
||||||
|
|
||||||
Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config)
|
Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu, const EmulatorConfig& config)
|
||||||
: cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, gpu, currentProcess, *this, config) {
|
: cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, gpu, currentProcess, *this, config) {
|
||||||
|
@ -159,6 +162,7 @@ void Kernel::reset() {
|
||||||
threadIndices.clear();
|
threadIndices.clear();
|
||||||
serviceManager.reset();
|
serviceManager.reset();
|
||||||
|
|
||||||
|
nextScheduledWakeupTick = std::numeric_limits<u64>::max();
|
||||||
needReschedule = false;
|
needReschedule = false;
|
||||||
|
|
||||||
// Allocate handle #0 to a dummy object and make a main process object
|
// Allocate handle #0 to a dummy object and make a main process object
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
#include <algorithm>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "arm_defs.hpp"
|
#include "arm_defs.hpp"
|
||||||
#include "kernel.hpp"
|
#include "kernel.hpp"
|
||||||
|
@ -396,6 +398,7 @@ void Kernel::sleepThread(s64 ns) {
|
||||||
t.status = ThreadStatus::WaitSleep;
|
t.status = ThreadStatus::WaitSleep;
|
||||||
t.wakeupTick = getWakeupTick(ns);
|
t.wakeupTick = getWakeupTick(ns);
|
||||||
|
|
||||||
|
addWakeupEvent(t.wakeupTick);
|
||||||
requireReschedule();
|
requireReschedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -697,3 +700,38 @@ bool Kernel::shouldWaitOnObject(KernelObject* object) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Kernel::pollThreadWakeups() {
|
||||||
|
rescheduleThreads();
|
||||||
|
bool haveSleepingThread = false;
|
||||||
|
u64 nextWakeupTick = std::numeric_limits<u64>::max();
|
||||||
|
|
||||||
|
for (auto index : threadIndices) {
|
||||||
|
const Thread& t = threads[index];
|
||||||
|
|
||||||
|
if (t.status == ThreadStatus::WaitSleep || t.status == ThreadStatus::WaitSync1 || t.status == ThreadStatus::WaitSyncAny || t.status == ThreadStatus::WaitSyncAll) {
|
||||||
|
nextWakeupTick = std::min<u64>(nextWakeupTick, t.wakeupTick);
|
||||||
|
haveSleepingThread = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& scheduler = cpu.getScheduler();
|
||||||
|
|
||||||
|
if (haveSleepingThread && nextWakeupTick > scheduler.currentTimestamp) {
|
||||||
|
nextScheduledWakeupTick = nextWakeupTick;
|
||||||
|
scheduler.addEvent(Scheduler::EventType::ThreadWakeup, nextWakeupTick);
|
||||||
|
} else {
|
||||||
|
nextScheduledWakeupTick = std::numeric_limits<u64>::max();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kernel::addWakeupEvent(u64 tick) {
|
||||||
|
// We only need to queue the event if the tick of the wakeup is coming sooner than our next scheduled wakeup.
|
||||||
|
if (nextScheduledWakeupTick > tick) {
|
||||||
|
nextScheduledWakeupTick = tick;
|
||||||
|
auto& scheduler = cpu.getScheduler();
|
||||||
|
|
||||||
|
scheduler.removeEvent(Scheduler::EventType::ThreadWakeup);
|
||||||
|
scheduler.addEvent(Scheduler::EventType::ThreadWakeup, tick);
|
||||||
|
}
|
||||||
|
}
|
|
@ -177,6 +177,7 @@ void Emulator::pollScheduler() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Scheduler::EventType::ThreadWakeup: kernel.pollThreadWakeups(); break;
|
||||||
case Scheduler::EventType::UpdateTimers: kernel.pollTimers(); break;
|
case Scheduler::EventType::UpdateTimers: kernel.pollTimers(); break;
|
||||||
case Scheduler::EventType::RunDSP: {
|
case Scheduler::EventType::RunDSP: {
|
||||||
dsp->runAudioFrame(time);
|
dsp->runAudioFrame(time);
|
||||||
|
|
Loading…
Add table
Reference in a new issue