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