#include #include #include "JSystem/JUtility/JUTDbg.h" #include "JSystem/JKernel/JKRHeap.h" #include "JSystem/JKernel/JKRThread.h" #include "JSystem/JKernel/JKRDisposer.h" #include "JSystem/JSupport/JSUList.h" #include "types.h" // this file has some unused strings that need to be generated by ppcdis or fake functions JSUList JKRThread::sThreadList(false); JSUList JKRTask::sTaskList; OSMessageQueue JKRTask::sEndMesgQueue; JKRIdleThread *JKRIdleThread::sThread; // Unused JKRThreadSwitch *JKRThreadSwitch::sManager; u32 JKRThreadSwitch::sTotalCount; // Unused u64 JKRThreadSwitch::sTotalStart; // Unused JKRThreadSwitch_PreCallback JKRThreadSwitch::mUserPreCallback; // Unused JKRThreadSwitch_PostCallback JKRThreadSwitch::mUserPostCallback; // Unused OSMessage *JKRTask::sEndMesgBuffer; // Unused u32 JKRTask::sEndMesgBufSize; // Unused JKRThread::JKRThread(u32 stack_size, int message_count, int param_3) : mThreadListLink(this) { JKRHeap *heap = JKRHeap::findFromRoot(this); if (heap == nullptr) { heap = JKRHeap::getSystemHeap(); } setCommon_heapSpecified(heap, stack_size, param_3); setCommon_mesgQueue(mHeap, message_count); } JKRThread::JKRThread(JKRHeap *heap, u32 stack_size, int message_count, int param_4) : mThreadListLink(this) { if (heap == nullptr) { heap = JKRHeap::getCurrentHeap(); } setCommon_heapSpecified(heap, stack_size, param_4); setCommon_mesgQueue(mHeap, message_count); } JKRThread::JKRThread(OSThread *thread, int message_count) : mThreadListLink(this) { mHeap = nullptr; mThreadRecord = thread; mStackSize = (u32)thread->stackEnd - (u32)thread->stackBase; mStackMemory = thread->stackBase; setCommon_mesgQueue(JKRHeap::getSystemHeap(), message_count); } JKRThread::~JKRThread() { sThreadList.remove(&mThreadListLink); if (mHeap != nullptr) { if (!OSIsThreadTerminated(mThreadRecord)) { OSDetachThread(mThreadRecord); OSCancelThread(mThreadRecord); } JKRFreeToHeap(mHeap, mStackMemory); JKRFreeToHeap(mHeap, mThreadRecord); } JKRFree(mMesgBuffer); } void JKRThread::setCommon_mesgQueue(JKRHeap *heap, int msgCount) { #line 128 mMessageCount = msgCount; mMesgBuffer = (OSMessage *)JKRHeap::alloc(mMessageCount << 2, 0, heap); JUT_ASSERT(mMesgBuffer); OSInitMessageQueue(&mMessageQueue, mMesgBuffer, mMessageCount); JKRThread::sThreadList.append(&mThreadListLink); mCurrentHeap = nullptr; mCurrentHeapError = nullptr; } BOOL JKRThread::setCommon_heapSpecified(JKRHeap *heap, u32 stackSize, int threadPriority) { #line 161 mHeap = heap; mStackSize = stackSize & ~0x1F; mStackMemory = JKRHeap::alloc(mStackSize, 0x20, mHeap); JUT_ASSERT(mStackMemory); #line 167 mThreadRecord = (OSThread *)JKRHeap::alloc(sizeof(OSThread), 0x20, mHeap); JUT_ASSERT(mThreadRecord); return OSCreateThread(mThreadRecord, &JKRThread::start, this, (void *)((u32)mStackMemory + mStackSize), mStackSize, threadPriority, 1); } void *JKRThread::start(void *thread) { return static_cast(thread)->run(); } JKRThread *JKRThread::searchThread(OSThread *thread) { JSUList &threadList = getList(); JSUListIterator iterator; for (iterator = threadList.getFirst(); iterator != threadList.getEnd(); ++iterator) { if (iterator->getThreadRecord() == thread) { return iterator.getObject(); } } return nullptr; } #ifdef DEBUG CW_FORCE_STRINGS(JKRThread_1, "JKRThread:%x OSThread:%x Load:ID:%d (%s)\n", "sThread == 0") #endif JKRThreadSwitch::JKRThreadSwitch(JKRHeap *heap) { mHeap = heap; OSSetSwitchThreadCallback(JKRThreadSwitch::callback); _0C = 0; _10 = 1; _18 = 0; sTotalCount = 0; sTotalStart = 0; mConsole = nullptr; mThreadName = nullptr; mSetNextHeap = true; } JKRThreadSwitch *JKRThreadSwitch::createManager(JKRHeap *heap) { #line 343 JUT_ASSERT(sManager == 0); if (!heap) { heap = JKRGetCurrentHeap(); } sManager = new (heap, 0) JKRThreadSwitch(heap); return sManager; } JKRThread *JKRThreadSwitch::enter(JKRThread *thread, int id) { if (thread == nullptr) { return nullptr; } else { JKRThread *nextThread = JKRThread::searchThread(thread->getThreadRecord()); if (nextThread != nullptr) thread = nextThread; JKRThread::TLoad *loadInfo = thread->getLoadInfo(); loadInfo->clear(); loadInfo->setValid(true); loadInfo->setId(id); } return thread; } void JKRThreadSwitch::callback(OSThread *current, OSThread *next) { if (mUserPreCallback) { (*mUserPreCallback)(current, next); } sTotalCount = sTotalCount + 1; JKRHeap *next_heap = nullptr; JSUList &threadList = JKRThread::getList(); JSUListIterator iterator; for (iterator = threadList.getFirst(); iterator != threadList.getEnd(); ++iterator) { JKRThread *thread = iterator.getObject(); if (thread->getThreadRecord() == current) { thread->setCurrentHeap(JKRHeap::getCurrentHeap()); JKRThread::TLoad *loadInfo = thread->getLoadInfo(); if (loadInfo->isValid()) { loadInfo->addCurrentCost(); } } if (thread->getThreadRecord() == next) { JKRThread::TLoad *loadInfo = thread->getLoadInfo(); if (loadInfo->isValid()) { loadInfo->setCurrentTime(); loadInfo->incCount(); } if (sManager->mSetNextHeap) { next_heap = thread->getCurrentHeap(); if (!next_heap) { next_heap = JKRHeap::getCurrentHeap(); } else if (JKRHeap::getRootHeap()->isSubHeap(next_heap)) { continue; } else { switch (thread->getCurrentHeapError()) { case 0: #line 508 JUT_PANIC("JKRThreadSwitch: currentHeap destroyed."); break; case 1: JUTWarningConsole("JKRThreadSwitch: currentHeap destroyed.\n"); next_heap = JKRHeap::getCurrentHeap(); break; case 2: next_heap = JKRHeap::getCurrentHeap(); break; case 3: next_heap = JKRHeap::getSystemHeap(); break; } } } } } if (next_heap) { next_heap->becomeCurrentHeap(); } if (mUserPostCallback) { (*mUserPostCallback)(current, next); } } void JKRThreadSwitch::draw(JKRThreadName_ *thread_name_list, JUTConsole *console) { const char *print_0 = " total: switch:%3d time:%d(%df)\n"; const char *print_1 = " -------------------------------------\n"; if (!console) { /*#if DEBUG OSReport(print_0, getTotalCount(), (int)_18, _10); OSReport(print_1); #endif*/ } else { console->clear(); console->print_f(print_0, getTotalCount(), (int)_18, _10); console->print(print_1); } for (JSUListIterator iterator = JKRThread::getList().getFirst(); iterator != JKRThread::getList().getEnd(); ++iterator) { JKRThread *thread = iterator.getObject(); JKRThread::TLoad *loadInfo = thread->getLoadInfo(); if (loadInfo->isValid()) { char *thread_print_name = nullptr; if (thread_name_list) { JKRThreadName_ *thread_name = thread_name_list; for (; thread_name->name; thread_name++) { if (thread_name->id == loadInfo->getId()) { thread_print_name = thread_name->name; break; } } } if (!thread_print_name) { char buffer[16]; sprintf(buffer, "%d", loadInfo->getId()); thread_print_name = buffer; } u32 switch_count = loadInfo->getCount(); float cost_per_0x18 = loadInfo->getCost() / (float)_18; u32 cost_int = (u32)(cost_per_0x18 * 100.0f); u32 cost_float = (u32)(cost_per_0x18 * 1000.0f) % 10; if (!console) { /*#if DEBUG OSReport(" [%10s] switch:%5d cost:%2d.%d%%\n", thread_print_name, switch_count, cost_int, cost_float); #endif*/ } else { console->print_f(" [%10s] switch:%5d cost:%2d.%d%%\n", thread_print_name, switch_count, cost_int, cost_float); } } } } #ifdef DEBUG CW_FORCE_STRINGS(JKRThread_2, "JUTConsole.h", "console != 0", "bufSize > 0", "sEndMesgBuffer") #endif JKRTask::JKRTask(int msgCount, int threadPriority, u32 stackSize) : JKRThread(stackSize, msgCount, threadPriority), mTaskLink(this), mTaskMsgQueue(nullptr) { // UNUSED FUNCTION OSResumeThread(mThreadRecord); } JKRTask::~JKRTask() { sTaskList.remove(&mTaskLink); } JKRTask *JKRTask::create(int reqCount, int threadPriority, u32 stackSize, JKRHeap *heap) { if (heap == nullptr) { heap = JKRHeap::sCurrentHeap; } JKRTask *task = new (heap, 0) JKRTask(reqCount, threadPriority, stackSize); if (task == nullptr) { return nullptr; } task->mRequest = new (heap, 0) Request[reqCount]; task->mRequestCnt = reqCount; if (task->mRequest == nullptr) { delete task; return nullptr; } for (int i = 0; i < reqCount; i++) { task->mRequest[i].mCb = nullptr; } sTaskList.append(&task->mTaskLink); return task; } void *JKRTask::run() { Request *req; OSInitFastCast(); while (true) { req = (Request *)waitMessageBlock(); if (req->mCb != nullptr) { req->mCb(req->mArg); if (mTaskMsgQueue != nullptr) { OSSendMessage(mTaskMsgQueue, req->mMsg, OS_MESSAGE_NOBLOCK); } } req->mCb = nullptr; } } JKRTask::Request *JKRTask::searchBlank() { // UNUSED FUNCTION for (int i = 0; i < (int)mRequestCnt; i++) { if (mRequest[i].mCb == nullptr) { return &mRequest[i]; } } return nullptr; } bool JKRTask::request(RequestCallback callback, void *arg, void *msg) { Request *req = searchBlank(); if (req == nullptr) { return false; } req->mCb = callback; req->mArg = arg; req->mMsg = msg; bool sendResult = OSSendMessage(&mMessageQueue, req, OS_MESSAGE_NOBLOCK); if (!sendResult) { req->mCb = nullptr; } return sendResult; }