1#include "mc/seadWorker.h"
2#include "prim/seadScopedLock.h"
3
4namespace sead
5{
6Worker::Worker(WorkerMgr* mgr, u32 num_jobs, s32 stack_size, s32 priority, const SafeString& name)
7 : Thread(name, nullptr, priority, MessageQueue::BlockType::Blocking, 0x7FFFFFFF, stack_size, 1),
8 mMgr(mgr)
9{
10 mJobQueues.allocBufferAssert(size: num_jobs, heap: nullptr);
11 mEvent.setSignal();
12}
13
14bool Worker::pushJobQueue(const char* description, JobQueue* queue, JobQueuePushType type)
15{
16 ScopedLock<JobQueueLock> lock(&mLock);
17
18 bool ret;
19 if (type == JobQueuePushType::cForward)
20 ret = mJobQueues.pushBack(item: queue);
21 else
22 ret = mJobQueues.pushBackwards(item: queue);
23
24 queue->setDescription(description);
25 return ret;
26}
27
28void Worker::clearJobQQ()
29{
30 ScopedLock<JobQueueLock> lock(&mLock);
31 mJobQueues.clear();
32}
33
34void Worker::calc_(MessageQueue::Element msg)
35{
36 if (msg == cMsg_Process)
37 proc_();
38}
39
40void Worker::proc_()
41{
42 ++mNumRuns;
43 mLastRun.setNow();
44 mWorkerState = Worker::State::cRunning;
45
46 JobQueue* queue = getNextJQ_();
47 const u32 core = mCore;
48 while (queue)
49 {
50 mCurrentQueue = queue;
51 mCurrentQueueDescription = queue->getDescription();
52
53 const auto granularity = queue->getGranularity(core);
54
55 // Process the queue.
56 queue->resetFinishEvent();
57 volatile bool ok = false;
58 u32 total_finished_jobs = 0;
59 while (!ok)
60 {
61 u32 finished_jobs = 0;
62 ok = queue->run(size: granularity, finished_jobs: &finished_jobs, worker: this);
63 total_finished_jobs += finished_jobs;
64 }
65
66 const u32 num_done = queue->addNumDoneJobs(num: total_finished_jobs);
67
68 if (num_done >= queue->getNumJobs())
69 queue->signalFinishEvent();
70
71 mWorkerState = Worker::State::cFinished;
72 queue->FINISH(core: mCore);
73 mWorkerState = Worker::State::cWaitingAtWorker;
74
75 mWorkerState = Worker::State::cRunning;
76 queue = getNextJQ_();
77 }
78
79 mCurrentQueue = nullptr;
80 mCurrentQueueDescription = nullptr;
81 mWorkerState = Worker::State::cSleep;
82 mEvent.setSignal();
83}
84
85JobQueue* Worker::getNextJQ_()
86{
87 ScopedLock<JobQueueLock> lock(&mLock);
88 return mJobQueues ? mJobQueues.popFront() : nullptr;
89}
90
91void Worker::wakeup_(MessageQueue::Element msg)
92{
93 SEAD_ASSERT_MSG(mWorkerState.load() == Worker::State::cSleep, "invalid state[%s]",
94 mWorkerState.load().text());
95
96 if (mJobQueues)
97 {
98 mEvent.resetSignal();
99 mWorkerState = Worker::State::cWakeup;
100 const bool success = sendMessage(msg, block_type: MessageQueue::BlockType::NonBlocking);
101 SEAD_ASSERT(success);
102 }
103}
104} // namespace sead
105