/* * 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 #include #include namespace ams::sf::cmif { class ServerDomainManager { NON_COPYABLE(ServerDomainManager); NON_MOVEABLE(ServerDomainManager); private: class Domain; struct Entry { NON_COPYABLE(Entry); NON_MOVEABLE(Entry); util::IntrusiveListNode free_list_node; util::IntrusiveListNode domain_list_node; Domain *owner; ServiceObjectHolder object; explicit Entry() : owner(nullptr) { /* ... */ } }; class Domain final : public DomainServiceObject, private sf::impl::ServiceObjectImplBase2 { NON_COPYABLE(Domain); NON_MOVEABLE(Domain); private: using EntryList = typename util::IntrusiveListMemberTraits<&Entry::domain_list_node>::ListType; private: ServerDomainManager *m_manager; EntryList m_entries; public: explicit Domain(ServerDomainManager *m) : m_manager(m) { /* ... */ } ~Domain(); void DisposeImpl(); virtual void AddReference() override { ServiceObjectImplBase2::AddReferenceImpl(); } virtual void Release() override { if (ServiceObjectImplBase2::ReleaseImpl()) { this->DisposeImpl(); } } virtual ServerDomainBase *GetServerDomain() override final { return static_cast(this); } virtual Result ReserveIds(DomainObjectId *out_ids, size_t count) override final; virtual void ReserveSpecificIds(const DomainObjectId *ids, size_t count) override final; virtual void UnreserveIds(const DomainObjectId *ids, size_t count) override final; virtual void RegisterObject(DomainObjectId id, ServiceObjectHolder &&obj) override final; virtual ServiceObjectHolder UnregisterObject(DomainObjectId id) override final; virtual ServiceObjectHolder GetObject(DomainObjectId id) override final; }; public: using DomainEntryStorage = util::TypedStorage; using DomainStorage = util::TypedStorage; private: class EntryManager { private: using EntryList = typename util::IntrusiveListMemberTraits<&Entry::free_list_node>::ListType; private: os::SdkMutex m_lock; EntryList m_free_list; Entry *m_entries; size_t m_num_entries; public: EntryManager(DomainEntryStorage *entry_storage, size_t entry_count); ~EntryManager(); Entry *AllocateEntry(); void FreeEntry(Entry *); void AllocateSpecificEntries(const DomainObjectId *ids, size_t count); inline DomainObjectId GetId(Entry *e) { const size_t index = e - m_entries; AMS_ABORT_UNLESS(index < m_num_entries); return DomainObjectId{ u32(index + 1) }; } inline Entry *GetEntry(DomainObjectId id) { if (id == InvalidDomainObjectId) { return nullptr; } const size_t index = id.value - 1; if (!(index < m_num_entries)) { return nullptr; } return m_entries + index; } }; private: os::SdkMutex m_entry_owner_lock; EntryManager m_entry_manager; private: virtual void *AllocateDomain() = 0; virtual void FreeDomain(void *) = 0; protected: ServerDomainManager(DomainEntryStorage *entry_storage, size_t entry_count) : m_entry_owner_lock(), m_entry_manager(entry_storage, entry_count) { /* ... */ } inline DomainServiceObject *AllocateDomainServiceObject() { void *storage = this->AllocateDomain(); if (storage == nullptr) { return nullptr; } return std::construct_at(static_cast(storage), this); } public: static void DestroyDomainServiceObject(DomainServiceObject *obj) { static_cast(obj)->DisposeImpl(); } }; }