ksys/act: Implement BaseProcLink

This commit is contained in:
Léo Lam
2020-08-20 13:15:12 +02:00
parent f92ab2f559
commit afde5b2775
12 changed files with 303 additions and 163 deletions
@@ -0,0 +1,160 @@
#include "KingSystem/ActorSystem/actBaseProcLink.h"
#include <prim/seadScopedLock.h>
#include <thread/seadThread.h>
#include "KingSystem/ActorSystem/actActorLinkConstDataAccess.h"
#include "KingSystem/ActorSystem/actBaseProc.h"
#include "KingSystem/ActorSystem/actBaseProcMgr.h"
namespace ksys::act {
BaseProcLink::BaseProcLink() = default;
BaseProcLink& BaseProcLink::operator=(const BaseProcLink& rhs) {
if (this == &rhs)
return *this;
reset();
if (rhs.mData)
mData = rhs.mData;
mId = rhs.mId;
return *this;
}
bool BaseProcLink::operator==(const BaseProcLink& rhs) const {
return (!hasProc() && !rhs.hasProc()) || mId == rhs.mId;
}
bool BaseProcLink::hasProc() const {
return getProc();
}
bool BaseProcLink::hasProcInCalcState() const {
return getProcInContext(
[](BaseProc* proc) { return proc && proc->getState() == BaseProc::State::Calc; });
}
bool BaseProcLink::hasProcById(BaseProc* proc) const {
return proc != nullptr & mId != cInvalidId && mId == proc->getId();
}
BaseProc* BaseProcLink::getProc(ActorLinkConstDataAccess* accessor, BaseProc* other_proc) {
return getProcInContext([&](BaseProc* proc) -> BaseProc* {
if (proc && acquireProc(accessor, proc, "frm::BaseProcLink") &&
BaseProcMgr::instance()->isAccessingProcSafe(proc, other_proc)) {
return proc;
}
return nullptr;
});
}
BaseProc* BaseProcLink::getProc(ActorLinkConstDataAccess* accessor) {
return getProcInContext([&](BaseProc* proc) -> BaseProc* {
if (proc && acquireProc(accessor, proc, "frm::BaseProcLink"))
return proc;
return nullptr;
});
}
bool BaseProcLink::acquire(BaseProc* proc, bool acquire_immediately) {
reset();
if (!proc || proc->isDeletedOrDeleting())
return false;
mData = proc->getBaseProcLinkData();
if (!mData) {
static constexpr const char* sStateNames[] = {"Init", "Calc", "Sleep", "Delete"};
sead::FixedSafeString<256> message;
message.format("%s:%s", proc->getName().cstr(), sStateNames[u8(proc->getState())]);
return false;
}
mId = proc->getId();
if (acquire_immediately) {
mData->mRefCount.increment();
mAcquired = true;
}
return true;
}
void BaseProcLink::reset() {
if (mAcquired) {
mAcquired = false;
if (mData)
mData->mRefCount.decrement();
}
mId = cInvalidId;
}
bool BaseProcLink::isAccessingSpecifiedProcUnsafe(BaseProc* other) const {
return getProcInContext([&](BaseProc* proc) {
return proc && !BaseProcMgr::instance()->isAccessingProcSafe(proc, other);
});
}
SEAD_SINGLETON_DISPOSER_IMPL(BaseProcLinkDataMgr)
BaseProc* BaseProcLinkData::getProc(u32 id, bool allow_deleted) const {
if (id == u32(-1) || mId != id)
return nullptr;
if (!allow_deleted && (!mProc || mProc->getState() == BaseProc::State::Delete))
return nullptr;
return mProc;
}
sead::CriticalSection* BaseProcLinkData::lockIfNeeded() {
if (BaseProcMgr::instance()->isHighPriorityThread())
return nullptr;
mCS.lock();
return &mCS;
}
bool BaseProcLinkDataMgr::acquireLink(BaseProc* proc) {
auto lock = sead::makeScopedLock(mCS);
s32 index = mIndex;
for (s32 i = 0; i < mData.size(); ++i) {
const s32 j = index == 0x800 ? 0 : index;
auto& data = mData[j];
if (data.mId == u32(-1)) {
{
auto data_lock = sead::makeScopedLock(data.mCS);
data.mProc = proc;
data.mId = proc->mId;
proc->mBaseProcLinkData = &data;
}
mIndex = j + 1;
return true;
}
index = j + 1;
}
for (s32 i = 0; i < mData.size(); ++i) {
auto data_lock = sead::makeScopedLock(mData[i].mCS);
// Debug code was probably here?
}
return false;
}
bool BaseProcLinkDataMgr::releaseLink(BaseProc* proc) {
auto* data = proc->mBaseProcLinkData;
if (!data)
return false;
const auto thread = sead::ThreadMgr::instance()->getCurrentThread();
thread->getPriority();
auto lock = sead::makeScopedLock(data->mCS);
data->mProc = nullptr;
data->mId = -1;
proc->mBaseProcLinkData = nullptr;
return true;
}
} // namespace ksys::act