ksys: Add more task utilities

* TaskMgr, ManagedTask, ManagedTaskHandle

* GameTaskThread: partial implementation because PhysicsMemSys / Havok
  stuff hasn't been decompiled yet and calc_() requires PhysicsMemSys
This commit is contained in:
Léo Lam 2020-09-15 19:13:52 +02:00
parent 8b7369dffb
commit 3db6228dfc
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
10 changed files with 722 additions and 52 deletions

View File

@ -76,8 +76,16 @@ add_executable(uking
src/KingSystem/Utils/Thread/Event.cpp
src/KingSystem/Utils/Thread/Event.h
src/KingSystem/Utils/Thread/GameTaskThread.cpp
src/KingSystem/Utils/Thread/GameTaskThread.h
src/KingSystem/Utils/Thread/ManagedTask.cpp
src/KingSystem/Utils/Thread/ManagedTask.h
src/KingSystem/Utils/Thread/ManagedTaskHandle.cpp
src/KingSystem/Utils/Thread/ManagedTaskHandle.h
src/KingSystem/Utils/Thread/Task.cpp
src/KingSystem/Utils/Thread/Task.h
src/KingSystem/Utils/Thread/TaskMgr.cpp
src/KingSystem/Utils/Thread/TaskMgr.h
src/KingSystem/Utils/Thread/TaskQueueBase.cpp
src/KingSystem/Utils/Thread/TaskQueueBase.h
src/KingSystem/Utils/Thread/TaskQueue.cpp

View File

@ -86813,19 +86813,19 @@
0x00000071010c2a1c,sub_71010C2A1C,24,
0x00000071010c2a34,sub_71010C2A34,20,
0x00000071010c2a48,j__ZdlPv_1198,4,
0x00000071010c2a4c,Res1::ctor,32,
0x00000071010c2a6c,Res1::dtor,128,
0x00000071010c2aec,Res1::b,160,
0x00000071010c2b8c,sub_71010C2B8C,108,
0x00000071010c2bf8,Res1::dtorDelete,136,
0x00000071010c2c80,Res1::a,16,
0x00000071010c2c90,Res1::o,164,
0x00000071010c2d34,sub_71010C2D34,248,
0x00000071010c2e2c,Res1::field18andfieldCTrue_NotReady,32,
0x00000071010c2e4c,sub_71010C2E4C,36,
0x00000071010c2e70,sub_71010C2E70,96,
0x00000071010c2ed0,sub_71010C2ED0,8,
0x00000071010c2ed8,sub_71010C2ED8,12,
0x00000071010c2a4c,Res1::ctor,32,_ZN4ksys4util17ManagedTaskHandleC1Ev
0x00000071010c2a6c,Res1::dtor,128,_ZN4ksys4util17ManagedTaskHandleD1Ev
0x00000071010c2aec,Res1::b,160,_ZN4ksys4util17ManagedTaskHandle19removeTaskFromQueueEv
0x00000071010c2b8c,sub_71010C2B8C,108,_ZN4ksys4util17ManagedTaskHandle8finalizeEv
0x00000071010c2bf8,Res1::dtorDelete,136,_ZN4ksys4util17ManagedTaskHandleD0Ev
0x00000071010c2c80,Res1::a,16,_ZNK4ksys4util17ManagedTaskHandle7hasTaskEv
0x00000071010c2c90,Res1::o,164,_ZN4ksys4util17ManagedTaskHandle4waitEv
0x00000071010c2d34,sub_71010C2D34,248,_ZN4ksys4util17ManagedTaskHandle4waitERKN4sead8TickSpanE
0x00000071010c2e2c,Res1::field18andfieldCTrue_NotReady,32,_ZNK4ksys4util17ManagedTaskHandle14isTaskAttachedEv
0x00000071010c2e4c,sub_71010C2E4C,36,_ZNK4ksys4util17ManagedTaskHandle27didTaskCompleteSuccessfullyEv
0x00000071010c2e70,sub_71010C2E70,96,_ZN4ksys4util17ManagedTaskHandle10attachTaskERKNS1_10SetTaskArgE
0x00000071010c2ed0,sub_71010C2ED0,8,_ZN4ksys4util17ManagedTaskHandle9setStatusENS1_6StatusE
0x00000071010c2ed8,sub_71010C2ED8,12,_ZN4ksys4util17ManagedTaskHandle12setIsSuccessEb
0x00000071010c2ee4,sub_71010C2EE4,516,
0x00000071010c30e8,sub_71010C30E8,44,
0x00000071010c3114,ElementSpark::ctor,280,
@ -90490,33 +90490,33 @@
0x00000071011f7284,sub_71011F7284,92,_ZNK4ksys4util17TaskPostRunResult18getRuntimeTypeInfoEv
0x00000071011f72e0,j__ZdlPv_1226,4,_ZN4ksys4util17TaskPostRunResultD0Ev
0x00000071011f72e4,sub_71011F72E4,44,
0x00000071011f7310,EventPlusStringDerived::ctor,60,
0x00000071011f734c,sub_71011F734C,72,
0x00000071011f7394,EventPlusStringDerived::dtor,72,
0x00000071011f73dc,EventPlusStringDerived::dtorDelete,80,
0x00000071011f742c,EventPlusStringDerived::a,16,
0x00000071011f743c,EventPlusStringDerived::b,44,
0x00000071011f7468,EventPlusStringDerived::null1,4,
0x00000071011f746c,EventPlusStringDerived::c,100,
0x00000071011f74d0,EventPlusStringDerived::d,12,
0x00000071011f74dc,EventPlusStringDerived::e,88,
0x00000071011f7534,EventPlusStringDerived::f,12,
0x00000071011f7540,EventPlusStringDerived::null1_0,4,
0x00000071011f7544,EventPlusStringDerived::null1_1,4,
0x00000071011f7548,EventPlusStringDerived::null1_2,4,
0x00000071011f754c,sub_71011F754C,8,
0x00000071011f7554,EventPlusStringDerived::setWorkerThread,8,
0x00000071011f755c,EventPlusStringDerived::z,84,
0x00000071011f75b0,sub_71011F75B0,128,
0x00000071011f7630,EventPlusStringDerived::rtti1,204,
0x00000071011f76fc,EventPlusStringDerived::rtti2,92,
0x00000071011f7758,ThreadDerived::ctor,68,
0x00000071011f779c,ThreadDerived::dtor,28,
0x00000071011f77b8,ThreadDerived::dtorDelete,60,
0x00000071011f77f4,ThreadDerived::quit,52,
0x00000071011f7310,EventPlusStringDerived::ctor,60,_ZN4ksys4util11ManagedTaskC1EPN4sead4HeapE
0x00000071011f734c,sub_71011F734C,72,_ZN4ksys4util11ManagedTaskC1EN4sead9IDisposer14HeapNullOptionE
0x00000071011f7394,EventPlusStringDerived::dtor,72,_ZN4ksys4util11ManagedTaskD1Ev
0x00000071011f73dc,EventPlusStringDerived::dtorDelete,80,_ZN4ksys4util11ManagedTaskD0Ev
0x00000071011f742c,EventPlusStringDerived::a,16,_ZN4ksys4util11ManagedTask8prepare_EPNS0_11TaskRequestE
0x00000071011f743c,EventPlusStringDerived::b,44,_ZN4ksys4util11ManagedTask4run_Ev
0x00000071011f7468,EventPlusStringDerived::null1,4,_ZN4ksys4util11ManagedTask14onRunFinished_Ev
0x00000071011f746c,EventPlusStringDerived::c,100,_ZN4ksys4util11ManagedTask9onFinish_Ev
0x00000071011f74d0,EventPlusStringDerived::d,12,_ZN4ksys4util11ManagedTask13onPostFinish_Ev
0x00000071011f74dc,EventPlusStringDerived::e,88,_ZN4ksys4util11ManagedTask10preRemove_Ev
0x00000071011f7534,EventPlusStringDerived::f,12,_ZN4ksys4util11ManagedTask11postRemove_Ev
0x00000071011f7540,EventPlusStringDerived::null1_0,4,_ZN4ksys4util11ManagedTask6onRun_Ev
0x00000071011f7544,EventPlusStringDerived::null1_1,4,_ZN4ksys4util11ManagedTask12prepareImpl_EPNS0_11TaskRequestE
0x00000071011f7548,EventPlusStringDerived::null1_2,4,_ZN4ksys4util11ManagedTask14preRemoveImpl_Ev
0x00000071011f754c,sub_71011F754C,8,_ZNK4ksys4util11ManagedTask6isIdleEv
0x00000071011f7554,EventPlusStringDerived::setWorkerThread,8,_ZN4ksys4util11ManagedTask6setMgrEPNS0_7TaskMgrE
0x00000071011f755c,EventPlusStringDerived::z,84,_ZN4ksys4util11ManagedTask12attachHandleEPNS0_17ManagedTaskHandleEPNS0_13TaskQueueBaseE
0x00000071011f75b0,sub_71011F75B0,128,_ZN4ksys4util11ManagedTask12detachHandleEv?
0x00000071011f7630,EventPlusStringDerived::rtti1,204,_ZNK4ksys4util11ManagedTask27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x00000071011f76fc,EventPlusStringDerived::rtti2,92,_ZNK4ksys4util11ManagedTask18getRuntimeTypeInfoEv
0x00000071011f7758,ThreadDerived::ctor,68,_ZN4ksys4util14GameTaskThreadC1ERKN4sead14SafeStringBaseIcEEPNS2_4HeapEiNS2_12MessageQueue9BlockTypeElii
0x00000071011f779c,ThreadDerived::dtor,28,_ZN4ksys4util14GameTaskThreadD2Ev
0x00000071011f77b8,ThreadDerived::dtorDelete,60,_ZN4ksys4util14GameTaskThreadD0Ev
0x00000071011f77f4,ThreadDerived::quit,52,_ZN4ksys4util14GameTaskThread4quitEb
0x00000071011f7828,ThreadDerived::calc_,164,
0x00000071011f78cc,sub_71011F78CC,204,
0x00000071011f7998,sub_71011F7998,92,
0x00000071011f78cc,sub_71011F78CC,204,_ZNK4ksys4util14GameTaskThread27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x00000071011f7998,sub_71011F7998,92,_ZNK4ksys4util14GameTaskThread18getRuntimeTypeInfoEv
0x00000071011f79f4,sub_71011F79F4,140,
0x00000071011f7a80,SetMainInvokerClass::ctor,20,_ZN4ksys4util18TaskDelegateSetterC1Ev
0x00000071011f7a94,SetMainInvokerClass::dtor,4,_ZN4ksys4util18TaskDelegateSetterD1Ev
@ -90569,19 +90569,19 @@
0x00000071011f8748,sub_71011F8748,112,_ZNK4ksys4util18TaskPostRunContext27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x00000071011f87b8,sub_71011F87B8,92,_ZNK4ksys4util18TaskPostRunContext18getRuntimeTypeInfoEv
0x00000071011f8814,j__ZdlPv_1229,4,_ZN4ksys4util18TaskPostRunContextD0Ev
0x00000071011f8818,WorkerThread::ctor,172,
0x00000071011f88c4,WorkerThread::dtor,80,
0x00000071011f8914,WorkerThread::deleteElements,196,
0x00000071011f89d8,WorkerThread::dtorDelete,88,
0x00000071011f8a30,WorkerThread::submitRequest,408,
0x00000071011f8bc8,WorkerThread::lockAndRemoveSomethingFromQueueAndWait,276,
0x00000071011f8cdc,sub_71011F8CDC,112,
0x00000071011f8d4c,WorkerThread::submitRequest2,460,
0x00000071011f8f18,WorkerThread::init,380,
0x00000071011f9094,WorkerThread::hasQueue,16,
0x00000071011f90a4,WorkerThread::removeSomethingFromQueueAndWait,428,
0x00000071011f9250,WorkerThread::rtti1,112,
0x00000071011f92c0,WorkerThread::rtti2,92,
0x00000071011f8818,WorkerThread::ctor,172,_ZN4ksys4util7TaskMgrC1EPN4sead4HeapE
0x00000071011f88c4,WorkerThread::dtor,80,_ZN4ksys4util7TaskMgrD1Ev
0x00000071011f8914,WorkerThread::deleteElements,196,_ZN4ksys4util7TaskMgr8finalizeEv
0x00000071011f89d8,WorkerThread::dtorDelete,88,_ZN4ksys4util7TaskMgrD0Ev
0x00000071011f8a30,WorkerThread::submitRequest,408,_ZN4ksys4util7TaskMgr13submitRequestERNS0_14TaskMgrRequestE
0x00000071011f8bc8,WorkerThread::lockAndRemoveSomethingFromQueueAndWait,276,_ZN4ksys4util7TaskMgr24fetchIdleTaskForRequest_ERNS0_14TaskMgrRequestEb?
0x00000071011f8cdc,sub_71011F8CDC,112,_ZN4ksys4util7TaskMgr8freeTaskEPNS0_11ManagedTaskE
0x00000071011f8d4c,WorkerThread::submitRequest2,460,_ZN4ksys4util7TaskMgr16trySubmitRequestERNS0_14TaskMgrRequestE
0x00000071011f8f18,WorkerThread::init,380,_ZN4ksys4util7TaskMgr4initEiPN4sead4HeapERNS2_10IDelegate1IPPNS0_11ManagedTaskEEE?
0x00000071011f9094,WorkerThread::hasQueue,16,_ZNK4ksys4util7TaskMgr8hasTasksEv
0x00000071011f90a4,WorkerThread::removeSomethingFromQueueAndWait,428,_ZN4ksys4util7TaskMgr14fetchIdleTask_Eb
0x00000071011f9250,WorkerThread::rtti1,112,_ZNK4ksys4util7TaskMgr27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x00000071011f92c0,WorkerThread::rtti2,92,_ZNK4ksys4util7TaskMgr18getRuntimeTypeInfoEv
0x00000071011f931c,SeadController::getInstance,12,
0x00000071011f9328,SeadController::setInstance,12,
0x00000071011f9334,sub_71011F9334,12,

Can't render this file because it is too large.

View File

@ -0,0 +1,15 @@
#include "KingSystem/Utils/Thread/GameTaskThread.h"
namespace ksys::util {
GameTaskThread::GameTaskThread(const sead::SafeString& name, sead::Heap* heap, s32 priority,
sead::MessageQueue::BlockType block_type, long quit_msg,
s32 stack_size, s32 message_queue_size)
: TaskThread(name, heap, priority, block_type, quit_msg, stack_size, message_queue_size) {}
void GameTaskThread::quit(bool) {
mMessageQueue.push(cMessage_GameThreadQuit, sead::MessageQueue::BlockType::Blocking);
Thread::quit(false);
}
} // namespace ksys::util

View File

@ -0,0 +1,27 @@
#pragma once
#include "KingSystem/Utils/Thread/TaskThread.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::util {
class GameTaskThread : public TaskThread {
SEAD_RTTI_OVERRIDE(GameTaskThread, TaskThread)
public:
GameTaskThread(const sead::SafeString& name, sead::Heap* heap, s32 priority,
sead::MessageQueue::BlockType block_type, long quit_msg, s32 stack_size,
s32 message_queue_size);
~GameTaskThread() override { ; }
void quit(bool is_jam) override;
protected:
static constexpr s32 cMessage_GameThreadQuit = 4;
void calc_(sead::MessageQueue::Element msg) override;
u8 _1a0 = 0;
s32 _1a4 = -1;
};
KSYS_CHECK_SIZE_NX150(GameTaskThread, 0x1a8);
} // namespace ksys::util

