botw/src/KingSystem/Framework/frmWorkerSupportThreadMgr.cpp

139 lines
4.7 KiB
C++

#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