| 1 | #include "mc/seadWorker.h" |
| 2 | #include "prim/seadScopedLock.h" |
| 3 | |
| 4 | namespace sead |
| 5 | { |
| 6 | Worker::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 | |
| 14 | bool 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 | |
| 28 | void Worker::clearJobQQ() |
| 29 | { |
| 30 | ScopedLock<JobQueueLock> lock(&mLock); |
| 31 | mJobQueues.clear(); |
| 32 | } |
| 33 | |
| 34 | void Worker::calc_(MessageQueue::Element msg) |
| 35 | { |
| 36 | if (msg == cMsg_Process) |
| 37 | proc_(); |
| 38 | } |
| 39 | |
| 40 | void 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 | |
| 85 | JobQueue* Worker::getNextJQ_() |
| 86 | { |
| 87 | ScopedLock<JobQueueLock> lock(&mLock); |
| 88 | return mJobQueues ? mJobQueues.popFront() : nullptr; |
| 89 | } |
| 90 | |
| 91 | void 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 | |