View File

@ -0,0 +1,106 @@
#include "KingSystem/Utils/Thread/ManagedTask.h"
#include "KingSystem/Utils/Thread/ManagedTaskHandle.h"
#include "KingSystem/Utils/Thread/TaskMgr.h"
#include "KingSystem/Utils/Thread/TaskQueueLock.h"
namespace ksys::util {
ManagedTask::ManagedTask(sead::Heap* heap) : Task(heap) {}
ManagedTask::ManagedTask(sead::IDisposer::HeapNullOption heap_null_option)
: Task(nullptr, heap_null_option) {}
ManagedTask::~ManagedTask() {
if (mHandle) {
mHandle->finalize();
mHandle = nullptr;
}
finalize_();
}
void ManagedTask::prepare_(TaskRequest* request) {
mIsIdle = false;
prepareImpl_(request);
}
void ManagedTask::run_() {
Task::run_();
onRun_();
}
void ManagedTask::onRunFinished_() {}
void ManagedTask::onFinish_() {
if (auto* handle = mHandle) {
handle->setIsSuccess(isSuccess());
handle->setStatus(ManagedTaskHandle::Status::TaskFinished);
}
if (!mHandle && mMgr)
mMgr->freeTask(this);
}
void ManagedTask::onPostFinish_() {
mIsIdle = true;
}
void ManagedTask::preRemove_() {
preRemoveImpl_();
if (mHandle)
mHandle->setStatus(ManagedTaskHandle::Status::TaskRemoved);
if (!mHandle && mMgr)
mMgr->freeTask(this);
}
void ManagedTask::postRemove_() {
mIsIdle = true;
}
void ManagedTask::onRun_() {}
void ManagedTask::prepareImpl_(TaskRequest*) {}
void ManagedTask::preRemoveImpl_() {}
bool ManagedTask::isIdle() const {
return mIsIdle;
}
void ManagedTask::setMgr(TaskMgr* mgr) {
mMgr = mgr;
}
void ManagedTask::attachHandle(ManagedTaskHandle* handle, TaskQueueBase* queue) {
if (mHandle)
return;
if (handle) {
handle->attachTask({this, queue});
handle->setStatus(ManagedTaskHandle::Status::TaskAttached);
}
mHandle = handle;
}
// NON_MATCHING: switch
void ManagedTask::detachHandle() {
TaskQueueLock lock;
lock.lock(mQueue);
if (mHandle) {
switch (mHandle->getStatus()) {
case ManagedTaskHandle::Status::TaskRemoved:
case ManagedTaskHandle::Status::TaskFinished:
mHandle = nullptr;
if (mMgr)
mMgr->freeTask(this);
break;
default:
mHandle = nullptr;
break;
}
}
}
} // namespace ksys::util

