Thread scheduling fixes (#722)

* Add thread preemption when a thread wakes up from a timeout

* Add arbiter sleeping with timeout

Update threads.cpp

* Scheduler: Fix event numbers

* More address arbiter fixes

* Update preempt threads branch (#755)

* CI: Fix Vulkan SDK action (#723)

* GPU registers: Fix writes to some registers ignoring the mask (#725)

Co-authored-by: henry <23128103+atem2069@users.noreply.github.com>

* OLED theme

* OLED theme config fix (#736)

Co-authored-by: smiRaphi <neogt404@gmail.com>

* Adding Swedish translation

* Fix Metal renderer compilation on iOS

* [Core] Improve iOS compilation workflow

* [Qt] Hook Swedish to UI

* AppDataDocumentProvider: Typo (#740)

* More iOS work

* More iOS progress

* More iOS work

* AppDataDocumentProvider: Add missing ``COLUMN_FLAGS`` in the default document projectation (#741)

Fixes unable to copy files from device to app's internal storage problem

* More iOS work

* ios: Simplify MTKView interface (still doesn't work though)

* ios: Pass CAMetalLayer instead of void* to Obj-C++ bridging header

* Fix bridging cast

* FINALLY IOS GRAPHICS

* ios: Remove printf spam

* Metal: Reimplement some texture formats on iOS

* metal: implement texture decoder

* metal: check for format support

* metal: implement texture swizzling

* metal: remove unused texture functions

* Shadergen types: Add Metal & MSL

* Format

* Undo submodule changes

* Readme: Add Chonkystation 3

* Metal: Use std::unique_ptr for texture decode

* AppDataDocumentProvider: Allow to remove documents (#744)

* AppDataDocumentProvider: Allow to remove documents

* Typo

* Metal renderer fixes for iOS

* iOS driver: Add doc comments

* iOS: Add frontend & frontend build files (#746)

* iOS: Add SwiftUI part to repo

* Add iOS build script

* Update SDL2 submodule

* Fix iOS build script

* CI: Update xcode tools for iOS

* Update iOS_Build.yml

* Update iOS build

* Lower XCode version

* A

* Update project.pbxproj

* Update iOS_Build.yml

* Update iOS_Build.yml

* Update build.sh

* iOS: Fail on build error

* iOS: Add file picker (#747)

* iOS: Add file picker

* Fix lock placement

* Qt: Add runpog icon (#752)

* Update discord-rpc submodule (#753)

* Remove cryptoppwin submodule (#754)

---------

Co-authored-by: henry <23128103+atem2069@users.noreply.github.com>
Co-authored-by: smiRaphi <neogt404@gmail.com>
Co-authored-by: smiRaphi <87574679+smiRaphi@users.noreply.github.com>
Co-authored-by: Daniel Nylander <po@danielnylander.se>
Co-authored-by: Ishan09811 <156402647+Ishan09811@users.noreply.github.com>
Co-authored-by: Samuliak <samuliak77@gmail.com>
Co-authored-by: Albert <45282415+ggrtk@users.noreply.github.com>

---------

Co-authored-by: henry <23128103+atem2069@users.noreply.github.com>
Co-authored-by: smiRaphi <neogt404@gmail.com>
Co-authored-by: smiRaphi <87574679+smiRaphi@users.noreply.github.com>
Co-authored-by: Daniel Nylander <po@danielnylander.se>
Co-authored-by: Ishan09811 <156402647+Ishan09811@users.noreply.github.com>
Co-authored-by: Samuliak <samuliak77@gmail.com>
Co-authored-by: Albert <45282415+ggrtk@users.noreply.github.com>
This commit is contained in:
wheremyfoodat
2025-10-12 00:00:15 +03:00
committed by GitHub
parent 3701fb6ca3
commit 72b9aecda5
8 changed files with 95 additions and 17 deletions

View File

@@ -80,6 +80,14 @@ void Kernel::arbitrateAddress() {
break;
}
case ArbitrationType::WaitIfLessTimeout: {
s32 word = static_cast<s32>(mem.read32(address)); // Yes this is meant to be signed
if (word < value) {
sleepThreadOnArbiterWithTimeout(address, ns);
}
break;
}
case ArbitrationType::Signal: signalArbiter(address, value); break;
default: Helpers::panic("ArbitrateAddress: Unimplemented type %s", arbitrationTypeToString(type));
}
@@ -96,8 +104,9 @@ void Kernel::signalArbiter(u32 waitingAddress, s32 threadCount) {
// Wake threads with the highest priority threads being woken up first
for (auto index : threadIndices) {
Thread& t = threads[index];
if (t.status == ThreadStatus::WaitArbiter && t.waitingAddress == waitingAddress) {
if ((t.status == ThreadStatus::WaitArbiter || t.status == ThreadStatus::WaitArbiterTimeout) && t.waitingAddress == waitingAddress) {
t.status = ThreadStatus::Ready;
t.gprs[0] = Result::Success; // Return that the arbiter was actually signalled and that we didn't timeout
count += 1;
// Check if we've reached the max number of. If count < 0 then all threads are released.

View File

@@ -138,6 +138,7 @@ void Kernel::waitSynchronization1() {
// Add the current thread to the object's wait list
object->getWaitlist() |= (1ull << currentThreadIndex);
addWakeupEvent(t.wakeupTick);
requireReschedule();
}
}
@@ -232,6 +233,7 @@ void Kernel::waitSynchronizationN() {
waitObjects[i].second->getWaitlist() |= (1ull << currentThreadIndex); // And add the thread to the object's waitlist
}
addWakeupEvent(t.wakeupTick);
requireReschedule();
} else {
Helpers::panic("WaitSynchronizationN with waitAll");

View File

@@ -1,6 +1,7 @@
#include "kernel.hpp"
#include <cassert>
#include <limits>
#include "cpu.hpp"
#include "kernel_types.hpp"
@@ -161,6 +162,7 @@ void Kernel::reset() {
threadIndices.clear();
serviceManager.reset();
nextScheduledWakeupTick = std::numeric_limits<u64>::max();
needReschedule = false;
// Allocate handle #0 to a dummy object and make a main process object

View File

@@ -2,6 +2,7 @@
#include <bit>
#include <cassert>
#include <cstring>
#include <limits>
#include "arm_defs.hpp"
#include "kernel.hpp"
@@ -50,7 +51,7 @@ bool Kernel::canThreadRun(const Thread& t) {
if (t.status == ThreadStatus::Ready) {
return true;
} else if (t.status == ThreadStatus::WaitSleep || t.status == ThreadStatus::WaitSync1 || t.status == ThreadStatus::WaitSyncAny ||
t.status == ThreadStatus::WaitSyncAll) {
t.status == ThreadStatus::WaitSyncAll || t.status == ThreadStatus::WaitArbiterTimeout) {
// TODO: Set r0 to the correct error code on timeout for WaitSync{1/Any/All}
return cpu.getTicks() >= t.wakeupTick;
}
@@ -215,6 +216,23 @@ void Kernel::sleepThreadOnArbiter(u32 waitingAddress) {
requireReschedule();
}
void Kernel::sleepThreadOnArbiterWithTimeout(u32 waitingAddress, s64 timeoutNs) {
regs[0] = Result::OS::Timeout; // This will be overwritten with success if we don't timeout
// Timeout is 0, don't bother waiting, instantly timeout
if (timeoutNs == 0) {
return;
}
Thread& t = threads[currentThreadIndex];
t.status = ThreadStatus::WaitArbiterTimeout;
t.waitingAddress = waitingAddress;
t.wakeupTick = getWakeupTick(timeoutNs);
addWakeupEvent(t.wakeupTick);
requireReschedule();
}
// Acquires an object that is **ready to be acquired** without waiting on it
void Kernel::acquireSyncObject(KernelObject* object, const Thread& thread) {
switch (object->type) {
@@ -390,6 +408,7 @@ void Kernel::sleepThread(s64 ns) {
t.status = ThreadStatus::WaitSleep;
t.wakeupTick = getWakeupTick(ns);
addWakeupEvent(t.wakeupTick);
requireReschedule();
}
}
@@ -688,6 +707,42 @@ bool Kernel::shouldWaitOnObject(KernelObject* object) {
}
}
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 || t.status == ThreadStatus::WaitArbiterTimeout) {
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);
}
}
std::vector<Thread> Kernel::getMainProcessThreads() {
// Sort the thread indices so that they appear nicer in the debugger
auto indices = threadIndices;