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