I hate timers

This commit is contained in:
wheremyfoodat 2023-08-14 17:24:53 +03:00
parent 1354b0f7fa
commit 8881467505
4 changed files with 69 additions and 12 deletions

View file

@ -35,6 +35,7 @@ class Kernel {
std::vector<KernelObject> objects; std::vector<KernelObject> objects;
std::vector<Handle> portHandles; std::vector<Handle> portHandles;
std::vector<Handle> mutexHandles; std::vector<Handle> mutexHandles;
std::vector<Handle> timerHandles;
// Thread indices, sorted by priority // Thread indices, sorted by priority
std::vector<int> threadIndices; std::vector<int> threadIndices;
@ -84,6 +85,7 @@ private:
void releaseMutex(Mutex* moo); void releaseMutex(Mutex* moo);
void cancelTimer(Timer* timer); void cancelTimer(Timer* timer);
void signalTimer(Handle timerHandle, Timer* timer); void signalTimer(Handle timerHandle, Timer* timer);
void updateTimer(Handle timerHandle, Timer* timer);
// Wake up the thread with the highest priority out of all threads in the waitlist // Wake up the thread with the highest priority out of all threads in the waitlist
// Returns the index of the woken up thread // Returns the index of the woken up thread
@ -182,6 +184,14 @@ public:
void requireReschedule() { needReschedule = true; } void requireReschedule() { needReschedule = true; }
void evalReschedule() { void evalReschedule() {
for (auto handle : timerHandles) {
const auto object = getObject(handle, KernelObjectType::Timer);
if (object != nullptr) {
Timer* timer = object->getData<Timer>();
updateTimer(handle, timer);
}
}
if (needReschedule) { if (needReschedule) {
needReschedule = false; needReschedule = false;
rescheduleThreads(); rescheduleThreads();

View file

@ -167,11 +167,13 @@ struct Timer {
u64 waitlist; // Refer to the getWaitlist function below for documentation u64 waitlist; // Refer to the getWaitlist function below for documentation
ResetType resetType = ResetType::OneShot; ResetType resetType = ResetType::OneShot;
u64 initialDelay; // Number of ns until the timer fires for the first time u64 startTick; // CPU tick the timer started
u64 interval; // Number of ns until the timer fires for the second and future times u64 currentDelay; // Number of ns until the timer fires next time
bool fired; // Has this Timer been signalled? u64 interval; // Number of ns until the timer fires for the second and future times
bool fired; // Has this timer been signalled?
bool running; // Is this timer running or stopped?
Timer(ResetType type) : resetType(type), initialDelay(0), interval(0), waitlist(0), fired(false) {} Timer(ResetType type) : resetType(type), startTick(0), currentDelay(0), interval(0), waitlist(0), fired(false), running(false) {}
}; };
struct MemoryBlock { struct MemoryBlock {

View file

@ -7,6 +7,7 @@ Kernel::Kernel(CPU& cpu, Memory& mem, GPU& gpu)
: cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, gpu, currentProcess, *this) { : cpu(cpu), regs(cpu.regs()), mem(mem), handleCounter(0), serviceManager(regs, mem, gpu, currentProcess, *this) {
objects.reserve(512); // Make room for a few objects to avoid further memory allocs later objects.reserve(512); // Make room for a few objects to avoid further memory allocs later
mutexHandles.reserve(8); mutexHandles.reserve(8);
timerHandles.reserve(8);
portHandles.reserve(32); portHandles.reserve(32);
threadIndices.reserve(appResourceLimits.maxThreads); threadIndices.reserve(appResourceLimits.maxThreads);
@ -146,6 +147,7 @@ void Kernel::reset() {
} }
objects.clear(); objects.clear();
mutexHandles.clear(); mutexHandles.clear();
timerHandles.clear();
portHandles.clear(); portHandles.clear();
threadIndices.clear(); threadIndices.clear();
serviceManager.reset(); serviceManager.reset();

View file

@ -1,26 +1,55 @@
#include "kernel.hpp" #include "kernel.hpp"
#include "cpu.hpp"
Handle Kernel::makeTimer(ResetType type) { Handle Kernel::makeTimer(ResetType type) {
Handle ret = makeObject(KernelObjectType::Timer); Handle ret = makeObject(KernelObjectType::Timer);
objects[ret].data = new Timer(type); objects[ret].data = new Timer(type);
if (type == ResetType::Pulse) Helpers::panic("Created pulse timer"); if (type == ResetType::Pulse) {
Helpers::panic("Created pulse timer");
}
timerHandles.push_back(ret);
return ret; return ret;
} }
void Kernel::updateTimer(Handle handle, Timer* timer) {
if (timer->running) {
const u64 currentTicks = cpu.getTicks();
u64 elapsedTicks = currentTicks - timer->startTick;
constexpr double ticksPerSec = double(CPU::ticksPerSec);
constexpr double nsPerTick = ticksPerSec / 1000000000.0;
const s64 elapsedNs = s64(double(elapsedTicks) * nsPerTick);
// Timer has fired
if (elapsedNs >= timer->currentDelay) {
timer->startTick = currentTicks;
timer->currentDelay = timer->interval;
signalTimer(handle, timer);
}
}
}
void Kernel::cancelTimer(Timer* timer) { void Kernel::cancelTimer(Timer* timer) {
timer->running = false;
// TODO: When we have a scheduler this should properly cancel timer events in the scheduler // TODO: When we have a scheduler this should properly cancel timer events in the scheduler
} }
void Kernel::signalTimer(Handle timerHandle, Timer* timer) { void Kernel::signalTimer(Handle timerHandle, Timer* timer) {
timer->fired = true; timer->fired = true;
wakeupAllThreads(timer->waitlist, timerHandle); requireReschedule();
switch (timer->resetType) { // Check if there's any thread waiting on this event
case ResetType::OneShot: timer->fired = false; break; if (timer->waitlist != 0) {
case ResetType::Sticky: break; wakeupAllThreads(timer->waitlist, timerHandle);
case ResetType::Pulse: Helpers::panic("Signalled pulsing timer"); break; timer->waitlist = 0; // No threads waiting;
switch (timer->resetType) {
case ResetType::OneShot: timer->fired = false; break;
case ResetType::Sticky: break;
case ResetType::Pulse: Helpers::panic("Signalled pulsing timer"); break;
}
} }
} }
@ -54,8 +83,10 @@ void Kernel::svcSetTimer() {
Timer* timer = object->getData<Timer>(); Timer* timer = object->getData<Timer>();
cancelTimer(timer); cancelTimer(timer);
timer->initialDelay = initial; timer->currentDelay = initial;
timer->interval = interval; timer->interval = interval;
timer->running = true;
timer->startTick = cpu.getTicks();
// If the initial delay is 0 then instantly signal the timer // If the initial delay is 0 then instantly signal the timer
if (initial == 0) { if (initial == 0) {
@ -81,4 +112,16 @@ void Kernel::svcClearTimer() {
} }
} }
void Kernel::svcCancelTimer() { Helpers::panic("Kernel::CancelTimer"); } void Kernel::svcCancelTimer() {
Handle handle = regs[0];
logSVC("CancelTimer (handle = %X)\n", handle);
KernelObject* object = getObject(handle, KernelObjectType::Timer);
if (object == nullptr) {
Helpers::panic("Tried to cancel non-existent timer %X\n", handle);
regs[0] = Result::Kernel::InvalidHandle;
} else {
cancelTimer(object->getData<Timer>());
regs[0] = Result::Success;
}
}