mirror of
https://github.com/Atmosphere-NX/Atmosphere-libs.git
synced 2025-08-11 17:59:24 +02:00
* Work around Clang's incomplete C++20 support for omitting typename * vapours: fix Clang error about missing return in constexpr function * stratosphere: fix call to non-constexpr strlen in constexpr function strlen being constexpr is a non-compliant GCC extension; Clang explicitly rejects it: https://reviews.llvm.org/D23692 * stratosphere: add a bunch of missing override specifiers * stratosphere: work around Clang consteval bug Minimal example: https://godbolt.org/z/MoM64v93M The issue seems to be that Clang does not consider f(x) to be a constant expression if x comes from a template argument that isn't a non-type auto template argument (???) We can work around this by relaxing GetMessageHeaderForCheck (by using constexpr instead of consteval). This produces no functional changes because the result of GetMessageHeaderForCheck() is assigned to a constexpr variable, so the result is guaranteed to be computed at compile-time. * stratosphere: fix missing require clauses in definitions GCC not requiring the require clauses to be repeated for member definitions is actually a compiler bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96830 Clang rejects declarations with missing require clauses. * Fix ALWAYS_INLINE_LAMBDA and parameter list relative order While GCC doesn't seem to care about the position of the always_inline attribute relative to the parameter list, Clang is very picky and requires the attribute to appear after the parameter list (and before a trailing return type) * stratosphere: fix static constexpr member variable with incomplete type GCC accepts this for some reason (because of the lambda?) but Clang correctly rejects this.
141 lines
5.6 KiB
C++
141 lines
5.6 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
#include <stratosphere/sf/sf_common.hpp>
|
|
#include <stratosphere/sf/cmif/sf_cmif_domain_api.hpp>
|
|
#include <stratosphere/sf/cmif/sf_cmif_domain_service_object.hpp>
|
|
#include <stratosphere/sf/impl/sf_service_object_impl.hpp>
|
|
|
|
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<ServerDomainBase *>(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<Entry>;
|
|
using DomainStorage = util::TypedStorage<Domain>;
|
|
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<Domain *>(storage), this);
|
|
}
|
|
public:
|
|
static void DestroyDomainServiceObject(DomainServiceObject *obj) {
|
|
static_cast<Domain *>(obj)->DisposeImpl();
|
|
}
|
|
};
|
|
|
|
|
|
}
|