/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#pragma once
#include
#include
namespace ams::kern {
/* NOTE: This header is included after all other KAutoObjects. */
namespace impl {
template requires std::derived_from
consteval bool IsAutoObjectInheritanceValidImpl() {
#define CLASS_TOKEN_HANDLER(CLASSNAME) \
if constexpr (std::same_as) { \
if (T::GetStaticTypeObj().GetClassToken() != ::ams::kern::ClassToken) { \
return false; \
} \
} else { \
if (T::GetStaticTypeObj().IsDerivedFrom(CLASSNAME::GetStaticTypeObj()) != std::derived_from) { \
return false; \
} \
}
FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER)
#undef CLASS_TOKEN_HANDLER
return true;
}
consteval bool IsEveryAutoObjectInheritanceValid() {
#define CLASS_TOKEN_HANDLER(CLASSNAME) if (!IsAutoObjectInheritanceValidImpl()) { return false; }
FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER)
#undef CLASS_TOKEN_HANDLER
return true;
}
static_assert(IsEveryAutoObjectInheritanceValid());
template
concept IsAutoObjectWithSpecializedGetId = std::derived_from && requires (const T &t, const KAutoObjectWithList &l) {
{ t.GetIdImpl() } -> std::same_as;
};
template
struct AutoObjectWithListComparatorImpl {
using RedBlackKeyType = u64;
static ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const RedBlackKeyType &v) { return v; }
static ALWAYS_INLINE RedBlackKeyType GetRedBlackKey(const KAutoObjectWithList &v) {
if constexpr (IsAutoObjectWithSpecializedGetId) {
return static_cast(v).GetIdImpl();
} else {
return reinterpret_cast(std::addressof(v));
}
}
template requires (std::same_as || std::same_as)
static ALWAYS_INLINE int Compare(const U &lhs, const KAutoObjectWithList &rhs) {
const u64 lid = GetRedBlackKey(lhs);
const u64 rid = GetRedBlackKey(rhs);
if (lid < rid) {
return -1;
} else if (lid > rid) {
return 1;
} else {
return 0;
}
}
};
template
using AutoObjectWithListComparator = AutoObjectWithListComparatorImpl, T, KAutoObjectWithList>::type>;
template
using TrueObjectContainerListType = typename KAutoObjectWithListContainer::ListType>;
template
ALWAYS_INLINE TrueObjectContainerListType &GetTrueObjectContainerList(typename KAutoObjectWithListContainer::DummyListType &l) {
static_assert(alignof(l) == alignof(impl::TrueObjectContainerListType));
static_assert(sizeof(l) == sizeof(impl::TrueObjectContainerListType));
return *reinterpret_cast *>(std::addressof(l));
}
}
inline NOINLINE void KAutoObject::ScheduleDestruction() {
MESOSPHERE_ASSERT_THIS();
/* Set our object to destroy. */
m_next_closed_object = GetCurrentThread().GetClosedObject();
/* Set ourselves as the thread's next object to destroy. */
GetCurrentThread().SetClosedObject(this);
}
template
class KAutoObjectWithListContainer::ListAccessor : public impl::KAutoObjectWithListContainerBase::ListAccessorImpl> {
NON_COPYABLE(ListAccessor);
NON_MOVEABLE(ListAccessor);
private:
using BaseListAccessor = impl::KAutoObjectWithListContainerBase::ListAccessorImpl>;
public:
explicit ALWAYS_INLINE ListAccessor(KAutoObjectWithListContainer *container) : BaseListAccessor(container, impl::GetTrueObjectContainerList(container->m_dummy_object_list)) { /* ... */ }
explicit ALWAYS_INLINE ListAccessor(KAutoObjectWithListContainer &container) : BaseListAccessor(container, impl::GetTrueObjectContainerList(container.m_dummy_object_list)) { /* ... */ }
ALWAYS_INLINE ~ListAccessor() { /* ... */ }
};
template
ALWAYS_INLINE void KAutoObjectWithListContainer::Register(T *obj) {
return this->RegisterImpl(obj, impl::GetTrueObjectContainerList(m_dummy_object_list));
}
template
ALWAYS_INLINE void KAutoObjectWithListContainer::Unregister(T *obj) {
return this->UnregisterImpl(obj, impl::GetTrueObjectContainerList(m_dummy_object_list));
}
template
ALWAYS_INLINE size_t KAutoObjectWithListContainer::GetOwnedCountChecked(const KProcess *owner) {
return this->GetOwnedCountImpl(owner, impl::GetTrueObjectContainerList(m_dummy_object_list));
}
inline u64 KAutoObjectWithList::GetId() const {
#define CLASS_TOKEN_HANDLER(CLASSNAME) \
if constexpr (impl::IsAutoObjectWithSpecializedGetId) { \
if (const CLASSNAME * const derived = this->DynamicCast(); derived != nullptr) { \
return [](const T * const t_derived) ALWAYS_INLINE_LAMBDA -> u64 { \
static_assert(std::same_as); \
if constexpr (impl::IsAutoObjectWithSpecializedGetId) { \
return impl::AutoObjectWithListComparator::GetRedBlackKey(*t_derived); \
} else { \
AMS_ASSUME(false); \
} \
}(derived); \
} \
}
FOR_EACH_K_CLASS_TOKEN_OBJECT_TYPE(CLASS_TOKEN_HANDLER)
#undef CLASS_TOKEN_HANDLER
return impl::AutoObjectWithListComparator::GetRedBlackKey(*this);
}
}