View File

@ -0,0 +1,47 @@
#pragma once
#include "KingSystem/Utils/Thread/Task.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::util {
class ManagedTaskHandle;
class TaskMgr;
class ManagedTask : public Task {
SEAD_RTTI_OVERRIDE(ManagedTask, Task)
public:
explicit ManagedTask(sead::Heap* heap);
explicit ManagedTask(sead::IDisposer::HeapNullOption heap_null_option);
~ManagedTask() override;
bool isIdle() const;
protected:
friend class ManagedTaskHandle;
friend class TaskMgr;
void setMgr(TaskMgr* mgr);
void attachHandle(ManagedTaskHandle* handle, TaskQueueBase* queue);
void detachHandle();
void prepare_(TaskRequest* request) override;
void run_() override;
void onRunFinished_() override;
void onFinish_() override;
void onPostFinish_() override;
void preRemove_() override;
void postRemove_() override;
virtual void onRun_();
virtual void prepareImpl_(TaskRequest* req);
virtual void preRemoveImpl_();
bool mIsIdle = true;
TaskMgr* mMgr = nullptr;
// FIXME: rename
ManagedTaskHandle* mHandle = nullptr;
};
KSYS_CHECK_SIZE_NX150(ManagedTask, 0xc0);
} // namespace ksys::util

