diff --git a/CMakeLists.txt b/CMakeLists.txt index 47de3964..e71f5303 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 716d3c00..1a999ca1 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -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, diff --git a/src/KingSystem/Utils/Thread/GameTaskThread.cpp b/src/KingSystem/Utils/Thread/GameTaskThread.cpp new file mode 100644 index 00000000..eacd9e64 --- /dev/null +++ b/src/KingSystem/Utils/Thread/GameTaskThread.cpp @@ -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 diff --git a/src/KingSystem/Utils/Thread/GameTaskThread.h b/src/KingSystem/Utils/Thread/GameTaskThread.h new file mode 100644 index 00000000..a16e9f68 --- /dev/null +++ b/src/KingSystem/Utils/Thread/GameTaskThread.h @@ -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 diff --git a/src/KingSystem/Utils/Thread/ManagedTask.cpp b/src/KingSystem/Utils/Thread/ManagedTask.cpp new file mode 100644 index 00000000..8a0f3dfd --- /dev/null +++ b/src/KingSystem/Utils/Thread/ManagedTask.cpp @@ -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 diff --git a/src/KingSystem/Utils/Thread/ManagedTask.h b/src/KingSystem/Utils/Thread/ManagedTask.h new file mode 100644 index 00000000..67b8ef04 --- /dev/null +++ b/src/KingSystem/Utils/Thread/ManagedTask.h @@ -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 diff --git a/src/KingSystem/Utils/Thread/ManagedTaskHandle.cpp b/src/KingSystem/Utils/Thread/ManagedTaskHandle.cpp new file mode 100644 index 00000000..874bf46f --- /dev/null +++ b/src/KingSystem/Utils/Thread/ManagedTaskHandle.cpp @@ -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 diff --git a/src/KingSystem/Utils/Thread/ManagedTaskHandle.h b/src/KingSystem/Utils/Thread/ManagedTaskHandle.h new file mode 100644 index 00000000..61c41c51 --- /dev/null +++ b/src/KingSystem/Utils/Thread/ManagedTaskHandle.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include