diff options
| author | Léo Lam <leo@leolam.fr> | 2021-04-26 15:59:49 +0200 |
|---|---|---|
| committer | Léo Lam <leo@leolam.fr> | 2021-04-26 17:56:01 +0200 |
| commit | 927c757345dcdeb5f77f421f9e05414d81b422b1 (patch) | |
| tree | 9a7a68ea02294e0da93b2b8b99a992076491f2a1 /src/KingSystem/Framework/frmWorkerSupportThreadMgr.cpp | |
| parent | caa3dcf5489f54c1aeb0bc1981f8de6441ddb0cc (diff) | |
ksys/frm: Implement WorkerSupportThreadMgr
Diffstat (limited to 'src/KingSystem/Framework/frmWorkerSupportThreadMgr.cpp')
| -rw-r--r-- | src/KingSystem/Framework/frmWorkerSupportThreadMgr.cpp | 138 |
1 files changed, 138 insertions, 0 deletions
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 <mc/seadCoreInfo.h> +#include <thread/seadDelegateThread.h> +#include <thread/seadThreadUtil.h> +#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<util::ManagedTask>(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<WorkerSupportThreadMgr, sead::Thread*, + sead::MessageQueue::Element>( + 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 |