View File

@ -0,0 +1,107 @@
#include "KingSystem/Utils/Thread/ManagedTaskHandle.h"
#include "KingSystem/Utils/Thread/ManagedTask.h"
#include "KingSystem/Utils/Thread/TaskQueueBase.h"
#include "KingSystem/Utils/Thread/TaskQueueLock.h"
namespace ksys::util {
ManagedTaskHandle::ManagedTaskHandle() = default;
ManagedTaskHandle::~ManagedTaskHandle() {
removeTaskFromQueue();
finalize();
}
void ManagedTaskHandle::removeTaskFromQueue() {
if (!mQueue)
return;
incrementRef_();
if (mTask)
mTask->removeFromQueue();
decrementRef_();
}
void ManagedTaskHandle::finalize() {
if (mQueue)
decrementRef_();
}
bool ManagedTaskHandle::hasTask() const {
return mTask != nullptr;
}
bool ManagedTaskHandle::wait() {
if (!mQueue)
return true;
incrementRef_();
if (mTask)
mTask->wait();
decrementRef_();
return true;
}
bool ManagedTaskHandle::wait(const sead::TickSpan& wait_duration) {
if (!mQueue)
return true;
incrementRef_();
if (!mTask) {
decrementRef_();
return true;
}
const bool ret = mTask->wait(wait_duration);
decrementRef_();
return ret;
}
bool ManagedTaskHandle::isTaskAttached() const {
return mTask && mStatus == Status::TaskAttached;
}
bool ManagedTaskHandle::didTaskCompleteSuccessfully() const {
return mStatus == Status::TaskFinished && mSuccess;
}
bool ManagedTaskHandle::attachTask(const SetTaskArg& arg) {
mTask = arg.task;
mQueue = arg.queue;
incrementRef_();
return true;
}
void ManagedTaskHandle::setStatus(Status status) {
mStatus = status;
}
void ManagedTaskHandle::setIsSuccess(bool success) {
mSuccess = success;
}
inline void ManagedTaskHandle::incrementRef_() {
TaskQueueLock lock;
mQueue->lock(&lock);
++mRefCount;
}
inline void ManagedTaskHandle::decrementRef_() {
TaskQueueLock lock;
mQueue->lock(&lock);
if (mRefCount > 0)
--mRefCount;
if (mRefCount <= 0 && mTask) {
mTask->detachHandle();
mTask = nullptr;
}
}
} // namespace ksys::util

