1#include "mc/seadWorkerMgr.h"
2#include "framework/seadInfLoopChecker.h"
3#include "prim/seadSafeString.h"
4
5namespace sead
6{
7WorkerMgr::WorkerMgr()
8 : mInfLoopEventSlot{
9 Delegate1<WorkerMgr, const InfLoopChecker::InfLoopParam&>(this, &WorkerMgr::onInfLoop_)}
10{
11}
12
13void WorkerMgr::onInfLoop_(const InfLoopChecker::InfLoopParam&)
14{
15 TickTime time;
16}
17
18WorkerMgr::InitializeArg::InitializeArg()
19{
20 worker_num_jobs = 0x20;
21 name = "WorkerMgr";
22 thread_stack_sizes[0] = 0x1000;
23 thread_priorities.fill(u: Thread::cDefaultPriority);
24 thread_stack_sizes[1] = thread_stack_sizes[2] = 0x8000;
25}
26
27static SafeString* makeWorkerName(Heap* heap, const WorkerMgr::InitializeArg& arg, u32 core)
28{
29 FixedSafeString<128> name;
30 const char* core_name = "?";
31#ifdef SEAD_DEBUG
32 core_name = CoreId(i).text();
33#endif
34 name.format(formatStr: "%s/Worker%d(%s)", arg.name, core, core_name);
35 return new HeapSafeString(heap, name);
36}
37
38void WorkerMgr::initialize(const InitializeArg& arg)
39{
40 if (InfLoopChecker::instance())
41 InfLoopChecker::instance()->getEvent().connect(slot&: mInfLoopEventSlot);
42
43 const u32 num_cores = CoreInfo::getNumCores();
44 auto* heap = HeapMgr::instance()->getCurrentHeap();
45 SEAD_ASSERT(heap);
46
47 mWorkers.allocBufferAssert(size: num_cores, heap);
48
49 for (u32 i = 0; i < num_cores; ++i)
50 {
51 auto* name = makeWorkerName(heap, arg, core: i);
52 auto* worker = new Worker(this, arg.worker_num_jobs, arg.thread_stack_sizes[i],
53 arg.thread_priorities[i], *name);
54 mWorkers[i] = worker;
55 worker->mCore = i;
56 if (worker->mCore)
57 {
58 worker->setAffinity(CoreIdMask(i));
59 worker->start();
60 }
61 }
62
63 mJobQueues.allocBufferAssert(size: 64, heap: nullptr);
64 mNumJobQueues = 0;
65}
66
67void WorkerMgr::finalize()
68{
69 if (mWorkers.size() > 1)
70 {
71 ThreadMgr::quitAndWaitDoneMultipleThread(
72 threads: reinterpret_cast<Thread**>(mWorkers.getBufferPtr() + 1), num: mWorkers.size() - 1, is_jam: true);
73 }
74
75 for (u32 i = 0, n = CoreInfo::getNumCores(); i != n; ++i)
76 {
77 if (mWorkers[i])
78 delete mWorkers[i];
79 mWorkers[i] = nullptr;
80 }
81}
82
83void WorkerMgr::pushJobQueue(JobQueue* queue, CoreIdMask core_id_mask, SyncType sync_type,
84 JobQueuePushType push_type)
85{
86 pushJobQueue(context_name: "nocontext", queue, core_id_mask, sync_type, push_type);
87}
88
89void WorkerMgr::pushJobQueue(const char* context_name, JobQueue* queue, CoreIdMask core_id_mask,
90 SyncType sync_type, JobQueuePushType push_type)
91{
92 SEAD_ASSERT_MSG(core_id_mask, "core_id_mask must not be 0. context_name = %s", context_name);
93
94 queue->setCoreMaskAndWaitType(mask: core_id_mask, type: sync_type);
95 queue->begin();
96
97 for (int i = 0; i < mWorkers.size(); ++i)
98 {
99 if (core_id_mask.isOn(id: i))
100 mWorkers[i]->pushJobQueue(name: context_name, queue, type: push_type);
101 }
102
103 mJobQueues[mNumJobQueues] = queue;
104 ++mNumJobQueues;
105}
106
107void WorkerMgr::run()
108{
109 if (mProcessJobQueues)
110 {
111 for (u32 i = 0; i < mNumJobQueues; ++i)
112 {
113 mJobQueues[i]->begin();
114 u32 finished_jobs = 0;
115 mJobQueues[i]->runAll(finished_jobs: &finished_jobs);
116 mJobQueues[i]->addNumDoneJobs(num: finished_jobs);
117 mJobQueues[i]->FINISH(core: CoreInfo::getCurrentCoreId());
118
119 for (int j = 0; j < mWorkers.size(); ++j)
120 mWorkers[j]->clearJobQQ();
121 }
122 }
123 else
124 {
125 ++mNumWakeups;
126 mLastWakeup.setNow();
127 for (int i = 0; i < mWorkers.size(); ++i)
128 {
129 if (mWorkers[i]->mCore)
130 mWorkers[i]->wakeup_(msg: Worker::cMsg_Process);
131 }
132 }
133}
134
135void WorkerMgr::sync()
136{
137 if (!mProcessJobQueues)
138 mWorkers[0]->proc_();
139
140 for (auto it = mWorkers.begin(idx: 1), end = mWorkers.end(); it != end; ++it)
141 {
142 while (!(*it)->mEvent.wait(duration: mWaitDuration))
143 continue;
144 }
145
146 if (!isAllWorkerSleep())
147 {
148 std::array<Worker::State, 256> states{};
149 u32 idx = 0;
150 for (int i = 0; i < mWorkers.size(); ++i)
151 {
152 states[idx] = mWorkers[i]->mWorkerState.load();
153 ++idx;
154 }
155
156 for (int i = 0; i < mWorkers.size(); ++i)
157 SEAD_DEBUG_PRINT(" [%d] [%s] = %s\n", i, mWorkers[i]->mCore.text(), states[i].text());
158
159 SEAD_ASSERT_MSG(false, "all sleep failed\n");
160 }
161
162 mNumJobQueues = 0;
163}
164
165bool WorkerMgr::isAllWorkerSleep() const
166{
167 for (int i = 0; i < mWorkers.size(); ++i)
168 {
169 if (mWorkers[i]->mWorkerState.load() != Worker::State::cSleep)
170 return false;
171 }
172 return true;
173}
174
175} // namespace sead
176