From 4f2c0a60798d07bc77121e4ef02fbf17075c52da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 14 Mar 2021 14:05:38 +0100 Subject: [PATCH] ksys/act: Finish BaseProcHandle --- data/uking_functions.csv | 26 +-- .../ActorSystem/actActorLinkConstDataAccess.h | 1 + src/KingSystem/ActorSystem/actBaseProc.h | 6 +- .../ActorSystem/actBaseProcHandle.cpp | 154 ++++++++++++++++-- .../ActorSystem/actBaseProcHandle.h | 23 ++- .../ActorSystem/actBaseProcInitializer.cpp | 6 +- .../ActorSystem/actBaseProcUnit.cpp | 30 +++- src/KingSystem/ActorSystem/actBaseProcUnit.h | 52 ++++-- 8 files changed, 242 insertions(+), 56 deletions(-) diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 80ef2ff4..4ed8c3ff 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -91736,24 +91736,24 @@ 0x00000071011bb828,sub_71011BB828,92,_ZNK4sead10Delegate1RIN4ksys3act8BaseProcEPvbE5cloneEPNS_4HeapE 0x00000071011bb884,sub_71011BB884,32,_GLOBAL__sub_I_actBaseProcHandle.cpp 0x00000071011bb8a4,BaseProcHandle::ctor,12,_ZN4ksys3act14BaseProcHandleC1Ev -0x00000071011bb8b0,BaseProcHandle::actorReady,32,_ZN4ksys3act14BaseProcHandle9procReadyEv -0x00000071011bb8d0,BaseProcHandle::hasActorAndFlags5,84, -0x00000071011bb924,BaseProcHandle::x,52, -0x00000071011bb958,BaseProcHandle::deleteActor,112, -0x00000071011bb9c8,BaseProcHandle::dtor,56,_ZN4ksys3act14BaseProcHandleD1Ev +0x00000071011bb8b0,BaseProcHandle::actorReady,32,_ZNK4ksys3act14BaseProcHandle11isProcReadyEv +0x00000071011bb8d0,BaseProcHandle::hasActorAndFlags5,84,_ZNK4ksys3act14BaseProcHandle21hasProcCreationFailedEv +0x00000071011bb924,BaseProcHandle::x,52,_ZNK4ksys3act14BaseProcHandle23isProcCreationCancelledEv +0x00000071011bb958,BaseProcHandle::deleteActor,112,_ZN4ksys3act14BaseProcHandle18deleteProcIfFailedEv +0x00000071011bb9c8,BaseProcHandle::dtor,56,_ZN4ksys3act14BaseProcHandle10deleteProcEv 0x00000071011bba00,BaseProcUnit::deleteActor,316,_ZN4ksys3act12BaseProcUnit10deleteProcEjPNS0_14BaseProcHandleE -0x00000071011bbb3c,BaseProcHandle::getActor,24,_ZN4ksys3act14BaseProcHandle7getProcEv -0x00000071011bbb54,BaseProcHandle::setProcStateFlag8000,184, -0x00000071011bbc0c,BaseProcHandle::wakeUpActorAndReleaseUnit,184, -0x00000071011bbcc4,BaseProcHandle::getBaseProcEvent,48, -0x00000071011bbcf4,BaseProcHandle::allocUnit,228, +0x00000071011bbb3c,BaseProcHandle::getActor,24,_ZNK4ksys3act14BaseProcHandle7getProcEv +0x00000071011bbb54,BaseProcHandle::setProcStateFlag8000,184,_ZN4ksys3act14BaseProcHandle11releaseProcEv +0x00000071011bbc0c,BaseProcHandle::wakeUpActorAndReleaseUnit,184,_ZN4ksys3act14BaseProcHandle18releaseAndWakeProcEv +0x00000071011bbcc4,BaseProcHandle::getBaseProcEvent,48,_ZNK4ksys3act14BaseProcHandle13getCreateTaskEv +0x00000071011bbcf4,BaseProcHandle::allocUnit,228,_ZN4ksys3act14BaseProcHandle9allocUnitEv 0x00000071011bbdd8,BaseProcUnit::setActor,540,_ZN4ksys3act12BaseProcUnit7setProcEPNS0_8BaseProcE 0x00000071011bbff4,BaseProcUnit::cleanUp,512,_ZN4ksys3act12BaseProcUnit7cleanUpEPNS0_8BaseProcEb 0x00000071011bc1f4,BaseProcUnit::unlinkActor,412,_ZN4ksys3act12BaseProcUnit10unlinkProcEPNS0_8BaseProcE 0x00000071011bc390,BaseProcUnit::isParentHandleDefault,24,_ZNK4ksys3act12BaseProcUnit21isParentHandleDefaultEv -0x00000071011bc3a8,sub_71011BC3A8,132, -0x00000071011bc42c,sub_71011BC42C,56, -0x00000071011bc464,sinitBaseProcHandle,172, +0x00000071011bc3a8,sub_71011BC3A8,132,_ZN4ksys3act16BaseProcUnitPoolD2Ev +0x00000071011bc42c,sub_71011BC42C,56,_ZN4ksys3act14BaseProcHandleD1Ev +0x00000071011bc464,sinitBaseProcHandle,172,_GLOBAL__sub_I_actBaseProcUnit.cpp? 0x00000071011bc510,_ZN12BaseProcLinkC2Ev,20,_ZN4ksys3act12BaseProcLinkC1Ev 0x00000071011bc524,_ZN12BaseProcLink12acquireActorER13ActorAccessorP9ActorBase,308,_ZNK4ksys3act12BaseProcLink7getProcEPNS0_24ActorLinkConstDataAccessEPNS0_8BaseProcE 0x00000071011bc658,BaseProcLinkData::lockCritSectionOnGameThreadOrHavokThread,68,_ZN4ksys3act16BaseProcLinkData12lockIfNeededEv diff --git a/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.h b/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.h index c608f9ba..18d2a4b4 100644 --- a/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.h +++ b/src/KingSystem/ActorSystem/actActorLinkConstDataAccess.h @@ -39,6 +39,7 @@ public: protected: friend class ActorConstDataAccess; friend class BaseProc; + friend class BaseProcHandle; friend class BaseProcUnit; bool mAcquired = false; diff --git a/src/KingSystem/ActorSystem/actBaseProc.h b/src/KingSystem/ActorSystem/actBaseProc.h index 9df6427b..c2712ed7 100644 --- a/src/KingSystem/ActorSystem/actBaseProc.h +++ b/src/KingSystem/ActorSystem/actBaseProc.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -122,7 +123,6 @@ public: void setCreatePriorityState1(); void setCreatePriorityState2(); - bool setStateFlag(u32 flag_bit); void onJobPush(JobType type) { onJobPush1_(type); @@ -135,6 +135,7 @@ public: /// Set the BaseProcUnit. Only for use by BaseProcCreateTask. void setUnitForBaseProcCreateTask(BaseProcUnit* unit) { mProcUnit = unit; } void setInitializedFlag() { mFlags.set(Flags::Initialized); } + bool requestDeleteProcUnit() { return setStateFlag(StateFlags::RequestDeleteProcUnit); } protected: friend class BaseProcLinkDataMgr; @@ -279,6 +280,9 @@ protected: BaseProcJobHandler*& getJobHandler(JobType type) { return mJobHandlers[int(type)]; } BaseProcJobHandler* getJobHandler(JobType type) const { return mJobHandlers[int(type)]; } + bool setStateFlag(u32 flag_bit); + bool setStateFlag(StateFlags flag) { return setStateFlag(sead::log2(u32(flag))); } + bool x00000071011ba9fc(); sead::FixedSafeString<64> mName; diff --git a/src/KingSystem/ActorSystem/actBaseProcHandle.cpp b/src/KingSystem/ActorSystem/actBaseProcHandle.cpp index 35a1b13d..95cfa803 100644 --- a/src/KingSystem/ActorSystem/actBaseProcHandle.cpp +++ b/src/KingSystem/ActorSystem/actBaseProcHandle.cpp @@ -1,4 +1,7 @@ #include "KingSystem/ActorSystem/actBaseProcHandle.h" +#include +#include "KingSystem/ActorSystem/actActorLinkConstDataAccess.h" +#include "KingSystem/ActorSystem/actBaseProc.h" #include "KingSystem/ActorSystem/actBaseProcUnit.h" #include "KingSystem/Utils/InitTimeInfo.h" @@ -6,28 +9,159 @@ namespace ksys::act { static util::InitTimeInfo sInfo; -BaseProcHandle::BaseProcHandle() { - mUnit = nullptr; - mFlag = 0; -} +BaseProcHandle::BaseProcHandle() = default; BaseProcHandle::~BaseProcHandle() { + deleteProc(); +} + +bool BaseProcHandle::isProcReady() const { + return mUnit && mUnit->isReady(); +} + +bool BaseProcHandle::hasProcCreationFailed() const { + if (mFailed) + return true; + + if (!mUnit) + return false; + + const auto status = mUnit->getStatus(); + if (status == BaseProcUnit::Status::NoProc || status == BaseProcUnit::Status::Cancelled) + return true; + + if (mUnit->getCreateTask().getStatus() == util::Task::Status::RemovedFromQueue || + status == BaseProcUnit::Status::Cancelled) { + return true; + } + + return false; +} + +bool BaseProcHandle::isProcCreationCancelled() const { + if (!mUnit) + return false; + + if (mUnit->getCreateTask().getStatus() == util::Task::Status::RemovedFromQueue) + return true; + + if (mUnit->getStatus() == BaseProcUnit::Status::Cancelled) + return true; + + return false; +} + +void BaseProcHandle::deleteProcIfFailed() { + if (mFailed && !mUnit) { + mFailed = false; + return; + } + + if (hasProcCreationFailed()) + deleteProc(); +} + +void BaseProcHandle::deleteProc() { if (mUnit) { mUnit->deleteProc(0, this); mUnit = nullptr; } - mFlag = 0; + mFailed = false; } -bool BaseProcHandle::procReady() { - return mUnit && mUnit->isReady(); -} - -BaseProc* BaseProcHandle::getProc() { +BaseProc* BaseProcHandle::getProc() const { if (mUnit) return mUnit->getProc(); return nullptr; } +BaseProc* BaseProcHandle::releaseProc() { + if (!isProcReady()) + return nullptr; + + BaseProcUnit* unit = mUnit; + BaseProc* proc = nullptr; + + { + ActorLinkConstDataAccess accessor; + { + const auto lock = sead::makeScopedLock(unit->getCS()); + if (unit->compareExchangeHandle(this, &gDummyProcHandle)) { + if (unit->getProc()) + accessor.acquire(unit->getProc()); + } + } + + proc = accessor.mProc; + if (proc) + proc->requestDeleteProcUnit(); + } + + mUnit = nullptr; + return proc; +} + +BaseProc* BaseProcHandle::releaseAndWakeProc() { + if (!isProcReady()) + return nullptr; + + BaseProcUnit* unit = mUnit; + BaseProc* proc = nullptr; + + { + ActorLinkConstDataAccess accessor; + { + const auto lock = sead::makeScopedLock(unit->getCS()); + if (unit->compareExchangeHandle(this, &gDummyProcHandle)) { + if (unit->getProc()) + accessor.acquire(unit->getProc()); + } + } + + proc = accessor.mProc; + if (proc) + proc->wakeUp(BaseProc::SleepWakeReason::_0); + } + + mUnit = nullptr; + return proc; +} + +BaseProcCreateTask* BaseProcHandle::getCreateTask() const { + sead::Atomic unit = mUnit; + auto* ret = unit ? &unit->getCreateTask() : nullptr; + static_cast(unit.load()); + return ret; +} + +bool BaseProcHandle::allocUnit() { + if (mUnit) + return false; + + int idx = gUnitPool.idx; + for (int i = 0; i < gUnitPool.units.size(); ++idx, ++i) { + idx = (idx == gUnitPool.units.size()) ? 0 : idx; + auto* unit = gUnitPool.get(idx); + + if (!unit->getCreateTask().canSubmitRequest()) + continue; + if (unit->getProc() != nullptr) + continue; + if (!unit->compareExchangeHandle(nullptr, this)) + continue; + + gUnitPool.idx = idx + 1; + mUnit = unit; + if (!mUnit) + return false; + + mUnit->setInitializingStatus(); + return true; + } + + mUnit = nullptr; + return false; +} + } // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actBaseProcHandle.h b/src/KingSystem/ActorSystem/actBaseProcHandle.h index a9815995..7a28f949 100644 --- a/src/KingSystem/ActorSystem/actBaseProcHandle.h +++ b/src/KingSystem/ActorSystem/actBaseProcHandle.h @@ -14,21 +14,26 @@ public: BaseProcHandle(); ~BaseProcHandle(); - bool procReady(); + bool isProcReady() const; + bool hasProcCreationFailed() const; + bool isProcCreationCancelled() const; - BaseProc* getProc(); + void deleteProcIfFailed(); + void deleteProc(); + + BaseProc* getProc() const; + BaseProc* releaseProc(); + BaseProc* releaseAndWakeProc(); + BaseProcCreateTask* getCreateTask() const; BaseProcUnit* getUnit() const { return mUnit; } bool allocUnit(); - BaseProcCreateTask* getCreateTask() const; - bool getFlag() const { return mFlag; } - void setFlag(bool flag) { mFlag = flag; } - - static BaseProcHandle sDummyHandle; + bool hasFailed() const { return mFailed; } + void setFailed(bool failed) { mFailed = failed; } private: - BaseProcUnit* mUnit; - bool mFlag; + BaseProcUnit* mUnit = nullptr; + bool mFailed = false; }; KSYS_CHECK_SIZE_NX150(BaseProcHandle, 0x10); diff --git a/src/KingSystem/ActorSystem/actBaseProcInitializer.cpp b/src/KingSystem/ActorSystem/actBaseProcInitializer.cpp index da1c33f1..2785fd5b 100644 --- a/src/KingSystem/ActorSystem/actBaseProcInitializer.cpp +++ b/src/KingSystem/ActorSystem/actBaseProcInitializer.cpp @@ -89,7 +89,7 @@ void BaseProcInitializer::deleteThreadIfPaused() { bool BaseProcInitializer::requestCreateBaseProc(const BaseProcCreateRequest& req) { if (!mActorGenerationEnabled) { if (req.task_data->mProcHandle) - req.task_data->mProcHandle->setFlag(true); + req.task_data->mProcHandle->setFailed(true); return false; } @@ -112,13 +112,13 @@ bool BaseProcInitializer::requestCreateBaseProc(const BaseProcCreateRequest& req util::TaskMgrRequest mgr_req; if (req.task_data->mProcHandle) { if (!req.task_data->mProcHandle->allocUnit()) { - req.task_data->mProcHandle->setFlag(true); + req.task_data->mProcHandle->setFailed(true); return false; } mgr_req.task = req.task_data->mProcHandle->getCreateTask(); if (!mgr_req.task) { - req.task_data->mProcHandle->setFlag(true); + req.task_data->mProcHandle->setFailed(true); return false; } } else { diff --git a/src/KingSystem/ActorSystem/actBaseProcUnit.cpp b/src/KingSystem/ActorSystem/actBaseProcUnit.cpp index cac5c864..23baa4ea 100644 --- a/src/KingSystem/ActorSystem/actBaseProcUnit.cpp +++ b/src/KingSystem/ActorSystem/actBaseProcUnit.cpp @@ -8,7 +8,19 @@ namespace ksys::act { -bool BaseProcUnit::deleteProc(u32, BaseProcHandle* handle) { +BaseProcUnitPool gUnitPool{}; +BaseProcHandle gDummyProcHandle; + +BaseProcUnit::~BaseProcUnit() { + deleteProc(0, nullptr); +} + +bool BaseProcUnit::deleteProc([[maybe_unused]] u32 x, BaseProcHandle* handle) { +#ifdef MATCHING_HACK_NX_CLANG + // Ensure x is not optimized out. + __builtin_assume(x); +#endif + ActorLinkConstDataAccess accessor; { @@ -18,8 +30,8 @@ bool BaseProcUnit::deleteProc(u32, BaseProcHandle* handle) { if (mProc) accessor.acquire(mProc); - if (mStatus == Status::_1 || mProc) { - mHandle.compareExchange(handle, &BaseProcHandle::sDummyHandle); + if (mStatus == Status::Initializing || mProc) { + mHandle.compareExchange(handle, &gDummyProcHandle); } else { mStatus = Status::Unused; mHandle = nullptr; @@ -65,7 +77,7 @@ bool BaseProcUnit::setProc(BaseProc* proc) { return false; } - if (mStatus != Status::_1) + if (mStatus != Status::Initializing) print_info(); mProc = proc; @@ -75,7 +87,7 @@ bool BaseProcUnit::setProc(BaseProc* proc) { void BaseProcUnit::reset() { auto* handle = getHandle(); - if (handle != &BaseProcHandle::sDummyHandle) { + if (handle != &gDummyProcHandle) { sead::FixedSafeString<256> message; message.format("BaseProcUnit:%p, %p", this, handle); util::PrintDebug(message); @@ -85,7 +97,7 @@ void BaseProcUnit::reset() { mHandle = nullptr; } -void BaseProcUnit::cleanUp(BaseProc* proc, bool set_status_5) { +void BaseProcUnit::cleanUp(BaseProc* proc, bool is_cancellation) { const auto lock = sead::makeScopedLock(mCS); mProc = nullptr; @@ -102,9 +114,9 @@ void BaseProcUnit::cleanUp(BaseProc* proc, bool set_status_5) { print_info(); } else { const auto status = mStatus.load(); - if (status == Status::Unused || (status > Status::_3 && status != Status::_5)) + if (status == Status::Unused || (status > Status::NoProc && status != Status::Cancelled)) print_info(); - mStatus = set_status_5 ? Status::_5 : Status::_3; + mStatus = is_cancellation ? Status::Cancelled : Status::NoProc; } } @@ -123,7 +135,7 @@ void BaseProcUnit::unlinkProc(BaseProc* proc) { } bool BaseProcUnit::isParentHandleDefault() const { - return mHandle == &BaseProcHandle::sDummyHandle; + return mHandle == &gDummyProcHandle; } } // namespace ksys::act diff --git a/src/KingSystem/ActorSystem/actBaseProcUnit.h b/src/KingSystem/ActorSystem/actBaseProcUnit.h index 20309485..07ccbabb 100644 --- a/src/KingSystem/ActorSystem/actBaseProcUnit.h +++ b/src/KingSystem/ActorSystem/actBaseProcUnit.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include "KingSystem/ActorSystem/actBaseProcCreateTask.h" @@ -12,25 +13,44 @@ class BaseProcHandle; class BaseProcUnit { public: + enum class Status : u32 { + Unused = 0, + Initializing = 1, + Ready = 2, + NoProc = 3, + _4 = 4, + Cancelled = 5, + }; + + BaseProcUnit() = default; + ~BaseProcUnit(); + + BaseProcUnit(const BaseProcUnit&) = delete; + BaseProcUnit(BaseProcUnit&&) = delete; + auto operator=(const BaseProcUnit&) = delete; + auto operator=(BaseProcUnit&&) = delete; + bool deleteProc(u32, BaseProcHandle* handle); bool setProc(BaseProc* proc); void unlinkProc(BaseProc* proc); - void cleanUp(BaseProc* proc, bool set_status_5); + void cleanUp(BaseProc* proc, bool is_cancellation); bool isParentHandleDefault() const; + Status getStatus() const { return mStatus; } BaseProc* getProc() const { return mProc; } + BaseProcCreateTask& getCreateTask() { return mCreateTask; } + const BaseProcCreateTask& getCreateTask() const { return mCreateTask; } + sead::CriticalSection& getCS() { return mCS; } + bool isReady() const { return mStatus == Status::Ready; } -private: - enum class Status : u32 { - Unused = 0, - _1 = 1, - Ready = 2, - _3 = 3, - _4 = 4, - _5 = 5, - }; + bool compareExchangeHandle(BaseProcHandle* expected, BaseProcHandle* desired) { + return mHandle.compareExchange(expected, desired); + } + void setInitializingStatus() { mStatus = Status::Initializing; } + +private: void reset(); BaseProcHandle* getHandle() const { return mHandle.load(); } @@ -38,9 +58,19 @@ private: sead::Atomic mStatus = Status::Unused; sead::Atomic mHandle{}; BaseProc* mProc{}; - BaseProcCreateTask mCreateTask; + BaseProcCreateTask mCreateTask{nullptr}; sead::CriticalSection mCS; }; KSYS_CHECK_SIZE_NX150(BaseProcUnit, 0x2f0); +struct BaseProcUnitPool { + BaseProcUnit* get(int i) { return &units[i]; } + + sead::SafeArray units; + int idx = 0; +}; + +extern BaseProcUnitPool gUnitPool; +extern BaseProcHandle gDummyProcHandle; + } // namespace ksys::act