View File

@ -0,0 +1,60 @@
#pragma once
#include <basis/seadTypes.h>
#include <time/seadTickSpan.h>
#include "KingSystem/Utils/Types.h"
namespace ksys::util {
class ManagedTask;
class TaskQueueBase;
class ManagedTaskHandle {
public:
enum class Status {
Uninitialized = 0,
TaskAttached = 1,
TaskFinished = 2,
TaskRemoved = 3,
};
ManagedTaskHandle();
virtual ~ManagedTaskHandle();
void finalize();
Status getStatus() const { return mStatus; }
void removeTaskFromQueue();
bool hasTask() const;
bool wait();
bool wait(const sead::TickSpan& wait_duration);
bool isTaskAttached() const;
bool didTaskCompleteSuccessfully() const;
private:
friend class ManagedTask;
struct SetTaskArg {
ManagedTask* task;
TaskQueueBase* queue;
};
bool attachTask(const SetTaskArg& arg);
void setIsSuccess(bool success);
void setStatus(Status status);
void incrementRef_();
void decrementRef_();
bool mSuccess = false;
Status mStatus = Status::Uninitialized;
s32 mRefCount = 0;
ManagedTask* mTask = nullptr;
TaskQueueBase* mQueue = nullptr;
};
KSYS_CHECK_SIZE_NX150(ManagedTaskHandle, 0x28);
} // namespace ksys::util

