mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-09 23:55:40 +12:00
[Kernel] Fully implement semaphores
This commit is contained in:
parent
d6a107afef
commit
09ba66ae60
3 changed files with 62 additions and 0 deletions
|
@ -133,7 +133,9 @@ private:
|
||||||
void svcCloseHandle();
|
void svcCloseHandle();
|
||||||
void svcCreateEvent();
|
void svcCreateEvent();
|
||||||
void svcCreateMutex();
|
void svcCreateMutex();
|
||||||
|
void svcCreateSemaphore();
|
||||||
void svcReleaseMutex();
|
void svcReleaseMutex();
|
||||||
|
void svcReleaseSemaphore();
|
||||||
void svcSignalEvent();
|
void svcSignalEvent();
|
||||||
void svcSleepThread();
|
void svcSleepThread();
|
||||||
void connectToPort();
|
void connectToPort();
|
||||||
|
|
|
@ -36,6 +36,8 @@ void Kernel::serviceSVC(u32 svc) {
|
||||||
case 0x0C: setThreadPriority(); break;
|
case 0x0C: setThreadPriority(); break;
|
||||||
case 0x13: svcCreateMutex(); break;
|
case 0x13: svcCreateMutex(); break;
|
||||||
case 0x14: svcReleaseMutex(); break;
|
case 0x14: svcReleaseMutex(); break;
|
||||||
|
case 0x15: svcCreateSemaphore(); break;
|
||||||
|
case 0x16: svcReleaseSemaphore(); break;
|
||||||
case 0x17: svcCreateEvent(); break;
|
case 0x17: svcCreateEvent(); break;
|
||||||
case 0x18: svcSignalEvent(); break;
|
case 0x18: svcSignalEvent(); break;
|
||||||
case 0x19: svcClearEvent(); break;
|
case 0x19: svcClearEvent(); break;
|
||||||
|
|
|
@ -231,6 +231,15 @@ void Kernel::acquireSyncObject(KernelObject* object, const Thread& thread) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case KernelObjectType::Semaphore: {
|
||||||
|
Semaphore* s = object->getData<Semaphore>();
|
||||||
|
if (s->availableCount <= 0) [[unlikely]] // This should be unreachable but let's check anyways
|
||||||
|
Helpers::panic("Tried to acquire unacquirable semaphore");
|
||||||
|
|
||||||
|
s->availableCount -= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case KernelObjectType::Thread:
|
case KernelObjectType::Thread:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -493,6 +502,55 @@ void Kernel::svcReleaseMutex() {
|
||||||
releaseMutex(moo);
|
releaseMutex(moo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Kernel::svcCreateSemaphore() {
|
||||||
|
s32 initialCount = static_cast<s32>(regs[1]);
|
||||||
|
s32 maxCount = static_cast<s32>(regs[2]);
|
||||||
|
logSVC("CreateSemaphore (initial count = %d, max count = %d)\n", initialCount, maxCount);
|
||||||
|
|
||||||
|
if (initialCount > maxCount)
|
||||||
|
Helpers::panic("CreateSemaphore: Initial count higher than max count");
|
||||||
|
|
||||||
|
if (initialCount < 0 || maxCount < 0)
|
||||||
|
Helpers::panic("CreateSemaphore: Negative count value");
|
||||||
|
|
||||||
|
regs[0] = SVCResult::Success;
|
||||||
|
regs[1] = makeSemaphore(initialCount, maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kernel::svcReleaseSemaphore() {
|
||||||
|
const Handle handle = regs[1];
|
||||||
|
const s32 releaseCount = static_cast<s32>(regs[2]);
|
||||||
|
logSVC("ReleaseSemaphore (handle = %X, release count = %d)\n", handle, releaseCount);
|
||||||
|
|
||||||
|
const auto object = getObject(handle, KernelObjectType::Semaphore);
|
||||||
|
if (object == nullptr) [[unlikely]] {
|
||||||
|
Helpers::panic("Tried to release non-existent semaphore");
|
||||||
|
regs[0] = SVCResult::BadHandle;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (releaseCount < 0)
|
||||||
|
Helpers::panic("ReleaseSemaphore: Negative count");
|
||||||
|
|
||||||
|
Semaphore* s = object->getData<Semaphore>();
|
||||||
|
if (s->maximumCount - s->availableCount < releaseCount)
|
||||||
|
Helpers::panic("ReleaseSemaphore: Release count too high");
|
||||||
|
|
||||||
|
// Write success and old available count to r0 and r1 respectively
|
||||||
|
regs[0] = SVCResult::Success;
|
||||||
|
regs[1] = s->availableCount;
|
||||||
|
// Bump available count
|
||||||
|
s->availableCount += releaseCount;
|
||||||
|
|
||||||
|
// Wake up threads one by one until the available count hits 0 or we run out of threads to wake up
|
||||||
|
while (s->availableCount > 0 && s->waitlist != 0) {
|
||||||
|
int index = wakeupOneThread(s->waitlist, handle); // Wake up highest priority thread
|
||||||
|
s->waitlist ^= (1ull << index); // Remove thread from waitlist
|
||||||
|
|
||||||
|
s->availableCount--; // Decrement available count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns whether an object is waitable or not
|
// Returns whether an object is waitable or not
|
||||||
// The KernelObject type enum is arranged in a specific order in kernel_types.hpp so this
|
// The KernelObject type enum is arranged in a specific order in kernel_types.hpp so this
|
||||||
// can simply compile to a fast sub+cmp+set despite looking slow
|
// can simply compile to a fast sub+cmp+set despite looking slow
|
||||||
|
|
Loading…
Add table
Reference in a new issue