From 690eb0636a6e2d85ff0421cd6846feaa4de4bbac Mon Sep 17 00:00:00 2001 From: James Benton Date: Wed, 8 Jul 2015 22:10:35 +0100 Subject: [PATCH] Implement all the thread synchronisation objects for the new scheduler. Event, fastmutex, messagequeue, mutex, condition, semaphore. This also gets rid of the silly systemobject system, yay! Add some stubs for Alarm, need interrupt support in our CPU to implement. --- build/wiiu.vcxproj | 6 +- build/wiiu.vcxproj.filters | 18 +- src/codetests.cpp | 12 +- src/kernelfunctionlog.h | 2 +- src/main.cpp | 4 + src/modules/coreinit/coreinit.cpp | 5 +- src/modules/coreinit/coreinit.h | 1 + src/modules/coreinit/coreinit_alarm.cpp | 69 +++++ src/modules/coreinit/coreinit_alarm.h | 85 +++++++ src/modules/coreinit/coreinit_event.cpp | 237 ++++++++++++------ src/modules/coreinit/coreinit_event.h | 42 ++-- src/modules/coreinit/coreinit_fastmutex.cpp | 31 ++- src/modules/coreinit/coreinit_fastmutex.h | 63 ++++- .../coreinit/coreinit_messagequeue.cpp | 160 ++++++------ src/modules/coreinit/coreinit_messagequeue.h | 63 +++-- src/modules/coreinit/coreinit_mutex.cpp | 200 +++++++-------- src/modules/coreinit/coreinit_mutex.h | 87 ++++--- src/modules/coreinit/coreinit_queue.h | 127 ++++++++++ src/modules/coreinit/coreinit_scheduler.cpp | 93 +++++++ src/modules/coreinit/coreinit_scheduler.h | 29 ++- src/modules/coreinit/coreinit_semaphore.cpp | 96 +++---- src/modules/coreinit/coreinit_semaphore.h | 30 +-- src/modules/coreinit/coreinit_thread.cpp | 168 ++----------- src/modules/coreinit/coreinit_thread.h | 89 +++---- src/modules/coreinit/coreinit_threadqueue.cpp | 81 ++++++ src/modules/coreinit/coreinit_threadqueue.h | 59 +++++ src/processor.cpp | 1 + src/processor.h | 1 + src/system.cpp | 34 +-- src/system.h | 42 +--- src/systemobject.h | 18 -- src/systemtypes.h | 1 - 32 files changed, 1229 insertions(+), 725 deletions(-) create mode 100755 src/modules/coreinit/coreinit_alarm.cpp create mode 100755 src/modules/coreinit/coreinit_alarm.h create mode 100755 src/modules/coreinit/coreinit_queue.h create mode 100755 src/modules/coreinit/coreinit_threadqueue.cpp create mode 100755 src/modules/coreinit/coreinit_threadqueue.h delete mode 100644 src/systemobject.h diff --git a/build/wiiu.vcxproj b/build/wiiu.vcxproj index 977714a0..82491283 100644 --- a/build/wiiu.vcxproj +++ b/build/wiiu.vcxproj @@ -113,6 +113,7 @@ + @@ -136,6 +137,7 @@ + @@ -188,14 +190,17 @@ + + + @@ -210,7 +215,6 @@ - diff --git a/build/wiiu.vcxproj.filters b/build/wiiu.vcxproj.filters index 1acba32e..0071db8c 100644 --- a/build/wiiu.vcxproj.filters +++ b/build/wiiu.vcxproj.filters @@ -321,6 +321,12 @@ Source Files\modules\coreinit + + Source Files\modules\coreinit + + + Source Files\modules\coreinit + @@ -470,9 +476,6 @@ Header Files\interpreter - - Header Files\system - Header Files\modules\coreinit @@ -581,5 +584,14 @@ Header Files\modules\coreinit + + Header Files\modules\coreinit + + + Header Files\modules\coreinit + + + Header Files\modules\coreinit + \ No newline at end of file diff --git a/src/codetests.cpp b/src/codetests.cpp index 9948fa39..051d8360 100644 --- a/src/codetests.cpp +++ b/src/codetests.cpp @@ -184,22 +184,22 @@ loadTestElf(const std::string &path, TestFile &tests) return true; } -static std::string & -ltrim(std::string &s) +static std::string +ltrim(std::string s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(std::isspace)))); return s; } -static std::string & -rtrim(std::string &s) +static std::string +rtrim(std::string s) { s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); return s; } -static std::string & -trim(std::string &s) +static std::string +trim(std::string s) { return ltrim(rtrim(s)); } diff --git a/src/kernelfunctionlog.h b/src/kernelfunctionlog.h index 44758850..bbbf9ada 100755 --- a/src/kernelfunctionlog.h +++ b/src/kernelfunctionlog.h @@ -19,7 +19,7 @@ struct LogState static inline void logCall(LogState &state, const char *name) { - auto len = sprintf_s(state.buffer, state.length, "%s(", name); + auto len = sprintf_s(state.buffer + state.pos, state.length, "%s(", name); state.length -= len; state.pos += len; } diff --git a/src/main.cpp b/src/main.cpp index cb0f5886..9a8a71c5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -216,6 +216,10 @@ play(const std::string &path) OSCreateThread(thread0, 0, 0, nullptr, stack0top, stackSize, 16, OSThreadAttributes::AffinityCPU0); OSCreateThread(thread2, 0, 0, nullptr, stack2top, stackSize, 16, OSThreadAttributes::AffinityCPU2); + // Set the two idle threads to inactive + thread0->state = OSThreadState::None; + thread2->state = OSThreadState::None; + // Create the main thread for core1 OSCreateThread(thread1, entryPoint, 0, nullptr, stack1top, stackSize, 16, OSThreadAttributes::AffinityCPU1); diff --git a/src/modules/coreinit/coreinit.cpp b/src/modules/coreinit/coreinit.cpp index 80207c7b..7a9e54c8 100644 --- a/src/modules/coreinit/coreinit.cpp +++ b/src/modules/coreinit/coreinit.cpp @@ -13,11 +13,12 @@ CoreInit::~CoreInit() void CoreInit::initialise() { + initialiseDynLoad(); + initialiseEvent(); + initialiseGHS(); initialiseMembase(); initialiseMessageQueues(); - initialiseGHS(); initialiseSystemInformation(); - initialiseDynLoad(); } void diff --git a/src/modules/coreinit/coreinit.h b/src/modules/coreinit/coreinit.h index 1a300667..95a4861c 100644 --- a/src/modules/coreinit/coreinit.h +++ b/src/modules/coreinit/coreinit.h @@ -11,6 +11,7 @@ public: private: void initialiseDynLoad(); + void initialiseEvent(); void initialiseGHS(); void initialiseMembase(); void initialiseMessageQueues(); diff --git a/src/modules/coreinit/coreinit_alarm.cpp b/src/modules/coreinit/coreinit_alarm.cpp new file mode 100755 index 00000000..061c7750 --- /dev/null +++ b/src/modules/coreinit/coreinit_alarm.cpp @@ -0,0 +1,69 @@ +#include "coreinit.h" +#include "coreinit_alarm.h" + +BOOL +OSCancelAlarm(OSAlarm *alarm) +{ + assert(false); + return FALSE; +} + +void +OSCancelAlarms(uint32_t alarmTag) +{ + assert(false); +} + +void +OSCreateAlarm(OSAlarm *alarm) +{ + OSCreateAlarmEx(alarm, nullptr); +} + +void +OSCreateAlarmEx(OSAlarm *alarm, const char *name) +{ + memset(alarm, 0, sizeof(OSAlarm)); + alarm->tag = OSAlarm::Tag; + alarm->name = name; + OSInitThreadQueueEx(&alarm->threadQueue, alarm); +} + +void * +OSGetAlarmUserData(OSAlarm *alarm) +{ + return alarm->userData; +} + +BOOL +OSSetAlarm(OSAlarm *alarm, Time time, AlarmCallback callback) +{ + assert(false); + return FALSE; +} + +BOOL +OSSetPeriodicAlarm(OSAlarm *alarm, Time start, Time interval, AlarmCallback callback) +{ + assert(false); + return FALSE; +} + +void +OSSetAlarmTag(OSAlarm *alarm, uint32_t alarmTag) +{ + alarm->alarmTag = alarmTag; +} + +void +OSSetAlarmUserData(OSAlarm *alarm, void *data) +{ + alarm->userData = data; +} + +BOOL +OSWaitAlarm(OSAlarm *alarm) +{ + assert(false); + return FALSE; +} diff --git a/src/modules/coreinit/coreinit_alarm.h b/src/modules/coreinit/coreinit_alarm.h new file mode 100755 index 00000000..6ed422bd --- /dev/null +++ b/src/modules/coreinit/coreinit_alarm.h @@ -0,0 +1,85 @@ +#pragma once +#include "systemtypes.h" +#include "coreinit_threadqueue.h" +#include "coreinit_time.h" + +#pragma pack(push, 1) + +struct OSAlarm; +struct OSContext; +using AlarmCallback = wfunc_ptr; + +struct OSAlarmQueue +{ + static const uint32_t Tag = 0x614C6D51; + be_val tag; + be_ptr name; + UNKNOWN(4); + + OSThreadQueue threadQueue; + be_ptr head; + be_ptr tail; +}; +CHECK_OFFSET(OSAlarmQueue, 0x00, tag); +CHECK_OFFSET(OSAlarmQueue, 0x04, name); +CHECK_OFFSET(OSAlarmQueue, 0x0c, threadQueue); +CHECK_OFFSET(OSAlarmQueue, 0x1c, head); +CHECK_OFFSET(OSAlarmQueue, 0x20, tail); +CHECK_SIZE(OSAlarmQueue, 0x24); + +struct OSAlarm +{ + static const uint32_t Tag = 0x614C724D; + be_val tag; + be_ptr name; + UNKNOWN(4); + AlarmCallback callback; + be_val alarmTag; // Like group in memheap + UNKNOWN(0x38 - 0x14); + be_ptr userData; + UNKNOWN(4); + OSThreadQueue threadQueue; + be_ptr alarmQueue; + be_ptr context; +}; +CHECK_OFFSET(OSAlarm, 0x00, tag); +CHECK_OFFSET(OSAlarm, 0x04, name); +CHECK_OFFSET(OSAlarm, 0x0c, callback); +CHECK_OFFSET(OSAlarm, 0x10, alarmTag); +CHECK_OFFSET(OSAlarm, 0x38, userData); +CHECK_OFFSET(OSAlarm, 0x40, threadQueue); +CHECK_OFFSET(OSAlarm, 0x50, alarmQueue); +CHECK_OFFSET(OSAlarm, 0x54, context); +CHECK_SIZE(OSAlarm, 0x58); + +#pragma pack(pop) + +BOOL +OSCancelAlarm(OSAlarm *alarm); + +void +OSCancelAlarms(uint32_t alarmTag); + +void +OSCreateAlarm(OSAlarm *alarm); + +void +OSCreateAlarmEx(OSAlarm *alarm, const char *name); + +void * +OSGetAlarmUserData(OSAlarm *alarm); + +BOOL +OSSetAlarm(OSAlarm *alarm, Time time, AlarmCallback callback); + +BOOL +OSSetPeriodicAlarm(OSAlarm *alarm, Time start, Time interval, AlarmCallback callback); + +void +OSSetAlarmTag(OSAlarm *alarm, uint32_t alarmTag); + +void +OSSetAlarmUserData(OSAlarm *alarm, void *data); + +BOOL +OSWaitAlarm(OSAlarm *alarm); diff --git a/src/modules/coreinit/coreinit_event.cpp b/src/modules/coreinit/coreinit_event.cpp index 2523f8aa..3b6f8847 100644 --- a/src/modules/coreinit/coreinit_event.cpp +++ b/src/modules/coreinit/coreinit_event.cpp @@ -1,132 +1,196 @@ #include "coreinit.h" +#include "coreinit_alarm.h" #include "coreinit_event.h" -#include "coreinit_thread.h" +#include "coreinit_memheap.h" +#include "coreinit_scheduler.h" #include "system.h" -#include "processor.h" void -OSInitEvent(EventHandle handle, bool value, EventMode mode) +OSInitEvent(OSEvent *event, bool value, EventMode mode) { - OSInitEventEx(handle, value, mode, nullptr); + OSInitEventEx(event, value, mode, nullptr); } void -OSInitEventEx(EventHandle handle, bool value, EventMode mode, char *name) +OSInitEventEx(OSEvent *event, bool value, EventMode mode, char *name) { - auto event = gSystem.addSystemObject(handle); + event->tag = OSEvent::Tag; event->mode = mode; event->value = value; event->name = name; + OSInitThreadQueueEx(&event->queue, event); } void -OSSignalEvent(EventHandle handle) +OSSignalEvent(OSEvent *event) { - auto event = gSystem.getSystemObject(handle); - std::unique_lock lock { event->mutex }; + OSLockScheduler(); + assert(event); + assert(event->tag == OSEvent::Tag); - event->value = TRUE; - - if (event->mode == EventMode::ManualReset) { - // Wake all waiting fibers - for (auto fiber : event->queue) { - gProcessor.queue(fiber); - } - - event->queue.clear(); - } else if (event->mode == EventMode::AutoReset) { - // Wake highest priority fiber - Fiber *highest = nullptr; - - for (auto fiber : event->queue) { - if (!highest || fiber->thread->basePriority > highest->thread->basePriority) { - highest = fiber; - } - } - - if (highest) { - gProcessor.queue(highest); - event->queue.erase(std::remove(event->queue.begin(), event->queue.end(), highest), event->queue.end()); - } - } -} - -void -OSSignalEventAll(EventHandle handle) -{ - auto event = gSystem.getSystemObject(handle); - std::unique_lock lock { event->mutex }; - event->value = TRUE; - - // Wake all fibers - for (auto fiber : event->queue) { - gProcessor.queue(fiber); + if (event->value != FALSE) { + // Event has already been set + OSUnlockScheduler(); + return; } - event->queue.clear(); + // Set event + event->value = TRUE; + + if (!OSIsThreadQueueEmpty(&event->queue)) { + if (event->mode == EventMode::AutoReset) { + // Reset value + event->value = FALSE; + + // Wakeup one thread + auto thread = OSPopFrontThreadQueue(&event->queue); + OSWakeupOneThreadNoLock(thread); + OSRescheduleNoLock(); + } else { + // Wakeup all threads + OSWakeupThreadNoLock(&event->queue); + OSRescheduleNoLock(); + } + } + + OSUnlockScheduler(); } void -OSResetEvent(EventHandle handle) +OSSignalEventAll(OSEvent *event) { - auto event = gSystem.getSystemObject(handle); - std::unique_lock lock { event->mutex }; + OSLockScheduler(); + assert(event); + assert(event->tag == OSEvent::Tag); + + if (event->value != FALSE) { + // Event has already been set + OSUnlockScheduler(); + return; + } + + // Set event + event->value = TRUE; + + if (!OSIsThreadQueueEmpty(&event->queue)) { + if (event->mode == EventMode::AutoReset) { + // Reset event + event->value = FALSE; + } + + // Wakeup all threads + OSWakeupThreadNoLock(&event->queue); + OSRescheduleNoLock(); + } + + OSUnlockScheduler(); +} + +void +OSResetEvent(OSEvent *event) +{ + OSLockScheduler(); + assert(event); + assert(event->tag == OSEvent::Tag); + + // Reset event event->value = FALSE; + + OSUnlockScheduler(); } void -OSWaitEvent(EventHandle handle) +OSWaitEvent(OSEvent *event) { - auto event = gSystem.getSystemObject(handle); - auto fiber = gProcessor.getCurrentFiber(); + OSLockScheduler(); + assert(event); + assert(event->tag == OSEvent::Tag); - while (!event->value) { - std::unique_lock lock { event->mutex }; + if (event->value) { + // Event is already set - if (event->value) { - break; + if (event->mode == EventMode::AutoReset) { + // Reset event + event->value = FALSE; } - event->queue.push_back(fiber); - gProcessor.wait(lock); + OSUnlockScheduler(); + return; + } else { + // Wait for event to be set + OSSleepThreadNoLock(&event->queue); + OSRescheduleNoLock(); } - if (event->mode == EventMode::AutoReset) { - event->value = FALSE; - } + OSUnlockScheduler(); +} + +static AlarmCallback +pEventAlarmHandler = nullptr; + +struct EventAlarmData +{ + OSEvent *event; + OSThread *thread; + BOOL timeout; +}; + +void +EventAlarmHandler(OSAlarm *alarm, OSContext *context) +{ + OSLockScheduler(); + + // Wakeup the thread waiting on this alarm + auto data = reinterpret_cast(OSGetAlarmUserData(alarm)); + data->timeout = TRUE; + OSWakeupOneThreadNoLock(data->thread); + + OSUnlockScheduler(); } BOOL -OSWaitEventWithTimeout(EventHandle handle, Time timeout) +OSWaitEventWithTimeout(OSEvent *event, Time timeout) { - auto event = gSystem.getSystemObject(handle); - auto fiber = gProcessor.getCurrentFiber(); - auto start = std::chrono::system_clock::now(); + BOOL result = TRUE; + OSLockScheduler(); - while (!event->value) { - std::unique_lock lock { event->mutex }; - - if (event->value) { - break; + // Check if event is already set + if (event->value) { + if (event->mode == EventMode::AutoReset) { + // Reset event + event->value = FALSE; } - // Check for timeout - auto diff = std::chrono::system_clock::now() - start; - auto ns = std::chrono::duration_cast(diff).count(); - - if (ns >= timeout) { - return FALSE; - } - - event->queue.push_back(fiber); - gProcessor.wait(lock); + OSUnlockScheduler(); + return TRUE; } - if (event->mode == EventMode::AutoReset) { - event->value = FALSE; + // Setup some alarm data for callback + auto data = OSAllocFromSystem(); + data->event = event; + data->thread = OSGetCurrentThread(); + data->timeout = FALSE; + + // Create an alarm to trigger timeout + auto alarm = OSAllocFromSystem(); + OSCreateAlarm(alarm); + OSSetAlarmUserData(alarm, data); + OSSetAlarm(alarm, timeout, pEventAlarmHandler); + + // Wait for the event + OSSleepThreadNoLock(&event->queue); + OSRescheduleNoLock(); + + if (data->timeout) { + // Timed out, remove from wait queue + OSEraseFromThreadQueue(&event->queue, data->thread); + result = FALSE; } - return TRUE; + OSFreeToSystem(data); + OSFreeToSystem(alarm); + OSUnlockScheduler(); + return result; } void @@ -139,4 +203,11 @@ CoreInit::registerEventFunctions() RegisterKernelFunction(OSResetEvent); RegisterKernelFunction(OSWaitEvent); RegisterKernelFunction(OSWaitEventWithTimeout); + RegisterKernelFunction(EventAlarmHandler); +} + +void +CoreInit::initialiseEvent() +{ + pEventAlarmHandler = findExportAddress("EventAlarmHandler"); } diff --git a/src/modules/coreinit/coreinit_event.h b/src/modules/coreinit/coreinit_event.h index 3e67d57d..4107c820 100644 --- a/src/modules/coreinit/coreinit_event.h +++ b/src/modules/coreinit/coreinit_event.h @@ -1,45 +1,53 @@ #pragma once #include "coreinit_time.h" -#include "systemobject.h" +#include "coreinit_threadqueue.h" -enum class EventMode +enum class EventMode : uint32_t { ManualReset = 0, AutoReset = 1 }; -struct Fiber; +#pragma pack(push, 1) -struct Event : public SystemObject +struct OSEvent { static const uint32_t Tag = 0x65566E54; - char *name; - EventMode mode; - std::atomic value; - std::mutex mutex; - std::vector queue; + be_val tag; + be_ptr name; + UNKNOWN(4); + be_val value; + OSThreadQueue queue; + be_val mode; }; -using EventHandle = SystemObjectHeader *; +CHECK_OFFSET(OSEvent, 0x0, tag); +CHECK_OFFSET(OSEvent, 0x4, name); +CHECK_OFFSET(OSEvent, 0xc, value); +CHECK_OFFSET(OSEvent, 0x10, queue); +CHECK_OFFSET(OSEvent, 0x20, mode); +CHECK_SIZE(OSEvent, 0x24); + +#pragma pack(pop) void -OSInitEvent(EventHandle handle, bool value, EventMode mode); +OSInitEvent(OSEvent *event, bool value, EventMode mode); void -OSInitEventEx(EventHandle handle, bool value, EventMode mode, char *name); +OSInitEventEx(OSEvent *event, bool value, EventMode mode, char *name); void -OSSignalEvent(EventHandle handle); +OSSignalEvent(OSEvent *event); void -OSSignalEventAll(EventHandle handle); +OSSignalEventAll(OSEvent *event); void -OSWaitEvent(EventHandle handle); +OSWaitEvent(OSEvent *event); void -OSResetEvent(EventHandle handle); +OSResetEvent(OSEvent *event); BOOL -OSWaitEventWithTimeout(EventHandle handle, Time timeout); +OSWaitEventWithTimeout(OSEvent *event, Time timeout); diff --git a/src/modules/coreinit/coreinit_fastmutex.cpp b/src/modules/coreinit/coreinit_fastmutex.cpp index a0a8b404..46fbe748 100644 --- a/src/modules/coreinit/coreinit_fastmutex.cpp +++ b/src/modules/coreinit/coreinit_fastmutex.cpp @@ -2,49 +2,48 @@ #include "coreinit_fastmutex.h" #include "coreinit_mutex.h" -// TODO: Fast Mutex is platform specific, lets just use normal mutex for now. -// Linux: futex, Windows8+ WaitOnAddress +// TODO: Implement fast mutex void -OSFastMutex_Init(FastMutexHandle handle, char *name) +OSFastMutex_Init(OSFastMutex *mutex, const char *name) { - OSInitMutexEx(handle, name); + OSInitMutexEx(reinterpret_cast(mutex), name); } void -OSFastMutex_Lock(FastMutexHandle handle) +OSFastMutex_Lock(OSFastMutex *mutex) { - OSLockMutex(handle); + OSLockMutex(reinterpret_cast(mutex)); } void -OSFastMutex_Unlock(FastMutexHandle handle) +OSFastMutex_Unlock(OSFastMutex *mutex) { - OSUnlockMutex(handle); + OSUnlockMutex(reinterpret_cast(mutex)); } BOOL -OSFastMutex_TryLock(FastMutexHandle handle) +OSFastMutex_TryLock(OSFastMutex *mutex) { - return OSTryLockMutex(handle); + return OSTryLockMutex(reinterpret_cast(mutex)); } void -OSFastCond_Init(FastConditionHandle handle, char *name) +OSFastCond_Init(OSFastCondition *condition, const char *name) { - OSInitCondEx(handle, name); + OSInitCondEx(reinterpret_cast(condition), name); } void -OSFastCond_Wait(FastConditionHandle conditionHandle, FastMutexHandle mutexHandle) +OSFastCond_Wait(OSFastCondition *condition, OSFastMutex *mutex) { - OSWaitCond(conditionHandle, mutexHandle); + OSWaitCond(reinterpret_cast(condition), reinterpret_cast(mutex)); } void -OSFastCond_Signal(FastConditionHandle handle) +OSFastCond_Signal(OSFastCondition *condition) { - OSSignalCond(handle); + OSSignalCond(reinterpret_cast(condition)); } void diff --git a/src/modules/coreinit/coreinit_fastmutex.h b/src/modules/coreinit/coreinit_fastmutex.h index de23b318..5ea8fe30 100644 --- a/src/modules/coreinit/coreinit_fastmutex.h +++ b/src/modules/coreinit/coreinit_fastmutex.h @@ -1,27 +1,70 @@ #pragma once -#include "systemobject.h" #include "systemtypes.h" +#include "coreinit_threadqueue.h" -using FastMutexHandle = p32; -using FastConditionHandle = p32; +#pragma pack(push, 1) + +struct OSFastMutex; + +struct OSFastMutexLink +{ + be_ptr next; + be_ptr prev; +}; +CHECK_OFFSET(OSFastMutexLink, 0x00, next); +CHECK_OFFSET(OSFastMutexLink, 0x04, prev); +CHECK_SIZE(OSFastMutexLink, 0x08); + +struct OSFastMutex +{ + static const uint32_t Tag = 0x664D7458; + + be_val tag; + be_ptr name; + UNKNOWN(4); + OSThreadSimpleQueue queue; + OSFastMutexLink link; + UNKNOWN(16); +}; +CHECK_OFFSET(OSFastMutex, 0x00, tag); +CHECK_OFFSET(OSFastMutex, 0x04, name); +CHECK_OFFSET(OSFastMutex, 0x0c, queue); +CHECK_OFFSET(OSFastMutex, 0x14, link); +CHECK_SIZE(OSFastMutex, 0x2c); + +struct OSFastCondition +{ + static const uint32_t Tag = 0x664E6456; + + be_val tag; + be_ptr name; + UNKNOWN(4); + OSThreadQueue queue; +}; +CHECK_OFFSET(OSFastCondition, 0x00, tag); +CHECK_OFFSET(OSFastCondition, 0x04, name); +CHECK_OFFSET(OSFastCondition, 0x0c, queue); +CHECK_SIZE(OSFastCondition, 0x1c); + +#pragma pack(pop) void -OSFastMutex_Init(FastMutexHandle handle, char *name); +OSFastMutex_Init(OSFastMutex *mutex, const char *name); void -OSFastMutex_Lock(FastMutexHandle handle); +OSFastMutex_Lock(OSFastMutex *mutex); void -OSFastMutex_Unlock(FastMutexHandle handle); +OSFastMutex_Unlock(OSFastMutex *mutex); BOOL -OSFastMutex_TryLock(FastMutexHandle handle); +OSFastMutex_TryLock(OSFastMutex *mutex); void -OSFastCond_Init(FastConditionHandle handle, char *name); +OSFastCond_Init(OSFastCondition *condition, const char *name); void -OSFastCond_Wait(FastConditionHandle conditionHandle, FastMutexHandle mutexHandle); +OSFastCond_Wait(OSFastCondition *condition, OSFastMutex *mutex); void -OSFastCond_Signal(FastConditionHandle handle); +OSFastCond_Signal(OSFastCondition *condition); diff --git a/src/modules/coreinit/coreinit_messagequeue.cpp b/src/modules/coreinit/coreinit_messagequeue.cpp index 63ffa2dd..bbbdb595 100644 --- a/src/modules/coreinit/coreinit_messagequeue.cpp +++ b/src/modules/coreinit/coreinit_messagequeue.cpp @@ -1,165 +1,157 @@ #include "coreinit.h" #include "coreinit_memheap.h" #include "coreinit_messagequeue.h" -#include "system.h" -#include "util.h" +#include "coreinit_scheduler.h" -static MessageQueueHandle +static OSMessageQueue * gSystemMessageQueue; static OSMessage * gSystemMessageArray; void -OSInitMessageQueue(MessageQueueHandle handle, OSMessage *messages, int32_t size) +OSInitMessageQueue(OSMessageQueue *queue, OSMessage *messages, int32_t size) { - OSInitMessageQueueEx(handle, messages, size, nullptr); + OSInitMessageQueueEx(queue, messages, size, nullptr); } void -OSInitMessageQueueEx(MessageQueueHandle handle, OSMessage *messages, int32_t size, char *name) +OSInitMessageQueueEx(OSMessageQueue *queue, OSMessage *messages, int32_t size, const char *name) { - auto queue = gSystem.addSystemObject(handle); + queue->tag = OSMessageQueue::Tag; queue->name = name; - queue->first = 0; - queue->count = 0; - queue->size = size; queue->messages = messages; - - queue->mutex = OSAllocMutex(); - queue->waitRead = OSAllocCondition(); - queue->waitSend = OSAllocCondition(); - - OSInitMutex(queue->mutex); - OSInitCond(queue->waitRead); - OSInitCond(queue->waitSend); + queue->size = size; + queue->first = 0; + queue->used = 0; + OSInitThreadQueueEx(&queue->sendQueue, queue); + OSInitThreadQueueEx(&queue->recvQueue, queue); } -// Insert at back of message queue BOOL -OSSendMessage(MessageQueueHandle handle, OSMessage *message, MessageFlags::Flags flags) +OSSendMessage(OSMessageQueue *queue, OSMessage *message, MessageFlags::Flags flags) { - auto queue = gSystem.getSystemObject(handle); - OSLockMutex(queue->mutex); + OSLockScheduler(); + assert(queue && queue->tag == OSMessageQueue::Tag); + assert(message); - if (!(flags & MessageFlags::Blocking) && queue->count == queue->size) { - // Do not wait for space + if (!(flags & MessageFlags::Blocking) && queue->used == queue->size) { + // Do not block waiting for space to insert message + OSUnlockScheduler(); return FALSE; } - // Wait for space - while (queue->count == queue->size) { - OSWaitCond(queue->waitSend, queue->mutex); + // Wait for space in the message queue + while (queue->used == queue->size) { + OSSleepThreadNoLock(&queue->sendQueue); + OSRescheduleNoLock(); } - auto index = (queue->first + queue->count) % queue->size; - auto dst = static_cast(queue->messages) + index; - // Copy into message array + auto index = (queue->first + queue->used) % queue->size; + auto dst = static_cast(queue->messages) + index; memcpy(dst, message, sizeof(OSMessage)); - queue->count++; + queue->used++; - // Wake up anyone waiting for message to read - OSUnlockMutex(queue->mutex); - OSSignalCond(queue->waitRead); + // Wakeup threads waiting to read message + OSWakeupThreadNoLock(&queue->recvQueue); + OSRescheduleNoLock(); + OSUnlockScheduler(); return TRUE; } -// Insert at front of message queue BOOL -OSJamMessage(MessageQueueHandle handle, OSMessage *message, MessageFlags::Flags flags) +OSJamMessage(OSMessageQueue *queue, OSMessage *message, MessageFlags::Flags flags) { - auto queue = gSystem.getSystemObject(handle); - uint32_t index; - OSLockMutex(queue->mutex); + OSLockScheduler(); + assert(queue && queue->tag == OSMessageQueue::Tag); + assert(message); - if (!(flags & MessageFlags::Blocking) && queue->count == queue->size) { - // Do not wait for space - OSUnlockMutex(queue->mutex); + if (!(flags & MessageFlags::Blocking) && queue->used == queue->size) { + // Do not block waiting for space to insert message + OSUnlockScheduler(); return FALSE; } - // Wait for space - while (queue->count == queue->size) { - OSWaitCond(queue->waitSend, queue->mutex); + // Wait for space in the message queue + while (queue->used == queue->size) { + OSSleepThreadNoLock(&queue->sendQueue); + OSRescheduleNoLock(); } - // Get index before front if (queue->first == 0) { - index = queue->size - 1; + queue->first = queue->size - 1; } else { - index = queue->first - 1; + queue->first--; } // Copy into message array - auto dst = static_cast(queue->messages) + index; + auto dst = static_cast(queue->messages) + queue->first; memcpy(dst, message, sizeof(OSMessage)); + queue->used++; - // Update queue start and count - queue->first = index; - queue->count++; - - // Wake up anyone waiting for message to read - OSUnlockMutex(queue->mutex); - OSSignalCond(queue->waitRead); + // Wakeup threads waiting to read message + OSWakeupThreadNoLock(&queue->recvQueue); + OSRescheduleNoLock(); + OSUnlockScheduler(); return TRUE; } -// Read from front of message queue BOOL -OSReceiveMessage(MessageQueueHandle handle, OSMessage *message, MessageFlags::Flags flags) +OSReceiveMessage(OSMessageQueue *queue, OSMessage *message, MessageFlags::Flags flags) { - auto queue = gSystem.getSystemObject(handle); - OSLockMutex(queue->mutex); + OSLockScheduler(); + assert(queue && queue->tag == OSMessageQueue::Tag); + assert(message); - if (!(flags & MessageFlags::Blocking) && queue->count == 0) { - // Do not wait for space - OSUnlockMutex(queue->mutex); + if (!(flags & MessageFlags::Blocking) && queue->used == 0) { + // Do not block waiting for a message to arrive + OSUnlockScheduler(); return FALSE; } - while (queue->count == 0) { - OSWaitCond(queue->waitRead, queue->mutex); + // Wait for a message to appear in queue + while (queue->used == 0) { + OSSleepThreadNoLock(&queue->recvQueue); + OSRescheduleNoLock(); } - - auto index = queue->first; - auto src = static_cast(queue->messages) + index; - - // Copy from message array + + // Copy into message array + auto src = static_cast(queue->messages) + queue->first; memcpy(message, src, sizeof(OSMessage)); queue->first = (queue->first + 1) % queue->size; - queue->count--; + queue->used--; - // Wake up anyone waiting for space to send - OSUnlockMutex(queue->mutex); - OSSignalCond(queue->waitSend); + // Wakeup threads waiting for space to send message + OSWakeupThreadNoLock(&queue->sendQueue); + OSRescheduleNoLock(); + OSUnlockScheduler(); return TRUE; } -// Peek from front of message queue BOOL -OSPeekMessage(MessageQueueHandle handle, OSMessage *message) +OSPeekMessage(OSMessageQueue *queue, OSMessage *message) { - auto queue = gSystem.getSystemObject(handle); - OSLockMutex(queue->mutex); + OSLockScheduler(); + assert(queue && queue->tag == OSMessageQueue::Tag); + assert(message); - if (queue->count == 0) { - OSUnlockMutex(queue->mutex); + if (queue->used == 0) { + OSUnlockScheduler(); return FALSE; } - // Copy from message array auto src = static_cast(queue->messages) + queue->first; memcpy(message, src, sizeof(OSMessage)); - OSUnlockMutex(queue->mutex); + OSUnlockScheduler(); return TRUE; } -MessageQueueHandle +OSMessageQueue * OSGetSystemMessageQueue() { return gSystemMessageQueue; @@ -180,7 +172,7 @@ CoreInit::registerMessageQueueFunctions() void CoreInit::initialiseMessageQueues() { - gSystemMessageQueue = OSAllocFromSystem(); + gSystemMessageQueue = OSAllocFromSystem(); gSystemMessageArray = reinterpret_cast(OSAllocFromSystem(16 * sizeof(OSMessage))); OSInitMessageQueue(gSystemMessageQueue, gSystemMessageArray, 16); } diff --git a/src/modules/coreinit/coreinit_messagequeue.h b/src/modules/coreinit/coreinit_messagequeue.h index f62096f0..da270776 100644 --- a/src/modules/coreinit/coreinit_messagequeue.h +++ b/src/modules/coreinit/coreinit_messagequeue.h @@ -8,9 +8,36 @@ struct OSMessage { - p32 message; - uint32_t args[3]; + be_ptr message; + be_val args[3]; }; +CHECK_OFFSET(OSMessage, 0x00, message); +CHECK_OFFSET(OSMessage, 0x04, args); +CHECK_SIZE(OSMessage, 0x10); + +struct OSMessageQueue +{ + static const uint32_t Tag = 0x6D536751; + + be_val tag; + be_ptr name; + UNKNOWN(4); + OSThreadQueue sendQueue; + OSThreadQueue recvQueue; + be_ptr messages; + be_val size; + be_val first; + be_val used; +}; +CHECK_OFFSET(OSMessageQueue, 0x00, tag); +CHECK_OFFSET(OSMessageQueue, 0x04, name); +CHECK_OFFSET(OSMessageQueue, 0x0c, sendQueue); +CHECK_OFFSET(OSMessageQueue, 0x1c, recvQueue); +CHECK_OFFSET(OSMessageQueue, 0x2c, messages); +CHECK_OFFSET(OSMessageQueue, 0x30, size); +CHECK_OFFSET(OSMessageQueue, 0x34, first); +CHECK_OFFSET(OSMessageQueue, 0x38, used); +CHECK_SIZE(OSMessageQueue, 0x3c); #pragma pack(pop) @@ -23,39 +50,23 @@ enum Flags }; } -struct MessageQueue : public SystemObject -{ - static const uint32_t Tag = 0x6D536751; - - char *name; - uint32_t first; - uint32_t count; - uint32_t size; - OSMessage *messages; - MutexHandle mutex; - ConditionHandle waitSend; - ConditionHandle waitRead; -}; - -using MessageQueueHandle = SystemObjectHeader *; +void +OSInitMessageQueue(OSMessageQueue *queue, OSMessage *messages, int32_t size); void -OSInitMessageQueue(MessageQueueHandle handle, OSMessage *messages, int32_t size); - -void -OSInitMessageQueueEx(MessageQueueHandle handle, OSMessage *messages, int32_t size, char *name); +OSInitMessageQueueEx(OSMessageQueue *queue, OSMessage *messages, int32_t size, const char *name); BOOL -OSSendMessage(MessageQueueHandle handle, OSMessage *message, MessageFlags::Flags flags); +OSSendMessage(OSMessageQueue *queue, OSMessage *message, MessageFlags::Flags flags); BOOL -OSJamMessage(MessageQueueHandle handle, OSMessage *message, MessageFlags::Flags flags); +OSJamMessage(OSMessageQueue *queue, OSMessage *message, MessageFlags::Flags flags); BOOL -OSReceiveMessage(MessageQueueHandle handle, OSMessage *message, MessageFlags::Flags flags); +OSReceiveMessage(OSMessageQueue *queue, OSMessage *message, MessageFlags::Flags flags); BOOL -OSPeekMessage(MessageQueueHandle handle, OSMessage *message); +OSPeekMessage(OSMessageQueue *queue, OSMessage *message); -MessageQueueHandle +OSMessageQueue * OSGetSystemMessageQueue(); diff --git a/src/modules/coreinit/coreinit_mutex.cpp b/src/modules/coreinit/coreinit_mutex.cpp index 2415f179..2e2ee331 100644 --- a/src/modules/coreinit/coreinit_mutex.cpp +++ b/src/modules/coreinit/coreinit_mutex.cpp @@ -1,165 +1,159 @@ #include "coreinit.h" #include "coreinit_mutex.h" -#include "coreinit_memheap.h" -#include "system.h" -#include "processor.h" +#include "coreinit_scheduler.h" +#include "coreinit_thread.h" +#include "coreinit_queue.h" -MutexHandle -OSAllocMutex() +void +OSInitMutex(OSMutex *mutex) { - return OSAllocFromSystem(); -} - -ConditionHandle -OSAllocCondition() -{ - return OSAllocFromSystem(); + OSInitMutexEx(mutex, nullptr); } void -OSInitMutex(MutexHandle handle) +OSInitMutexEx(OSMutex *mutex, const char *name) { - OSInitMutexEx(handle, nullptr); -} - -void -OSInitMutexEx(MutexHandle handle, char *name) -{ - auto mutex = gSystem.addSystemObject(handle); + mutex->tag = OSMutex::Tag; mutex->name = name; - mutex->count = 0; mutex->owner = nullptr; + mutex->count = 0; + OSInitThreadQueueEx(&mutex->queue, mutex); + OSInitQueueLink(&mutex->link); } void -OSLockMutex(MutexHandle handle) +OSLockMutex(OSMutex *mutex) { - auto mutex = gSystem.getSystemObject(handle); - auto fiber = gProcessor.getCurrentFiber(); - - while (true) { - OSTestThreadCancel(); - std::unique_lock lock { mutex->mutex }; + OSLockScheduler(); + OSTestThreadCancelNoLock(); + OSLockMutexNoLock(mutex); + OSUnlockScheduler(); +} - if (!mutex->owner || mutex->owner == fiber) { - break; - } +void +OSLockMutexNoLock(OSMutex *mutex) +{ + assert(mutex && mutex->tag == OSMutex::Tag); + auto thread = OSGetCurrentThread(); - mutex->queue.push_back(fiber); - gProcessor.wait(lock); + if (mutex->owner && mutex->owner != thread) { + thread->mutex = mutex; + + // Wait for other owner to unlock + OSSleepThreadNoLock(&mutex->queue); + OSRescheduleNoLock(); + + thread->mutex = nullptr; } + if (mutex->owner != thread) { + // Add to mutex queue + OSAppendQueue(&thread->mutexQueue, mutex); + } + + mutex->owner = thread; mutex->count++; - mutex->owner = fiber; } BOOL -OSTryLockMutex(MutexHandle handle) +OSTryLockMutex(OSMutex *mutex) { - auto mutex = gSystem.getSystemObject(handle); - auto fiber = gProcessor.getCurrentFiber(); + auto thread = OSGetCurrentThread(); + OSLockScheduler(); + OSTestThreadCancelNoLock(); - std::unique_lock lock { mutex->mutex }; - - if (mutex->owner == fiber) { - mutex->count++; - return TRUE; - } else if (!mutex->owner) { - mutex->owner = fiber; - mutex->count = 1; - return TRUE; + if (mutex->owner && mutex->owner != thread) { + // Someone else owns this mutex + OSUnlockScheduler(); + return FALSE; } - return FALSE; + if (mutex->owner != thread) { + // Add to mutex queue + OSAppendQueue(&thread->mutexQueue, mutex); + } + + mutex->owner = thread; + mutex->count++; + OSUnlockScheduler(); + + return TRUE; } void -OSUnlockMutex(MutexHandle handle) +OSUnlockMutex(OSMutex *mutex) { - auto mutex = gSystem.getSystemObject(handle); - auto fiber = gProcessor.getCurrentFiber(); + OSLockScheduler(); + OSUnlockMutexNoLock(mutex); + OSTestThreadCancelNoLock(); + OSUnlockScheduler(); +} - std::unique_lock lock { mutex->mutex }; - assert(mutex->owner == fiber); +void +OSUnlockMutexNoLock(OSMutex *mutex) +{ + auto thread = OSGetCurrentThread(); + assert(mutex && mutex->tag == OSMutex::Tag); + assert(mutex->owner == thread); assert(mutex->count > 0); - mutex->count--; - if (!mutex->count) { - // Fully unlocked, wake up any waiting fibers + if (mutex->count == 0) { mutex->owner = nullptr; - for (auto fiber : mutex->queue) { - gProcessor.queue(fiber); - } + // Remove mutex from thread's mutex queue + OSEraseFromQueue(&thread->mutexQueue, mutex); - mutex->queue.clear(); + // Wakeup any threads trying to lock this mutex + OSWakeupThreadNoLock(&mutex->queue); + OSRescheduleNoLock(); } - - lock.unlock(); - OSTestThreadCancel(); } void -OSInitCond(ConditionHandle handle) +OSInitCond(OSCondition *condition) { - OSInitCondEx(handle, nullptr); + OSInitCondEx(condition, nullptr); } void -OSInitCondEx(ConditionHandle handle, char *name) +OSInitCondEx(OSCondition *condition, const char *name) { - auto condition = gSystem.addSystemObject(handle); + condition->tag = OSCondition::Tag; condition->name = name; - condition->value = false; + OSInitThreadQueueEx(&condition->queue, condition); } void -OSWaitCond(ConditionHandle conditionHandle, MutexHandle mutexHandle) +OSWaitCond(OSCondition *condition, OSMutex *mutex) { - auto condition = gSystem.getSystemObject(conditionHandle); - auto fiber = gProcessor.getCurrentFiber(); - - // Unlock mutex - auto mutex = gSystem.getSystemObject(mutexHandle); - auto count = mutex->count; + auto thread = OSGetCurrentThread(); + OSLockScheduler(); + assert(mutex && mutex->tag == OSMutex::Tag); + assert(condition && condition->tag == OSCondition::Tag); + assert(mutex->owner == thread); + + // Force an unlock + auto mutexCount = mutex->count; mutex->count = 1; - OSUnlockMutex(mutexHandle); + OSUnlockMutexNoLock(mutex); - // Try acquire condition - while (true) { - std::unique_lock lock { condition->mutex }; + // Sleep on the condition + OSSleepThreadNoLock(&condition->queue); + OSRescheduleNoLock(); - if (condition->value) { - break; - } + // Restore lock + OSLockMutexNoLock(mutex); + mutex->count = mutexCount; - condition->queue.push_back(fiber); - gProcessor.wait(lock); - } - - condition->value = false; - - // Lock mutex - OSLockMutex(mutexHandle); - mutex->count = count; + OSUnlockScheduler(); } void -OSSignalCond(ConditionHandle handle) +OSSignalCond(OSCondition *condition) { - auto condition = gSystem.getSystemObject(handle); - std::unique_lock lock { condition->mutex }; - - // Set condition - condition->value = true; - - // Wake all waiting fibers - for (auto fiber : condition->queue) { - gProcessor.queue(fiber); - } - - condition->queue.clear(); + assert(condition && condition->tag == OSCondition::Tag); + OSWakeupThread(&condition->queue); } void diff --git a/src/modules/coreinit/coreinit_mutex.h b/src/modules/coreinit/coreinit_mutex.h index 820040da..f5d21ce9 100644 --- a/src/modules/coreinit/coreinit_mutex.h +++ b/src/modules/coreinit/coreinit_mutex.h @@ -1,64 +1,85 @@ #pragma once -#include -#include -#include "systemobject.h" -#include "coreinit_thread.h" +#include "systemtypes.h" +#include "coreinit_threadqueue.h" -struct Fiber; +#pragma pack(push, 1) -struct Mutex : public SystemObject +struct OSMutex; + +struct OSMutexLink +{ + be_ptr next; + be_ptr prev; +}; +CHECK_OFFSET(OSMutexLink, 0x00, next); +CHECK_OFFSET(OSMutexLink, 0x04, prev); +CHECK_SIZE(OSMutexLink, 0x8); + +struct OSMutex { static const uint32_t Tag = 0x6D557458; - char *name; - uint32_t count; - std::mutex mutex; - Fiber *owner; - std::vector queue; + be_val tag; + be_ptr name; + UNKNOWN(4); + OSThreadQueue queue; + be_ptr owner; + be_val count; + OSMutexLink link; // For thread's mutexQueue }; +CHECK_OFFSET(OSMutex, 0x00, tag); +CHECK_OFFSET(OSMutex, 0x04, name); +CHECK_OFFSET(OSMutex, 0x0c, queue); +CHECK_OFFSET(OSMutex, 0x1c, owner); +CHECK_OFFSET(OSMutex, 0x20, count); +CHECK_OFFSET(OSMutex, 0x24, link); +CHECK_SIZE(OSMutex, 0x2c); -struct Condition : public SystemObject +struct OSCondition { static const uint32_t Tag = 0x634E6456; - char *name; - bool value; - std::mutex mutex; - std::vector queue; + be_val tag; + be_ptr name; + UNKNOWN(4); + OSThreadQueue queue; }; +CHECK_OFFSET(OSCondition, 0x00, tag); +CHECK_OFFSET(OSCondition, 0x04, name); +CHECK_OFFSET(OSCondition, 0x0c, queue); +CHECK_SIZE(OSCondition, 0x1c); -using MutexHandle = SystemObjectHeader *; -using ConditionHandle = SystemObjectHeader *; - -MutexHandle -OSAllocMutex(); +#pragma pack(pop) void -OSInitMutex(MutexHandle handle); +OSInitMutex(OSMutex *mutex); void -OSInitMutexEx(MutexHandle handle, char *name); +OSInitMutexEx(OSMutex *mutex, const char *name); void -OSLockMutex(MutexHandle handle); +OSLockMutex(OSMutex *mutex); void -OSUnlockMutex(MutexHandle handle); +OSLockMutexNoLock(OSMutex *mutex); + +void +OSUnlockMutex(OSMutex *mutex); + +void +OSUnlockMutexNoLock(OSMutex *mutex); BOOL -OSTryLockMutex(MutexHandle handle); - -ConditionHandle -OSAllocCondition(); +OSTryLockMutex(OSMutex *mutex); void -OSInitCond(ConditionHandle handle); +OSInitCond(OSCondition *condition); void -OSInitCondEx(ConditionHandle handle, char *name); +OSInitCondEx(OSCondition *condition, const char *name); void -OSWaitCond(ConditionHandle conditionHandle, MutexHandle mutexHandle); +OSWaitCond(OSCondition *condition, OSMutex *mutex); void -OSSignalCond(ConditionHandle handle); +OSSignalCond(OSCondition *condition); diff --git a/src/modules/coreinit/coreinit_queue.h b/src/modules/coreinit/coreinit_queue.h new file mode 100755 index 00000000..cd10d4da --- /dev/null +++ b/src/modules/coreinit/coreinit_queue.h @@ -0,0 +1,127 @@ +#pragma once +#include "systemtypes.h" + +template +static void inline +OSInitQueue(QueueType *queue) +{ + queue->head = nullptr; + queue->tail = nullptr; +} + +template +static void inline +OSInitQueueEx(QueueType *queue, void *parent) +{ + OSInitQueue(queue); + queue->parent = parent; +} + +template +static void inline +OSInitQueueLink(LinkType *link) +{ + link->prev = nullptr; + link->next = nullptr; +} + +// Returns true if queue is empty +template +static bool inline +OSIsEmptyQueue(QueueType *queue) +{ + return queue->head == nullptr; +} + +// Clear queue +template +static void inline +OSClearQueue(QueueType *queue) +{ + for (auto item = queue->head; item; ) { + auto next = item->link.next; + item->queue = nullptr; + item->link.next = nullptr; + item->link.prev = nullptr; + item = next; + } + + queue->head = nullptr; + queue->tail = nullptr; +} + +// Append item to back of queue +template +static void inline +OSAppendQueue(QueueType *queue, ItemType *item) +{ + if (!queue->tail) { + queue->head = item; + queue->tail = item; + item->link.next = nullptr; + item->link.prev = nullptr; + } + + item->link.prev = queue->tail; + item->link.next = nullptr; + queue->tail->link.next = item; + queue->tail = item; +} + +// Erase item from the queue +template +static void inline +OSEraseFromQueue(QueueType *queue, ItemType *item) +{ + if (queue->head == item) { + // Erase from head + queue->head = item->link.next; + + if (queue->head) { + queue->head->link.prev = nullptr; + } else { + queue->tail = nullptr; + } + + return; + } + + if (queue->tail == item) { + // Erase from tail + queue->tail = item->link.prev; + + if (queue->tail) { + queue->tail->link.next = nullptr; + } + + return; + } + + // Erase from middle + auto prev = item->link.prev; + auto next = item->link.next; + prev->link.next = next; + next->link.prev = prev; +} + +// Remove and return the item at front of the queue +template +static auto inline +OSPopFrontFromQueue(QueueType *queue) +{ + auto result = queue->head; + + if (result) { + queue->head = result->link.next; + + if (queue->head) { + queue->head->link.prev = nullptr; + } + } + + if (result == queue->tail) { + queue->tail = nullptr; + } + + return result; +} diff --git a/src/modules/coreinit/coreinit_scheduler.cpp b/src/modules/coreinit/coreinit_scheduler.cpp index 25aff3a0..1a2d55af 100755 --- a/src/modules/coreinit/coreinit_scheduler.cpp +++ b/src/modules/coreinit/coreinit_scheduler.cpp @@ -1,5 +1,7 @@ #include "coreinit.h" #include "coreinit_scheduler.h" +#include "coreinit_thread.h" +#include "processor.h" static std::atomic_bool gSchedulerLock = false; @@ -19,3 +21,94 @@ OSUnlockScheduler() { gSchedulerLock.store(false, std::memory_order_release); } + +void +OSRescheduleNoLock() +{ + gProcessor.reschedule(true); +} + +int32_t +OSResumeThreadNoLock(OSThread *thread, int32_t counter) +{ + auto old = thread->suspendCounter; + thread->suspendCounter -= counter; + + if (thread->suspendCounter < 0) { + thread->suspendCounter = 0; + return old; + } + + if (thread->suspendCounter == 0) { + if (thread->state == OSThreadState::Ready) { + gProcessor.queue(thread->fiber); + } + } + + return old; +} + +void +OSSleepThreadNoLock(OSThreadQueue *queue) +{ + auto thread = OSGetCurrentThread(); + thread->queue = queue; + thread->state = OSThreadState::Waiting; + + if (queue) { + OSInsertThreadQueue(queue, thread); + } +} + +void +OSSuspendThreadNoLock(OSThread *thread) +{ + thread->requestFlag = OSThreadRequest::None; + thread->suspendCounter += thread->needSuspend; + thread->needSuspend = 0; + thread->state = OSThreadState::Ready; + OSWakeupThreadNoLock(&thread->suspendQueue); +} + +void +OSTestThreadCancelNoLock() +{ + auto thread = OSGetCurrentThread(); + + if (thread->cancelState) { + if (thread->requestFlag == OSThreadRequest::Suspend) { + OSSuspendThreadNoLock(thread); + OSRescheduleNoLock(); + } else if (thread->requestFlag == OSThreadRequest::Cancel) { + OSUnlockScheduler(); + OSExitThread(-1); + } + } +} + +void +OSWakeupOneThreadNoLock(OSThread *thread) +{ + gProcessor.queue(thread->fiber); +} + +void +OSWakeupThreadNoLock(OSThreadQueue *queue) +{ + for (auto thread = queue->head; thread; thread = thread->link.next) { + gProcessor.queue(thread->fiber); + } + + OSClearThreadQueue(queue); +} + +void +OSWakeupThreadWaitForSuspensionNoLock(OSThreadQueue *queue, int32_t suspendResult) +{ + for (auto thread = queue->head; thread; thread = thread->link.next) { + thread->suspendResult = suspendResult; + gProcessor.queue(thread->fiber); + } + + OSClearThreadQueue(queue); +} diff --git a/src/modules/coreinit/coreinit_scheduler.h b/src/modules/coreinit/coreinit_scheduler.h index bca6d3bb..fb985401 100755 --- a/src/modules/coreinit/coreinit_scheduler.h +++ b/src/modules/coreinit/coreinit_scheduler.h @@ -1,8 +1,35 @@ #pragma once -#include "coreinit.h" +#include "systemtypes.h" + +struct OSThread; +struct OSThreadQueue; void OSLockScheduler(); void OSUnlockScheduler(); + +void +OSRescheduleNoLock(); + +int32_t +OSResumeThreadNoLock(OSThread *thread, int32_t counter); + +void +OSSleepThreadNoLock(OSThreadQueue *queue); + +void +OSSuspendThreadNoLock(OSThread *thread); + +void +OSTestThreadCancelNoLock(); + +void +OSWakeupOneThreadNoLock(OSThread *thread); + +void +OSWakeupThreadNoLock(OSThreadQueue *queue); + +void +OSWakeupThreadWaitForSuspensionNoLock(OSThreadQueue *queue, int32_t suspendResult); diff --git a/src/modules/coreinit/coreinit_semaphore.cpp b/src/modules/coreinit/coreinit_semaphore.cpp index cd0f3af2..ceb76bbf 100644 --- a/src/modules/coreinit/coreinit_semaphore.cpp +++ b/src/modules/coreinit/coreinit_semaphore.cpp @@ -1,80 +1,90 @@ #include "coreinit.h" #include "coreinit_semaphore.h" -#include "processor.h" -#include "system.h" +#include "coreinit_scheduler.h" void -OSInitSemaphore(SemaphoreHandle handle, int32_t count) +OSInitSemaphore(OSSemaphore *semaphore, int32_t count) { - OSInitSemaphoreEx(handle, count, nullptr); + OSInitSemaphoreEx(semaphore, count, nullptr); } void -OSInitSemaphoreEx(SemaphoreHandle handle, int32_t count, char *name) +OSInitSemaphoreEx(OSSemaphore *semaphore, int32_t count, char *name) { - auto semaphore = gSystem.addSystemObject(handle); + semaphore->tag = OSSemaphore::Tag; semaphore->name = name; semaphore->count = count; + OSInitThreadQueueEx(&semaphore->queue, semaphore); } int32_t -OSWaitSemaphore(SemaphoreHandle handle) +OSWaitSemaphore(OSSemaphore *semaphore) { - auto semaphore = gSystem.getSystemObject(handle); - auto fiber = gProcessor.getCurrentFiber(); + int32_t previous; + OSLockScheduler(); + assert(semaphore && semaphore->tag == OSSemaphore::Tag); - while (true) { - std::unique_lock lock { semaphore->mutex }; - - if (semaphore->count > 0) { - break; - } - - semaphore->queue.push_back(fiber); - gProcessor.wait(lock); + while (semaphore->count <= 0) { + // Wait until we can decrease semaphore + OSSleepThreadNoLock(&semaphore->queue); + OSRescheduleNoLock(); } - return semaphore->count--; + previous = semaphore->count--; + OSUnlockScheduler(); + return previous; } int32_t -OSTryWaitSemaphore(SemaphoreHandle handle) +OSTryWaitSemaphore(OSSemaphore *semaphore) { - auto semaphore = gSystem.getSystemObject(handle); - auto fiber = gProcessor.getCurrentFiber(); - std::unique_lock lock { semaphore->mutex }; + int32_t previous; + OSLockScheduler(); + assert(semaphore && semaphore->tag == OSSemaphore::Tag); + + // Try to decrease semaphore + previous = semaphore->count; - if (semaphore->count <= 0) { - return semaphore->count; + if (semaphore->count > 0) { + semaphore->count--; } - return semaphore->count--; + OSUnlockScheduler(); + return previous; } int32_t -OSSignalSemaphore(SemaphoreHandle handle) +OSSignalSemaphore(OSSemaphore *semaphore) { - auto semaphore = gSystem.getSystemObject(handle); - auto fiber = gProcessor.getCurrentFiber(); - std::unique_lock lock { semaphore->mutex }; - auto count = semaphore->count++; + int32_t previous; + OSLockScheduler(); + assert(semaphore && semaphore->tag == OSSemaphore::Tag); - // Wakeup fibers - for (auto fiber : semaphore->queue) { - gProcessor.queue(fiber); - } + // Increase semaphore + previous = semaphore->count++; - semaphore->queue.clear(); + // Wakeup any waiting threads + OSWakeupThreadNoLock(&semaphore->queue); + OSRescheduleNoLock(); + + OSUnlockScheduler(); + return previous; +} + +int32_t +OSGetSemaphoreCount(OSSemaphore *semaphore) +{ + int32_t count; + OSLockScheduler(); + assert(semaphore && semaphore->tag == OSSemaphore::Tag); + + // Return count + count = semaphore->count; + + OSUnlockScheduler(); return count; } -int32_t -OSGetSemaphoreCount(SemaphoreHandle handle) -{ - auto semaphore = gSystem.getSystemObject(handle); - return semaphore->count; -} - void CoreInit::registerSemaphoreFunctions() { diff --git a/src/modules/coreinit/coreinit_semaphore.h b/src/modules/coreinit/coreinit_semaphore.h index 23c0814f..bd5e0c8e 100644 --- a/src/modules/coreinit/coreinit_semaphore.h +++ b/src/modules/coreinit/coreinit_semaphore.h @@ -1,36 +1,36 @@ #pragma once -#include -#include "systemobject.h" #include "systemtypes.h" +#include "coreinit_threadqueue.h" -struct Fiber; +#pragma pack(push, 1) -struct Semaphore : public SystemObject +struct OSSemaphore { static const uint32_t Tag = 0x73506852; - char *name; - int32_t count; - std::mutex mutex; - std::vector queue; + be_val tag; + be_ptr name; + UNKNOWN(4); + be_val count; + OSThreadQueue queue; }; -using SemaphoreHandle = SystemObjectHeader *; +#pragma pack(pop) void -OSInitSemaphore(SemaphoreHandle handle, int32_t count); +OSInitSemaphore(OSSemaphore *semaphore, int32_t count); void -OSInitSemaphoreEx(SemaphoreHandle handle, int32_t count, char *name); +OSInitSemaphoreEx(OSSemaphore *semaphore, int32_t count, char *name); int32_t -OSWaitSemaphore(SemaphoreHandle handle); +OSWaitSemaphore(OSSemaphore *semaphore); int32_t -OSTryWaitSemaphore(SemaphoreHandle handle); +OSTryWaitSemaphore(OSSemaphore *semaphore); int32_t -OSSignalSemaphore(SemaphoreHandle handle); +OSSignalSemaphore(OSSemaphore *semaphore); int32_t -OSGetSemaphoreCount(SemaphoreHandle handle); +OSGetSemaphoreCount(OSSemaphore *semaphore); diff --git a/src/modules/coreinit/coreinit_thread.cpp b/src/modules/coreinit/coreinit_thread.cpp index e708d550..eebc66ff 100644 --- a/src/modules/coreinit/coreinit_thread.cpp +++ b/src/modules/coreinit/coreinit_thread.cpp @@ -14,88 +14,7 @@ gDefaultThreads[3]; static uint32_t gThreadId = 1; -static void -__OSSleepThreadNoLock(OSThreadQueue *queue) -{ - auto thread = OSGetCurrentThread(); - thread->queue = queue; - thread->state = OSThreadState::Waiting; - - if (queue) { - OSInsertThreadQueue(queue, thread); - } -} - -static void -__OSWakeupThreadNoLock(OSThreadQueue *queue) -{ - for (auto thread = queue->head; thread; thread = thread->link.next) { - gProcessor.queue(thread->fiber); - } -} - -static void -__OSWakeupThreadWaitForSuspensionNoLock(OSThreadQueue *queue, int32_t suspendResult) -{ - for (auto thread = queue->head; thread; thread = thread->link.next) { - thread->suspendResult = suspendResult; - gProcessor.queue(thread->fiber); - } -} - -static int32_t -__OSResumeThreadNoLock(OSThread *thread, int32_t counter) -{ - auto old = thread->suspendCounter; - thread->suspendCounter -= counter; - - if (thread->suspendCounter < 0) { - thread->suspendCounter = 0; - return old; - } - - if (thread->suspendCounter == 0) { - if (thread->state == OSThreadState::Ready) { - gProcessor.queue(thread->fiber); - } - } - - return old; -} - -static void -__OSSuspendThreadNoLock(OSThread *thread) -{ - thread->requestFlag = OSThreadRequest::None; - thread->suspendCounter += thread->needSuspend; - thread->needSuspend = 0; - thread->state = OSThreadState::Ready; - __OSWakeupThreadNoLock(&thread->suspendQueue); -} - -static void -__OSRescheduleNoLock() -{ - gProcessor.reschedule(true); -} - -static void -__OSTestThreadCancelNoLock() -{ - auto thread = OSGetCurrentThread(); - - if (thread->cancelState) { - if (thread->requestFlag == OSThreadRequest::Suspend) { - __OSSuspendThreadNoLock(thread); - __OSRescheduleNoLock(); - } else if (thread->requestFlag == OSThreadRequest::Cancel) { - OSUnlockScheduler(); - OSExitThread(-1); - } - } -} - -static void +void __OSClearThreadStack32(OSThread *thread, uint32_t value) { uint32_t clearStart = 0, clearEnd = 0; @@ -121,19 +40,19 @@ OSCancelThread(OSThread *thread) OSLockScheduler(); if (thread->requestFlag == OSThreadRequest::Suspend) { - __OSWakeupThreadWaitForSuspensionNoLock(&thread->suspendQueue, -1); + OSWakeupThreadWaitForSuspensionNoLock(&thread->suspendQueue, -1); reschedule = true; } if (thread->suspendCounter != 0) { if (thread->cancelState == 0) { - __OSResumeThreadNoLock(thread, thread->suspendCounter); + OSResumeThreadNoLock(thread, thread->suspendCounter); reschedule = true; } } if (reschedule) { - __OSRescheduleNoLock(); + OSRescheduleNoLock(); } thread->suspendCounter = 0; @@ -185,8 +104,8 @@ void OSContinueThread(OSThread *thread) { OSLockScheduler(); - __OSResumeThreadNoLock(thread, thread->suspendCounter); - __OSRescheduleNoLock(); + OSResumeThreadNoLock(thread, thread->suspendCounter); + OSRescheduleNoLock(); OSUnlockScheduler(); } @@ -249,8 +168,8 @@ OSExitThread(int value) thread->state = OSThreadState::Moribund; } - __OSWakeupThreadNoLock(&thread->joinQueue); - __OSWakeupThreadWaitForSuspensionNoLock(&thread->suspendQueue, -1); + OSWakeupThreadNoLock(&thread->joinQueue); + OSWakeupThreadWaitForSuspensionNoLock(&thread->suspendQueue, -1); OSUnlockScheduler(); gProcessor.exit(); } @@ -308,38 +227,6 @@ OSGetThreadSpecific(uint32_t id) return OSGetCurrentThread()->specific[id]; } -void -OSInitThreadQueue(OSThreadQueue *queue) -{ - OSInitThreadQueueEx(queue, nullptr); -} - -void -OSInitThreadQueueEx(OSThreadQueue *queue, void *parent) -{ - queue->head = nullptr; - queue->tail = nullptr; - queue->parent = parent; -} - -void -OSInsertThreadQueue(OSThreadQueue *queue, OSThread *thread) -{ - thread->queue = queue; - - if (!queue->head) { - thread->link.prev = nullptr; - thread->link.next = nullptr; - queue->head = thread; - queue->tail = thread; - } else { - queue->tail->link.next = thread; - thread->link.prev = queue->tail; - thread->link.next = nullptr; - queue->tail = thread; - } -} - BOOL OSIsThreadSuspended(OSThread *thread) { @@ -364,8 +251,8 @@ OSJoinThread(OSThread *thread, be_val *val) } if (thread->state != OSThreadState::Moribund) { - __OSSleepThreadNoLock(&thread->joinQueue); - __OSRescheduleNoLock(); + OSSleepThreadNoLock(&thread->joinQueue); + OSRescheduleNoLock(); } if (val) { @@ -387,10 +274,10 @@ int32_t OSResumeThread(OSThread *thread) { OSLockScheduler(); - auto old = __OSResumeThreadNoLock(thread, 1); + auto old = OSResumeThreadNoLock(thread, 1); if (thread->suspendCounter == 0) { - __OSRescheduleNoLock(); + OSRescheduleNoLock(); } OSUnlockScheduler(); @@ -401,13 +288,12 @@ BOOL OSRunThread(OSThread *thread, ThreadEntryPoint entry, uint32_t argc, p32 argv) { BOOL result = false; - OSLockScheduler(); if (OSIsThreadTerminated(thread)) { // Setup state auto state = &thread->fiber->state; - state->cia = thread->entryPoint; + state->cia = entry; state->nia = state->cia + 4; state->gpr[1] = thread->stackStart; state->gpr[3] = argc; @@ -419,8 +305,8 @@ OSRunThread(OSThread *thread, ThreadEntryPoint entry, uint32_t argc, p32 a thread->requestFlag = OSThreadRequest::None; thread->needSuspend = 0; - __OSResumeThreadNoLock(thread, 1); - __OSRescheduleNoLock(); + OSResumeThreadNoLock(thread, 1); + OSRescheduleNoLock(); } OSUnlockScheduler(); @@ -441,7 +327,7 @@ OSSetThreadAffinity(OSThread *thread, uint32_t affinity) OSLockScheduler(); thread->attr &= ~OSThreadAttributes::AffinityAny; thread->attr |= affinity; - __OSRescheduleNoLock(); + OSRescheduleNoLock(); OSUnlockScheduler(); return TRUE; } @@ -470,7 +356,7 @@ OSSetThreadPriority(OSThread* thread, uint32_t priority) OSLockScheduler(); thread->basePriority = priority; - __OSRescheduleNoLock(); + OSRescheduleNoLock(); OSUnlockScheduler(); return TRUE; } @@ -512,8 +398,8 @@ void OSSleepThread(OSThreadQueue *queue) { OSLockScheduler(); - __OSSleepThreadNoLock(queue); - __OSRescheduleNoLock(); + OSSleepThreadNoLock(queue); + OSRescheduleNoLock(); OSUnlockScheduler(); } @@ -523,8 +409,8 @@ OSSleepTicks(Time ticks) OSLockScheduler(); // Create alarm // Set alarm interval - __OSSleepThreadNoLock(nullptr); - __OSRescheduleNoLock(); + OSSleepThreadNoLock(nullptr); + OSRescheduleNoLock(); OSUnlockScheduler(); } @@ -554,8 +440,8 @@ OSSuspendThread(OSThread *thread) thread->needSuspend++; result = thread->suspendCounter; - __OSSuspendThreadNoLock(thread); - __OSRescheduleNoLock(); + OSSuspendThreadNoLock(thread); + OSRescheduleNoLock(); goto exit; } else { if (thread->suspendCounter != 0) { @@ -564,8 +450,8 @@ OSSuspendThread(OSThread *thread) } else { thread->needSuspend++; thread->requestFlag = OSThreadRequest::Suspend; - __OSSleepThreadNoLock(&thread->suspendQueue); - __OSRescheduleNoLock(); + OSSleepThreadNoLock(&thread->suspendQueue); + OSRescheduleNoLock(); result = thread->suspendResult; } } @@ -579,7 +465,7 @@ void OSTestThreadCancel() { OSLockScheduler(); - __OSTestThreadCancelNoLock(); + OSTestThreadCancelNoLock(); OSUnlockScheduler(); } @@ -587,7 +473,7 @@ void OSWakeupThread(OSThreadQueue *queue) { OSLockScheduler(); - __OSWakeupThreadNoLock(queue); + OSWakeupThreadNoLock(queue); OSUnlockScheduler(); } diff --git a/src/modules/coreinit/coreinit_thread.h b/src/modules/coreinit/coreinit_thread.h index b6c1c3ff..39e7bedb 100644 --- a/src/modules/coreinit/coreinit_thread.h +++ b/src/modules/coreinit/coreinit_thread.h @@ -1,38 +1,12 @@ #pragma once #include "systemtypes.h" #include "coreinit_time.h" -#include "util.h" +#include "coreinit_threadqueue.h" #pragma pack(push, 1) -struct OSThread; struct Fiber; -struct OSThreadLink -{ - be_ptr prev; - be_ptr next; -}; -CHECK_OFFSET(OSThreadLink, 0x00, prev); -CHECK_OFFSET(OSThreadLink, 0x04, next); -CHECK_SIZE(OSThreadLink, 0x8); - -struct OSThreadQueue -{ - be_ptr head; - be_ptr tail; - be_ptr parent; - UNKNOWN(4); -}; -CHECK_OFFSET(OSThreadQueue, 0x00, head); -CHECK_OFFSET(OSThreadQueue, 0x04, tail); -CHECK_OFFSET(OSThreadQueue, 0x08, parent); -CHECK_SIZE(OSThreadQueue, 0x10); - -// OSDumpContext, OSLoadFPUContext, OSSaveContext -// OSGetLastError -// 0200F060 crash dump handler -// OSCheckActiveThreads 0x201AAA0 struct OSContext { static const uint64_t Tag1 = 0x4F53436F6E747874ull; @@ -122,6 +96,31 @@ enum Flags : uint8_t }; } +struct OSMutex; + +struct OSMutexQueue +{ + be_ptr head; + be_ptr tail; + be_ptr parent; + UNKNOWN(4); +}; +CHECK_OFFSET(OSMutexQueue, 0x0, head); +CHECK_OFFSET(OSMutexQueue, 0x4, tail); +CHECK_OFFSET(OSMutexQueue, 0x8, parent); +CHECK_SIZE(OSMutexQueue, 0x10); + +struct OSFastMutex; + +struct OSFastMutexQueue +{ + be_ptr head; + be_ptr tail; +}; +CHECK_OFFSET(OSFastMutexQueue, 0x00, head); +CHECK_OFFSET(OSFastMutexQueue, 0x04, tail); +CHECK_SIZE(OSFastMutexQueue, 0x08); + struct OSThread { static const uint32_t Tag = 0x74487244; @@ -133,20 +132,21 @@ struct OSThread be_val id; be_val suspendCounter; be_val priority; - be_val basePriority; // "ba" in DumpActiveThreads and returned in OSGetThreadPriority - be_val exitValue; // Exit value of thread - Fiber *fiber; // Naughty + be_val basePriority; // "ba" in DumpActiveThreads and returned in OSGetThreadPriority + be_val exitValue; // Exit value of thread + Fiber *fiber; // Naughty, hopefully not overriding anything important UNKNOWN(0x35c - 0x340); - be_ptr queue; // Queue the thread is on - OSThreadLink link; // Thread queue link - OSThreadQueue joinQueue; // Queue of threads waiting to join this - UNKNOWN(0x38c - 0x378); - OSThreadLink activeLink; // Link on active thread queue - be_val stackStart; // Stack starting value (top, highest address) - be_val stackEnd; // Stack end value (bottom, lowest address) - be_val entryPoint; // Entry point from OSCreateThread + be_ptr queue; // Queue the thread is on + OSThreadLink link; // Thread queue link + OSThreadQueue joinQueue; // Queue of threads waiting to join this + be_ptr mutex; // Mutex we are waiting to lock + OSMutexQueue mutexQueue; // Mutexes owned by this thread + OSThreadLink activeLink; // Link on active thread queue + be_val stackStart; // Stack starting value (top, highest address) + be_val stackEnd; // Stack end value (bottom, lowest address) + be_val entryPoint; // Entry point from OSCreateThread UNKNOWN(0x57c - 0x3a0); - be_val specific[0x10]; // OSGetThreadSpecific + be_val specific[0x10]; UNKNOWN(0x5c0 - 0x5bc); be_ptr name; // Thread name UNKNOWN(0x4); @@ -171,6 +171,8 @@ CHECK_OFFSET(OSThread, 0x334, exitValue); CHECK_OFFSET(OSThread, 0x35c, queue); CHECK_OFFSET(OSThread, 0x360, link); CHECK_OFFSET(OSThread, 0x368, joinQueue); +CHECK_OFFSET(OSThread, 0x378, mutex); +CHECK_OFFSET(OSThread, 0x37c, mutexQueue); CHECK_OFFSET(OSThread, 0x38c, activeLink); CHECK_OFFSET(OSThread, 0x394, stackStart); CHECK_OFFSET(OSThread, 0x398, stackEnd); @@ -239,15 +241,6 @@ OSGetThreadPriority(OSThread *thread); uint32_t OSGetThreadSpecific(uint32_t id); -void -OSInitThreadQueue(OSThreadQueue *queue); - -void -OSInitThreadQueueEx(OSThreadQueue *queue, void *parent); - -void -OSInsertThreadQueue(OSThreadQueue *queue, OSThread *thread); - BOOL OSIsThreadSuspended(OSThread *thread); diff --git a/src/modules/coreinit/coreinit_threadqueue.cpp b/src/modules/coreinit/coreinit_threadqueue.cpp new file mode 100755 index 00000000..673962b2 --- /dev/null +++ b/src/modules/coreinit/coreinit_threadqueue.cpp @@ -0,0 +1,81 @@ +#include "coreinit.h" +#include "coreinit_thread.h" +#include "coreinit_threadqueue.h" +#include "coreinit_queue.h" + +void +OSInitThreadQueue(OSThreadQueue *queue) +{ + OSInitQueueEx(queue, nullptr); +} + +void +OSInitThreadQueueEx(OSThreadQueue *queue, void *parent) +{ + OSInitQueueEx(queue, parent); +} + +void +OSClearThreadQueue(OSThreadQueue *queue) +{ + OSClearQueue(queue); +} + +void +OSEraseFromThreadQueue(OSThreadQueue *queue, OSThread *thread) +{ + OSEraseFromQueue(queue, thread); +} + +void +OSInsertThreadQueue(OSThreadQueue *queue, OSThread *thread) +{ + thread->queue = queue; + + if (!queue->head) { + // Insert only item + thread->link.prev = nullptr; + thread->link.next = nullptr; + queue->head = thread; + queue->tail = thread; + } else { + OSThread *insertBefore = nullptr; + + // Find insert location based on priority + for (insertBefore = queue->head; insertBefore; insertBefore = insertBefore->link.next) { + if (insertBefore->basePriority > thread->priority) { + break; + } + } + + if (!insertBefore) { + // Insert at tail + queue->tail->link.next = thread; + thread->link.next = nullptr; + thread->link.prev = queue->tail; + queue->tail = thread; + } else { + // Insert in middle + thread->link.next = insertBefore; + thread->link.prev = insertBefore->link.prev; + + if (insertBefore->link.prev) { + insertBefore->link.prev->link.next = thread; + } + + insertBefore->link.prev = thread; + } + } +} + +BOOL +OSIsThreadQueueEmpty(OSThreadQueue *queue) +{ + return OSIsEmptyQueue(queue); +} + +OSThread * +OSPopFrontThreadQueue(OSThreadQueue *queue) +{ + return OSPopFrontFromQueue(queue); +} diff --git a/src/modules/coreinit/coreinit_threadqueue.h b/src/modules/coreinit/coreinit_threadqueue.h new file mode 100755 index 00000000..3b4eed79 --- /dev/null +++ b/src/modules/coreinit/coreinit_threadqueue.h @@ -0,0 +1,59 @@ +#pragma once +#include "systemtypes.h" + +#pragma pack(push, 1) + +struct OSThread; + +struct OSThreadLink +{ + be_ptr prev; + be_ptr next; +}; +CHECK_OFFSET(OSThreadLink, 0x00, prev); +CHECK_OFFSET(OSThreadLink, 0x04, next); +CHECK_SIZE(OSThreadLink, 0x8); + +struct OSThreadQueue +{ + be_ptr head; + be_ptr tail; + be_ptr parent; + UNKNOWN(4); +}; +CHECK_OFFSET(OSThreadQueue, 0x00, head); +CHECK_OFFSET(OSThreadQueue, 0x04, tail); +CHECK_OFFSET(OSThreadQueue, 0x08, parent); +CHECK_SIZE(OSThreadQueue, 0x10); + +struct OSThreadSimpleQueue +{ + be_ptr head; + be_ptr tail; +}; +CHECK_OFFSET(OSThreadSimpleQueue, 0x00, head); +CHECK_OFFSET(OSThreadSimpleQueue, 0x04, tail); +CHECK_SIZE(OSThreadSimpleQueue, 0x08); + +#pragma pack(pop) + +void +OSInitThreadQueue(OSThreadQueue *queue); + +void +OSInitThreadQueueEx(OSThreadQueue *queue, void *parent); + +void +OSClearThreadQueue(OSThreadQueue *queue); + +void +OSEraseFromThreadQueue(OSThreadQueue *queue, OSThread *thread); + +void +OSInsertThreadQueue(OSThreadQueue *queue, OSThread *thread); + +BOOL +OSIsThreadQueueEmpty(OSThreadQueue *queue); + +OSThread * +OSPopFrontThreadQueue(OSThreadQueue *queue); diff --git a/src/processor.cpp b/src/processor.cpp index 8caf8f46..6163dbac 100755 --- a/src/processor.cpp +++ b/src/processor.cpp @@ -79,6 +79,7 @@ Processor::coreEntryPoint(Core *core) // Switch to fiber core->currentFiber = fiber; + fiber->coreID = core->id; fiber->parentFiber = core->primaryFiber; fiber->thread->state = OSThreadState::Running; lock.unlock(); diff --git a/src/processor.h b/src/processor.h index 98f5d8cb..1ef73466 100755 --- a/src/processor.h +++ b/src/processor.h @@ -24,6 +24,7 @@ struct Fiber static void __stdcall fiberEntryPoint(void *param); + uint32_t coreID; void *handle = nullptr; void *parentFiber = nullptr; OSThread *thread = nullptr; diff --git a/src/system.cpp b/src/system.cpp index 7fa871e8..2aaaa0da 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -77,7 +77,7 @@ System::loadThunks() // Allocate space for all thunks! mSystemThunks = OSAllocFromSystem(static_cast(mSystemCalls.size() * 8), 4); - addr = static_cast(mSystemThunks); + addr = gMemory.untranslate(mSystemThunks); for (auto &func : mSystemCalls) { // Set the function virtual address @@ -98,38 +98,6 @@ System::loadThunks() } } -bool -System::freeSystemObject(p32 header) -{ - std::lock_guard lock(mSystemObjectMutex); - auto itr = mSystemObjects.find(static_cast(header)); - - if (itr == mSystemObjects.end()) { - return false; - } - - // Destroy the system object - delete itr->second; - mSystemObjects.erase(itr); - return true; -} - -// Finds and frees all system objects within a range of memory -void -System::freeSystemObjects(uint32_t address, uint32_t size) -{ - std::lock_guard lock(mSystemObjectMutex); - auto start = address; - auto end = address + size; - auto itr = mSystemObjects.begin(); - auto pred = [start, end](auto &item) { return item.first >= start && item.first < end; }; - - while ((itr = std::find_if(itr, mSystemObjects.end(), pred)) != mSystemObjects.end()) { - delete itr->second; - mSystemObjects.erase(itr++); - } -} - void System::setFileSystem(FileSystem *fs) { diff --git a/src/system.h b/src/system.h index 12bc2771..34229355 100644 --- a/src/system.h +++ b/src/system.h @@ -31,53 +31,15 @@ public: FileSystem *getFileSystem(); void setFileSystem(FileSystem *fs); - // Create a system object for the virtual address - template - inline Type * - addSystemObject(p32 header) - { - std::lock_guard lock(mSystemObjectMutex); - auto object = new Type(); - - // Set object header values - header->tag = Type::Tag; - header->object = object; - - // Add to object map - auto sysobj = reinterpret_cast(object); - sysobj->objectTag = Type::Tag; - sysobj->objectVirtualAddress = static_cast(header); - mSystemObjects.insert(std::make_pair(sysobj->objectVirtualAddress, sysobj)); - - return object; - } - - // Get the system object associated with virtual address - template - inline Type * - getSystemObject(p32 header) - { - assert(header->tag == Type::Tag); - return reinterpret_cast(header->object); - } - - // Free the system object associated with virtual address - bool freeSystemObject(p32 header); - - // Finds and free all system objects within a range of memory addresses - void freeSystemObjects(uint32_t address, uint32_t size); - protected: void loadThunks(); private: UserModule *mUserModule; std::map mSystemModules; - p32 mSystemThunks; - std::vector mSystemCalls; - std::mutex mSystemObjectMutex; - std::map mSystemObjects; + void *mSystemThunks; + std::vector mSystemCalls; FileSystem *mFileSystem; }; diff --git a/src/systemobject.h b/src/systemobject.h deleted file mode 100644 index 0c6cdfa8..00000000 --- a/src/systemobject.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once -#include - -struct SystemObjectHeader -{ - uint32_t tag; - void *object; -}; - -struct SystemObject -{ - virtual ~SystemObject() - { - } - - uint32_t objectTag; - uint32_t objectVirtualAddress; -}; diff --git a/src/systemtypes.h b/src/systemtypes.h index bb0f0d81..f8364064 100644 --- a/src/systemtypes.h +++ b/src/systemtypes.h @@ -3,7 +3,6 @@ #include "be_val.h" #include "memory.h" #include "p32.h" -#include "systemobject.h" #include "wfunc_ptr.h" #ifndef BOOL