View File

@ -0,0 +1,212 @@
#include "KingSystem/Utils/Thread/TaskMgr.h"
#include <heap/seadHeap.h>
#include <heap/seadHeapMgr.h>
#include "KingSystem/Utils/Thread/ManagedTask.h"
#include "KingSystem/Utils/Thread/TaskThread.h"
namespace ksys::util {
TaskMgr::TaskMgr(sead::Heap* heap)
: mTasksCS(heap), mCS2(heap), mNewFreeTaskEvent(heap, true), mEvent2(heap, true) {
mFreeTaskLists[0].initOffset(ManagedTask::getListNodeOffset());
mFreeTaskLists[1].initOffset(ManagedTask::getListNodeOffset());
mNewFreeTaskEvent.resetSignal();
}
TaskMgr::~TaskMgr() {
finalize();
}
void TaskMgr::finalize() {
if (mFlags.isOn(Flag::HeapIsFreeable)) {
if (mTask)
delete mTask;
mTask = nullptr;
for (auto*& task : mTasks) {
if (task)
delete task;
task = nullptr;
}
mTasks.freeBuffer();
} else {
if (mTask) {
mTask->~ManagedTask();
mTask = nullptr;
}
for (auto* task : mTasks)
task->~ManagedTask();
}
}
void TaskMgr::submitRequest(TaskMgrRequest& request) {
bool request_had_no_task = false;
if (!request.task) {
request_had_no_task = true;
fetchIdleTaskForRequest_(request, true);
}
if (!request.task)
return;
auto* task = request.task;
if (request.handle) {
auto* queue = request.request->mQueue;
if (!queue) {
auto* thread = request.request->mThread;
queue = thread ? thread->getTaskQueue() : nullptr;
}
task->attachHandle(request.handle, queue);
} else {
task->attachHandle(nullptr, nullptr);
}
const bool ok = task->submitRequest(*request.request);
if (!ok) {
if (auto* managed_task = sead::DynamicCast<ManagedTask>(request.task)) {
managed_task->attachHandle(nullptr, nullptr);
if (!request_had_no_task)
return;
freeTask(managed_task);
} else if (!request_had_no_task) {
return;
}
}
if (request_had_no_task || !ok)
request.task = nullptr;
}
// NON_MATCHING: reorderings
bool TaskMgr::fetchIdleTaskForRequest_(TaskMgrRequest& request, bool retry_until_success) {
if (!hasTasks())
return false;
ManagedTask* task = [this, retry_until_success] {
const auto lock1 = sead::makeScopedLock(mTasksCS);
if (auto* task = fetchIdleTask_(retry_until_success))
return task;
swapLists_();
if (!retry_until_success)
return fetchIdleTask_(retry_until_success);
while (true) {
if (auto* task_1 = fetchIdleTask_(retry_until_success))
return task_1;
mNewFreeTaskEvent.wait();
swapLists_();
}
}();
if (!task)
return false;
request.task = task;
return true;
}
void TaskMgr::freeTask(ManagedTask* task) {
auto lock = sead::makeScopedLock(mCS2);
mFreeTaskLists[getListIndex2_()].pushBack(task);
mNewFreeTaskEvent.setSignal();
}
bool TaskMgr::trySubmitRequest(TaskMgrRequest& request) {
bool request_had_no_task = false;
if (!request.task) {
request_had_no_task = true;
if (!tryFetchTaskForRequest_(request, false))
return false;
}
if (!request.task)
return false;
auto* task = request.task;
if (request.handle) {
auto* queue = request.request->mQueue;
if (!queue) {
auto* thread = request.request->mThread;
queue = thread ? thread->getTaskQueue() : nullptr;
}
task->attachHandle(request.handle, queue);
} else {
task->attachHandle(nullptr, nullptr);
}
const bool ok = task->submitRequest(*request.request);
if (!ok) {
if (auto* managed_task = sead::DynamicCast<ManagedTask>(request.task)) {
managed_task->attachHandle(nullptr, nullptr);
if (!request_had_no_task)
return ok;
freeTask(managed_task);
} else if (!request_had_no_task) {
return ok;
}
}
if (request_had_no_task || !ok)
request.task = nullptr;
return ok;
}
// NON_MATCHING: the factory invoke function pointer is loaded earlier in the original code
void TaskMgr::init(s32 num_tasks, sead::Heap* heap, ManagedTaskFactory& factory) {
if (!heap->isFreeable())
mFlags.reset(Flag::HeapIsFreeable);
else
mFlags.set(Flag::HeapIsFreeable);
const sead::ScopedCurrentHeapSetter heap_setter{heap};
mTasks.allocBufferAssert(num_tasks, heap);
if (mTasks.size() != 0) {
auto& list = mFreeTaskLists[mListIndex];
for (auto*& task : mTasks) {
factory(&task);
task->setMgr(this);
list.pushBack(task);
}
}
factory(&mTask);
}
bool TaskMgr::hasTasks() const {
return mTasks.size() > 0;
}
ManagedTask* TaskMgr::fetchIdleTask_(bool retry_until_success) {
auto lock = sead::makeScopedLock(mTasksCS);
if (mFreeTaskLists[mListIndex].isEmpty())
return nullptr;
ManagedTask* result = nullptr;
while (true) {
for (auto& task : mFreeTaskLists[mListIndex]) {
if (task.isIdle()) {
result = std::addressof(task);
break;
}
}
if (result) {
auto lock1 = sead::makeScopedLock(mTasksCS);
mFreeTaskLists[mListIndex].erase(result);
return result;
}
if (!retry_until_success)
return nullptr;
mEvent2.wait(sead::TickSpan::fromMilliSeconds(1));
}
}
} // namespace ksys::util

