ksys/act: Add more BaseProcMgr functions

This commit is contained in:
Léo Lam
2021-03-16 11:42:49 +01:00
parent 7fc889714e
commit 298fa86491
11 changed files with 371 additions and 74 deletions
+1 -1
View File
@@ -229,7 +229,7 @@ bool BaseProc::canWakeUp_() {
return true;
}
void BaseProc::queueExtraJobPush_(JobType type) {
void BaseProc::queueExtraJobPush_(JobType type, int idx) {
if (!isDeletedOrDeleting())
BaseProcMgr::instance()->queueExtraJobPush(&getJobHandler(type)->getLink());
}
+6 -2
View File
@@ -98,11 +98,11 @@ public:
bool isInit() const { return mState == State::Init; }
bool isCalc() const { return mState == State::Calc; }
bool isSleep() const { return mState == State::Sleep; }
bool isDelete() const { return mState == State::Delete; }
bool isDeletedOrDeleting() const {
return mState == State::Delete || mStateFlags.isOn(StateFlags::RequestDelete);
}
bool isInitialized() const { return mFlags.isOn(Flags::Initialized); }
/// For BaseProcLink or ActorLinkConstDataAccess.
bool acquire(ActorLinkConstDataAccess& accessor);
BaseProcLinkData* getBaseProcLinkData() const { return mBaseProcLinkData; }
@@ -138,6 +138,10 @@ public:
void setInitializedFlag() { mFlags.set(Flags::Initialized); }
bool requestDeleteProcUnit() { return setStateFlag(StateFlags::RequestDeleteProcUnit); }
bool isInitialized() const { return mFlags.isOn(Flags::Initialized); }
bool isDeleting() const { return mFlags.isOn(Flags::PreDeleteStarted); }
bool isDeleteRequested() const { return mStateFlags.isOn(StateFlags::RequestDelete); }
protected:
friend class BaseProcLinkDataMgr;
friend class BaseProcMgr;
@@ -256,7 +260,7 @@ protected:
virtual IsSpecialJobTypeResult isSpecialJobType_(JobType type);
virtual bool canWakeUp_();
virtual void queueExtraJobPush_(JobType type);
virtual void queueExtraJobPush_(JobType type, int idx);
virtual bool hasJobType_(JobType type);
/// Called after processStateUpdate() is called for all actors in the update state list.
virtual void afterUpdateState_();
@@ -22,7 +22,7 @@ class BaseProc;
struct BaseProcCreateRequest;
struct BaseProcInitializerArgs {
u32 queue_size = 1024;
u32 queue_size;
sead::SafeString thread_name = "BaseProcCreate";
util::TaskSelectionDelegate* task_selector = nullptr;
};
+240 -2
View File
@@ -339,7 +339,8 @@ void BaseProcMgr::unlockProcMap() {
}
void BaseProcMgr::deleteAllProcs() {
auto procs = getProcs(ProcFilter::_1 | ProcFilter::_4 | ProcFilter::_8);
auto procs =
getProcs(ProcFilter::Sleeping | ProcFilter::Initializing | ProcFilter::SkipAccessCheck);
while (auto* proc = procs.next()) {
if (!proc->mFlags.isOn(BaseProc::Flags::DoNotDelete))
proc->deleteLater(BaseProc::DeleteReason::BaseProcMgrDeleteAll);
@@ -347,7 +348,8 @@ void BaseProcMgr::deleteAllProcs() {
}
bool BaseProcMgr::hasFinishedDeletingAllProcs() {
auto procs = getProcs(ProcFilter::_1 | ProcFilter::_2 | ProcFilter::_4 | ProcFilter::_8);
auto procs = getProcs(ProcFilter::Sleeping | ProcFilter::DeletedOrDeleting |
ProcFilter::Initializing | ProcFilter::SkipAccessCheck);
while (auto* proc = procs.next()) {
if (!proc->mFlags.isOn(BaseProc::Flags::DoNotDelete))
return false;
@@ -369,6 +371,227 @@ bool BaseProcMgr::isHighPriorityThread() const {
return id == mMainThreadId || id == mHavokThreadId1 || id == mHavokThreadId2;
}
bool BaseProcMgr::isAccessingProcSafe(BaseProc* proc, BaseProc* other) const {
[[maybe_unused]] const auto current_thread = sead::ThreadMgr::instance()->getCurrentThread();
if (!isHighPriorityThread())
return true;
if (mUnk2)
return true;
if (other) {
if (other == proc)
return true;
if (other->getConnectedCalcChild() == proc)
return true;
if (other->getConnectedCalcParent() == proc)
return true;
}
if (!mIsPushingJobs)
return true;
const auto type = mJobType;
if (type == JobType::Invalid || mStatus != Status::ProcessingActorJobs) {
#ifdef MATCHING_HACK_NX_CLANG
if (proc->isInit()) {
fail:
return false;
}
return true;
#else
return !proc->isInit();
#endif
}
if (auto* handler = proc->getJobHandler(type)) {
u8 priority = handler->getLink().getPriority();
while ((proc = proc->getConnectedCalcParent())) {
if (auto* h = proc->getJobHandler(type))
priority = h->getLink().getPriority();
}
if (mCurrentlyProcessingPrio != priority)
return true;
} else if (!proc->isInit()) {
return true;
}
#ifdef MATCHING_HACK_NX_CLANG
goto fail;
#else
return false;
#endif
}
bool BaseProcMgr::requestCreateProc(const BaseProcCreateRequest& req) {
return mProcInitializer->requestCreateBaseProc(req);
}
BaseProc* BaseProcMgr::createProc(const BaseProcCreateRequest& req) {
return mProcInitializer->createBaseProc(req);
}
struct ProcForEachContextData {
inline void handle(BaseProcMapNode* node) const {
if (BaseProcMgr::instance()->checkFilters(node->proc(), filters))
callback->invoke(node->proc());
}
BaseProcMgr::ProcFilters filters;
sead::IDelegate1<BaseProc*>* callback{};
};
struct ProcForEachContext {
void forEach(util::StrTreeMapNode* node) { // NOLINT(readability-make-member-function-const)
for (auto it = static_cast<BaseProcMapNode*>(node); it; it = it->next())
data->handle(it);
}
ProcForEachContextData* data;
};
inline bool BaseProcMgr::checkFilters(BaseProc* proc, ProcFilters filters) const {
if (proc->isDeleting() && filters.isOff(ProcFilter::Deleting))
return false;
if (!proc->isInitialized() && filters.isOff(ProcFilter::Uninitialized))
return false;
if (proc->isSleep() && filters.isOff(ProcFilter::Sleeping))
return false;
if (proc->isDeletedOrDeleting() && filters.isOff(ProcFilter::DeletedOrDeleting))
return false;
if (proc->isInit() && filters.isOff(ProcFilter::Initializing))
return false;
return !filters.isOff(ProcFilter::SkipAccessCheck) || isAccessingProcSafe(proc, nullptr);
}
BaseProc* BaseProcMgr::getProc(const sead::SafeString& name, BaseProcMgr::ProcFilters filters) {
const auto lock = sead::makeScopedLock(mProcMapCS);
if (auto* node = mProcMap.find(name)) {
auto* proc = node->proc();
if (checkFilters(proc, filters))
return proc;
}
return nullptr;
}
BaseProc* BaseProcMgr::getProc(const u32& id, BaseProcMgr::ProcFilters filters) {
auto* cs = lockProcMap();
auto guard = sead::makeScopeGuard([this] { unlockProcMap(); });
BaseProc* proc = nullptr;
do {
proc = getNextProc(cs, proc, filters);
if (proc && proc->getId() == id) {
if (!checkFilters(proc, filters))
proc = nullptr;
break;
}
} while (proc);
return proc;
}
// NON_MATCHING: stack
void BaseProcMgr::forEachProc(sead::IDelegate1<BaseProc*>& callback, ProcFilters filters) {
const auto lock = sead::makeScopedLock(mProcMapCS);
ProcForEachContextData data;
ProcForEachContext context;
context.data = &data;
data.filters = filters;
data.callback = &callback;
mProcMap.forEach(sead::Delegate1<ProcForEachContext, util::StrTreeMapNode*>(
&context, &ProcForEachContext::forEach));
}
void BaseProcMgr::forEachProc(const sead::SafeString& proc_name,
sead::IDelegate1<BaseProc*>& callback,
BaseProcMgr::ProcFilters filters) {
const auto lock = sead::makeScopedLock(mProcMapCS);
BaseProc* proc = nullptr;
if (auto* node = mProcMap.find(proc_name))
proc = node->proc();
while (proc) {
if (checkFilters(proc, filters))
callback.invoke(proc);
auto* next = proc->mMapNode.next();
proc = next ? next->proc() : nullptr;
}
}
bool BaseProcMgr::areInitializerThreadsIdle() const {
return !mProcInitializer->isAnyThreadActive();
}
void BaseProcMgr::waitForInitializerQueueToEmpty() {
mProcInitializer->waitForTaskQueuesToEmpty();
}
void BaseProcMgr::cancelInitializerTasks() {
mProcInitializer->cancelTasks();
}
void BaseProcMgr::blockInitializerTasks() {
mProcInitializer->blockPendingTasks();
}
void BaseProcMgr::restartInitializerThreads() {
blockInitializerTasks();
mProcInitializer->restartThreads();
}
void BaseProcMgr::pauseInitializerThreads() {
mProcInitializer->pauseThreads();
}
void BaseProcMgr::resumeInitializerThreads() {
mProcInitializer->resumeThreads();
}
void BaseProcMgr::unblockInitDeleteTasks() {
mProcDeleter->unblockTasks();
mProcInitializer->unblockPendingTasks();
}
void BaseProcMgr::pauseInitializerMainThread() {
mProcInitializer->pauseMainThread();
}
void BaseProcMgr::resumeInitializerMainThread() {
mProcInitializer->resumeMainThread();
}
bool BaseProcMgr::isAnyInitializerThreadActive() const {
return mProcInitializer->isAnyThreadActive();
}
int BaseProcMgr::getInitializerQueueSize() const {
return mProcInitializer->getQueueSize();
}
int BaseProcMgr::getInitializerQueueSizeEx(int x) const {
return mProcInitializer->getQueueSize(x);
}
void BaseProcMgr::removeInitializerTasksIf(sead::IDelegate1R<util::Task*, bool>& predicate) {
mProcInitializer->removeTasksIf(predicate);
}
void BaseProcMgr::setActorGenerationEnabled(bool enabled) {
mProcInitializer->setActorGenerationEnabled(enabled);
}
void BaseProcMgr::incrementUnk3() {
if (mUnk3 != 0xFF)
++mUnk3;
@@ -379,6 +602,21 @@ void BaseProcMgr::decrementUnk3() {
--mUnk3;
}
// NON_MATCHING: reorderings
void BaseProcMgr::queueExtraJobPush(BaseProcJobLink* job_link) {
getExtraJobs().pushBack(job_link);
}
// NON_MATCHING: ???
void BaseProcMgr::moveExtraJobsToOtherBuffer(JobType type) {
const auto old_idx = mCurrentExtraJobArrayIdx;
swapExtraJobArray();
auto& array = mExtraJobLinkArrays.ref()[old_idx];
for (auto& link : array) {
link.getProc()->queueExtraJobPush_(type, mCurrentExtraJobArrayIdx);
}
}
bool BaseProcMgr::hasExtraJobLink(BaseProcJobLink* job_link, s32 idx) {
for (auto& ptr : mExtraJobLinkArrays.ref()[idx]) {
if (&ptr == job_link)
+44 -37
View File
@@ -59,13 +59,13 @@ public:
};
enum class ProcFilter {
_1 = 1 << 0,
_2 = 1 << 1,
_4 = 1 << 2,
_8 = 1 << 3,
Sleeping = 1 << 0,
DeletedOrDeleting = 1 << 1,
Initializing = 1 << 2,
SkipAccessCheck = 1 << 3,
_10 = 1 << 4,
_20 = 1 << 5,
_40 = 1 << 6,
Deleting = 1 << 5,
Uninitialized = 1 << 6,
};
using ProcFilters = sead::TypedBitFlag<ProcFilter>;
@@ -86,7 +86,6 @@ public:
BaseProc* mProc{};
};
static void createInstanceAndInit(sead::Heap* heap);
static u32 getConstant0() { return sConstant0; }
static u32 getConstant1() { return sConstant1; }
static u32 getConstant2() { return sConstant2; }
@@ -112,10 +111,6 @@ public:
void eraseFromUpdateStateList(BaseProc& proc);
void processPreDeleteList();
void forEachProc(const sead::IDelegate1<BaseProc*>& callback, u32 flags);
void deleteAllProcs();
bool hasFinishedDeletingAllProcs();
// endregion
bool requestPreDelete(BaseProc& proc);
@@ -133,7 +128,7 @@ public:
void swapExtraJobArray();
void queueExtraJobPush(BaseProcJobLink* job_link);
void moveExtraJobsToOtherBuffer();
void moveExtraJobsToOtherBuffer(JobType type);
bool hasExtraJobLink(BaseProcJobLink* job_link, s32 idx);
void clearExtraJobArrays();
@@ -145,8 +140,12 @@ public:
void setJobType(JobType type);
void setActorJobTypeAndPrio(JobType type, s32 prio, bool);
void goIdle();
void clearMode();
void calc();
void clearMode();
sead::CriticalSection* lockProcMap();
void unlockProcMap();
void deleteAllProcs();
bool hasFinishedDeletingAllProcs();
void jobInvoked(BaseProcJobLink* link, s32 required_calc_rounds);
// endregion
@@ -162,7 +161,7 @@ public:
/// Returns true if and only if the calling thread is the game thread or a Havok thread.
bool isHighPriorityThread() const;
/// Returns true if and only if it is safe to access the specified BaseProc.
bool isAccessingProcSafe(BaseProc* proc, BaseProc* other);
bool isAccessingProcSafe(BaseProc* proc, BaseProc* other) const;
// region BaseProc creation
@@ -171,17 +170,35 @@ public:
// endregion
// region BaseProc iteration
BaseProc* getNextProc(sead::CriticalSection* cs, BaseProc* proc, ProcFilters filters);
BaseProc* getProc(const sead::SafeString& name, ProcFilters filters);
BaseProc* getProc(const u32& id, ProcFilters filters);
void forEachProc(sead::IDelegate1<BaseProc*>& callback, ProcFilters filters);
void forEachProc(const sead::SafeString& proc_name, sead::IDelegate1<BaseProc*>& callback,
ProcFilters filters);
ProcIteratorContext getProcs(ProcFilter filters) { return {*this, filters}; }
bool checkFilters(BaseProc* proc, ProcFilters filters) const;
// endregion
// region Actor initializer control
void resumeThreadMaybe();
void stopThreads();
void clearMessageQueueMaybe();
void startActorCreateThread();
void clearInitializerMessageQueuesMaybe();
s32 getActorCreateInitializerQueueSize();
s32 getActorCreateInitializerQueueSizeEx(s32 x);
void invokeOnActorCreateInitializerThreadMaybe(void* delegate);
bool areInitializerThreadsIdle() const;
void waitForInitializerQueueToEmpty();
void cancelInitializerTasks();
void blockInitializerTasks();
void restartInitializerThreads();
void pauseInitializerThreads();
void resumeInitializerThreads();
void unblockInitDeleteTasks();
void pauseInitializerMainThread();
void resumeInitializerMainThread();
bool isAnyInitializerThreadActive() const;
int getInitializerQueueSize() const;
int getInitializerQueueSizeEx(int x = -1) const;
void removeInitializerTasksIf(sead::IDelegate1R<util::Task*, bool>& predicate);
void setActorGenerationEnabled(bool enabled);
// endregion
@@ -203,16 +220,10 @@ public:
BaseProcJobLists& getJobLists(JobType type) { return mJobLists[u32(type)]; }
bool isPushingJobs() const { return mIsPushingJobs; }
bool checkGetActorOk(BaseProc* proc, void* a2);
// region BaseProc iteration
sead::CriticalSection* lockProcMap();
void unlockProcMap();
BaseProc* getNextProc(sead::CriticalSection* cs, BaseProc* proc, ProcFilters filters);
ProcIteratorContext getProcs(ProcFilter filters) { return {*this, filters}; }
// endregion
static u32 sConstant0;
static u32 sConstant1;
static u32 sConstant2;
static u32 sConstant4;
private:
void doAddToUpdateStateList_(BaseProc& proc);
@@ -220,10 +231,6 @@ private:
bool checkJobPushState() const;
static sead::BufferedSafeString* sResidentActorListStr;
static u32 sConstant0;
static u32 sConstant1;
static u32 sConstant2;
static u32 sConstant4;
Status mStatus = Status::Idle;
sead::SizedEnum<JobType, u8> mJobType = JobType::Invalid;
+5
View File
@@ -13,3 +13,8 @@ add_subdirectory(System)
add_subdirectory(Terrain)
add_subdirectory(Utils)
add_subdirectory(World)
target_sources(uking PRIVATE
ksys.cpp
ksys.h
)
+32
View File
@@ -0,0 +1,32 @@
#include "KingSystem/ksys.h"
#include <heap/seadHeapMgr.h>
#include <thread/seadThread.h>
#include "KingSystem/ActorSystem/actBaseProcCreateTaskSelector.h"
#include "KingSystem/ActorSystem/actBaseProcInitializer.h"
#include "KingSystem/ActorSystem/actBaseProcMgr.h"
#include "KingSystem/System/HavokWorkerMgr.h"
namespace ksys {
void initBaseProcMgr(sead::Heap* heap) {
sead::ScopedCurrentHeapSetter setter(heap);
act::BaseProcMgr::createInstance(heap);
act::BaseProcCreateTaskSelector::createInstance(heap);
auto* worker_mgr = HavokWorkerMgr::instance();
act::BaseProcInitializerArgs args{};
args.queue_size = 1024;
args.thread_name = "ActorCreate";
args.task_selector = &act::BaseProcCreateTaskSelector::instance()->getDelegate();
act::BaseProcMgr::instance()->init(
heap, u32(act::JobType::Invalid), sead::ThreadMgr::instance()->getMainThread()->getId(),
worker_mgr->getWorkerThreadId(1), worker_mgr->getWorkerThreadId(2), args);
act::BaseProcMgr::sConstant0 = u32(act::JobType::PreCalc);
act::BaseProcMgr::sConstant1 = u32(act::JobType::Calc1);
act::BaseProcMgr::sConstant2 = u32(act::JobType::Calc2);
act::BaseProcMgr::sConstant4 = u32(act::JobType::Calc4);
}
} // namespace ksys
+11
View File
@@ -0,0 +1,11 @@
#pragma once
namespace sead {
class Heap;
}
namespace ksys {
void initBaseProcMgr(sead::Heap* heap);
} // namespace ksys