diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 9ab2b61c..8f5981b7 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -39801,7 +39801,7 @@ 0x000000710065a290,sub_710065A290,8, 0x000000710065a298,sub_710065A298,48, 0x000000710065a2c8,sub_710065A2C8,92, -0x000000710065a324,sub_710065A324,8, +0x000000710065a324,sub_710065A324,8,_ZNK4sead10IDelegate2IPNS_6ThreadElE9isNoDummyEv 0x000000710065a32c,sub_710065A32C,8,_ZNK4sead10IDelegate2IPNS_6ThreadElE5cloneEPNS_4HeapE 0x000000710065a334,sub_710065A334,48, 0x000000710065a364,sub_710065A364,92, @@ -75989,19 +75989,19 @@ 0x0000007100dcde30,sub_7100DCDE30,92, 0x0000007100dcde8c,sub_7100DCDE8C,52, 0x0000007100dcdec0,sub_7100DCDEC0,92, -0x0000007100dcdf1c,sub_7100DCDF1C,56, -0x0000007100dcdf54,sub_7100DCDF54,92, -0x0000007100dcdfb0,WorkerSupportThreadMgr::createInstance,276, -0x0000007100dce0c4,WorkerSupportThreadMgr::init,656, -0x0000007100dce354,WorkerSupportThreadMgr::startSleeperThread,588, -0x0000007100dce5a0,SleeperThreadFunc,44, -0x0000007100dce5cc,WorkerSupportThreadMgr::submitReq,240, -0x0000007100dce6bc,WorkerSupportThreadMgr::__auto0,68, -0x0000007100dce700,WorkerSupportThreadMgr::__auto3,48, -0x0000007100dce730,WorkerSupportThreadMgr::__auto1,44, -0x0000007100dce75c,WorkerSupportThreadMgr::__auto2,136, -0x0000007100dce7e8,sub_7100DCE7E8,48, -0x0000007100dce818,sub_7100DCE818,92, +0x0000007100dcdf1c,sub_7100DCDF1C,56,_ZN4ksys3frm22WorkerSupportThreadMgr18SingletonDisposer_D1Ev +0x0000007100dcdf54,sub_7100DCDF54,92,_ZN4ksys3frm22WorkerSupportThreadMgr18SingletonDisposer_D0Ev +0x0000007100dcdfb0,WorkerSupportThreadMgr::createInstance,276,_ZN4ksys3frm22WorkerSupportThreadMgr14createInstanceEPN4sead4HeapE +0x0000007100dce0c4,WorkerSupportThreadMgr::init,656,_ZN4ksys3frm22WorkerSupportThreadMgr4initEPN4sead4HeapE +0x0000007100dce354,WorkerSupportThreadMgr::startSleeperThread,588,_ZN4ksys3frm22WorkerSupportThreadMgr18initSleeperThreadsEv +0x0000007100dce5a0,SleeperThreadFunc,44,_ZN4ksys3frm22WorkerSupportThreadMgr16sleeperThreadFunEPN4sead6ThreadEl +0x0000007100dce5cc,WorkerSupportThreadMgr::submitReq,240,_ZN4ksys3frm22WorkerSupportThreadMgr13submitRequestEiPN4sead11IDelegate1RIPvbEE +0x0000007100dce6bc,WorkerSupportThreadMgr::__auto0,68,_ZN4ksys3frm22WorkerSupportThreadMgr11waitForTaskEi +0x0000007100dce700,WorkerSupportThreadMgr::__auto3,48,_ZN4ksys3frm22WorkerSupportThreadMgr12pauseThreadsEv +0x0000007100dce730,WorkerSupportThreadMgr::__auto1,44,_ZN4ksys3frm22WorkerSupportThreadMgr13resumeThreadsEv +0x0000007100dce75c,WorkerSupportThreadMgr::__auto2,136,_ZN4ksys3frm22WorkerSupportThreadMgr14destroyThreadsEv +0x0000007100dce7e8,sub_7100DCE7E8,48,_ZN4sead9Delegate2IN4ksys3frm22WorkerSupportThreadMgrEPNS_6ThreadElE6invokeES5_l +0x0000007100dce818,sub_7100DCE818,92,_ZNK4sead9Delegate2IN4ksys3frm22WorkerSupportThreadMgrEPNS_6ThreadElE5cloneEPNS_4HeapE 0x0000007100dce874,sub_7100DCE874,32, 0x0000007100dce894,sub_7100DCE894,100,_ZN4ksys3gdt7Manager18SingletonDisposer_D1Ev 0x0000007100dce8f8,sub_7100DCE8F8,108,_ZN4ksys3gdt7Manager18SingletonDisposer_D0Ev diff --git a/src/KingSystem/Framework/CMakeLists.txt b/src/KingSystem/Framework/CMakeLists.txt index 1c098cd3..622647a3 100644 --- a/src/KingSystem/Framework/CMakeLists.txt +++ b/src/KingSystem/Framework/CMakeLists.txt @@ -1,3 +1,5 @@ target_sources(uking PRIVATE frmRootTaskParam.h + frmWorkerSupportThreadMgr.cpp + frmWorkerSupportThreadMgr.h ) diff --git a/src/KingSystem/Framework/frmWorkerSupportThreadMgr.cpp b/src/KingSystem/Framework/frmWorkerSupportThreadMgr.cpp new file mode 100644 index 00000000..53dea002 --- /dev/null +++ b/src/KingSystem/Framework/frmWorkerSupportThreadMgr.cpp @@ -0,0 +1,138 @@ +#include "KingSystem/Framework/frmWorkerSupportThreadMgr.h" +#include +#include +#include +#include "KingSystem/Utils/SafeDelete.h" +#include "KingSystem/Utils/Thread/GameTaskThread.h" +#include "KingSystem/Utils/Thread/ManagedTask.h" +#include "KingSystem/Utils/Thread/ManagedTaskHandle.h" +#include "KingSystem/Utils/Thread/TaskMgr.h" + +namespace ksys::frm { + +SEAD_SINGLETON_DISPOSER_IMPL(WorkerSupportThreadMgr) + +void WorkerSupportThreadMgr::init(sead::Heap* heap) { + auto* worker = mWorkers; + for (size_t i = 0; i < NumWorkers; ++i) { + auto* mgr = new (heap) util::TaskMgr(heap); + mgr->init(NumTasks, heap); + worker->task_mgr = mgr; + + worker->task_handle = new (heap) util::ManagedTaskHandle; + for (int j = 0; j < NumTasks; ++j) + worker->tasks[j] = new (heap) util::ManagedTask(heap); + + const auto affinity = [&] { + if (i == 0) + return sead::CoreIdMask(sead::CoreId::cSub1); + return sead::CoreIdMask(sead::CoreId::cSub2); + }(); + + worker->thread_name.format("WorkerSupport[%d]", int(i)); + worker->task_thread = new (heap) util::GameTaskThread( + worker->thread_name, heap, sead::ThreadUtil::ConvertPrioritySeadToPlatform(17), + sead::MessageQueue::BlockType::Blocking, 0x7fffffff, 0x20000, 32); + + util::TaskThread::InitArg arg; + arg.batch_size = 0; + arg.heap = nullptr; + arg.queue = nullptr; + arg.heap = heap; + arg.num_lanes = 1; + worker->task_thread->init(arg); + worker->task_thread->setAffinity(affinity); + worker->task_thread->start(); + ++worker; + } + + mSleeperHeap = sead::ExpHeap::create(0x8000, "SleeperHeap", heap, sizeof(void*), + sead::Heap::cHeapDirection_Forward, false); + initSleeperThreads(); + mSleeperHeap->adjust(); +} + +void WorkerSupportThreadMgr::initSleeperThreads() { + for (int i = 0; i < NumWorkers; ++i) { + const sead::CoreIdMask affinity{sead::CoreId::cSub1 + i}; + if (affinity == sead::CoreIdMask(sead::CoreId::cSub2)) { + mWorkers[i].thread = new (mSleeperHeap) sead::DelegateThread( + "Sleeper", + new (mSleeperHeap) sead::Delegate2( + this, &WorkerSupportThreadMgr::sleeperThreadFun), + mSleeperHeap, sead::ThreadUtil::ConvertPrioritySeadToPlatform(15), + sead::MessageQueue::BlockType::NonBlocking, 0x7fffffff, 0x1000, 32); + mWorkers[i].thread->setAffinity(affinity); + mWorkers[i].thread->start(); + mWorkers[i].thread->sendMessage(1, sead::MessageQueue::BlockType::NonBlocking); + } else { + mWorkers[i].thread = nullptr; + } + } +} + +void WorkerSupportThreadMgr::sleeperThreadFun(sead::Thread* thread, sead::MessageQueue::Element) { + sead::Thread::sleep(sead::TickSpan::fromMicroSeconds(250)); +} + +static int getWorkerIdx(u32 id) { + return (id == 1 || id == 4 || id == 6 || id == 3 || id == 7) ? 1 : 0; +} + +static int getTaskIdx(u32 id) { + static constexpr u8 idx[] = {0, 0, 1, 1, 2, 2, 3, 4}; + return idx[id]; +} + +util::ManagedTask* WorkerSupportThreadMgr::getTask(int id) { + return mWorkers[getWorkerIdx(id)].tasks[getTaskIdx(id)]; +} + +void WorkerSupportThreadMgr::submitRequest(int id, util::TaskDelegate* delegate) { + auto& worker = mWorkers[getWorkerIdx(id)]; + if (mThreadsPaused) + return; + + util::TaskRequest req{false}; + req.mName = worker.thread_name; + req.mDelegate = delegate; + req.mHasHandle = true; + req.mSynchronous = false; + req.mThread = worker.task_thread; + + util::TaskMgrRequest task_mgr_req; + task_mgr_req.request = &req; + task_mgr_req.handle = worker.task_handle; + task_mgr_req.task = worker.tasks[getTaskIdx(id)]; + worker.task_mgr->submitRequest(task_mgr_req); +} + +void WorkerSupportThreadMgr::waitForTask(int id) { + if (!mThreadsPaused) + getTask(id)->wait(); +} + +void WorkerSupportThreadMgr::pauseThreads() { + mThreadsPaused = true; + for (auto& worker : mWorkers) + worker.task_thread->pauseAndWaitForAck(); +} + +void WorkerSupportThreadMgr::resumeThreads() { + mThreadsPaused = false; + for (auto& worker : mWorkers) + worker.task_thread->resume(); +} + +void WorkerSupportThreadMgr::destroyThreads() { + for (auto& worker : mWorkers) { + if (worker.thread) { + worker.thread->quitAndDestroySingleThread(false); + util::safeDelete(worker.thread); + } + } + mSleeperHeap->freeAll(); +} + +} // namespace ksys::frm diff --git a/src/KingSystem/Framework/frmWorkerSupportThreadMgr.h b/src/KingSystem/Framework/frmWorkerSupportThreadMgr.h new file mode 100644 index 00000000..00e8a359 --- /dev/null +++ b/src/KingSystem/Framework/frmWorkerSupportThreadMgr.h @@ -0,0 +1,72 @@ +#pragma once + +#include +#include +#include +#include "KingSystem/Utils/Thread/Task.h" +#include "KingSystem/Utils/Types.h" + +namespace sead { +class DelegateThread; +class Thread; +} // namespace sead + +namespace ksys::util { +class GameTaskThread; +class ManagedTask; +class ManagedTaskHandle; +class TaskMgr; +} // namespace ksys::util + +namespace ksys::frm { + +class WorkerSupportThreadMgr { + SEAD_SINGLETON_DISPOSER(WorkerSupportThreadMgr) + WorkerSupportThreadMgr() = default; + ~WorkerSupportThreadMgr() = default; + +public: + enum class Owner { + _0, + _1, + _2, + _3, + _4, + _5, + _6, + _7, + }; + + void init(sead::Heap* heap); + + void submitRequest(int id, util::TaskDelegate* delegate); + void waitForTask(int id); + void pauseThreads(); + void resumeThreads(); + void destroyThreads(); + +private: + static constexpr int NumWorkers = 2; + static constexpr int NumTasks = 5; + + struct Worker { + util::GameTaskThread* task_thread = nullptr; + sead::DelegateThread* thread; + util::ManagedTask* tasks[NumTasks]; + util::TaskMgr* task_mgr = nullptr; + util::ManagedTaskHandle* task_handle; + sead::FixedSafeString<32> thread_name; + }; + + void initSleeperThreads(); + void sleeperThreadFun(sead::Thread* thread, sead::MessageQueue::Element); + + util::ManagedTask* getTask(int id); + + Worker mWorkers[NumWorkers]; + bool mThreadsPaused = false; + sead::Heap* mSleeperHeap; +}; +KSYS_CHECK_SIZE_NX150(WorkerSupportThreadMgr, 0x130); + +} // namespace ksys::frm