View File

@ -0,0 +1,88 @@
#pragma once
#include <container/seadBuffer.h>
#include <container/seadOffsetList.h>
#include <container/seadSafeArray.h>
#include <heap/seadDisposer.h>
#include <prim/seadDelegate.h>
#include <prim/seadRuntimeTypeInfo.h>
#include <prim/seadScopedLock.h>
#include <prim/seadTypedBitFlag.h>
#include <thread/seadCriticalSection.h>
#include "KingSystem/Utils/Thread/Event.h"
#include "KingSystem/Utils/Types.h"
namespace ksys::util {
class ManagedTask;
class ManagedTaskHandle;
class TaskRequest;
struct TaskMgrRequest;
using ManagedTaskFactory = sead::IDelegate1<ManagedTask**>;
struct TaskMgrRequest {
/// Optional. If null, a task from the internal buffer will be used.
ManagedTask* task;
/// Must not be null.
TaskRequest* request;
/// Optional.
ManagedTaskHandle* handle;
};
KSYS_CHECK_SIZE_NX150(TaskMgrRequest, 0x18);
class TaskMgr {
SEAD_RTTI_BASE(TaskMgr)
public:
explicit TaskMgr(sead::Heap* heap);
virtual ~TaskMgr();
void init(s32 num_tasks, sead::Heap* heap, ManagedTaskFactory& factory);
void finalize();
void submitRequest(TaskMgrRequest& request);
bool trySubmitRequest(TaskMgrRequest& request);
bool hasTasks() const;
void freeTask(ManagedTask* task);
protected:
enum class Flag {
HeapIsFreeable = 0x1,
};
bool fetchIdleTaskForRequest_(TaskMgrRequest& request, bool retry_until_success);
ManagedTask* fetchIdleTask_(bool retry_until_success);
u8 getListIndex_() const { return mListIndex; }
u8 getListIndex2_() const { return ~mListIndex & 1; }
void swapLists_() {
auto lock = sead::makeScopedLock(mCS2);
mListIndex = getListIndex2_();
mNewFreeTaskEvent.resetSignal();
}
bool tryFetchTaskForRequest_(TaskMgrRequest& request, bool b) {
if (!mTasksCS.tryLock())
return false;
const bool ret = fetchIdleTaskForRequest_(request, b);
mTasksCS.unlock();
return ret;
}
sead::TypedBitFlag<Flag, u8> mFlags;
u8 mListIndex = 0;
ManagedTask* mTask = nullptr;
sead::CriticalSection mTasksCS;
sead::CriticalSection mCS2;
Event mNewFreeTaskEvent;
Event mEvent2;
sead::SafeArray<sead::OffsetList<ManagedTask>, 2> mFreeTaskLists;
sead::Buffer<ManagedTask*> mTasks;
};
KSYS_CHECK_SIZE_NX150(TaskMgr, 0x158);
} // namespace ksys::util