libstrat: convert to experimental new (super-accurate) sf allocation semantics

This commit is contained in:
Michael Scire
2021-01-17 07:55:32 -08:00
committed by SciresM
parent 8314d015f3
commit f06de12bea
149 changed files with 2852 additions and 1746 deletions

View File

@@ -15,9 +15,10 @@
*/
#pragma once
#include "../sf_common.hpp"
#include "sf_cmif_domain_api.hpp"
#include "sf_cmif_domain_service_object.hpp"
#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 {
@@ -39,7 +40,7 @@ namespace ams::sf::cmif {
explicit Entry() : owner(nullptr) { /* ... */ }
};
class Domain final : public DomainServiceObject {
class Domain final : public DomainServiceObject, private sf::impl::ServiceObjectImplBase2 {
NON_COPYABLE(Domain);
NON_MOVEABLE(Domain);
private:
@@ -51,7 +52,17 @@ namespace ams::sf::cmif {
explicit Domain(ServerDomainManager *m) : manager(m) { /* ... */ }
~Domain();
void DestroySelf();
void DisposeImpl();
virtual void AddReference() {
ServiceObjectImplBase2::AddReferenceImpl();
}
virtual void Release() {
if (ServiceObjectImplBase2::ReleaseImpl()) {
this->DisposeImpl();
}
}
virtual ServerDomainBase *GetServerDomain() override final {
return static_cast<ServerDomainBase *>(this);
@@ -120,7 +131,7 @@ namespace ams::sf::cmif {
}
public:
static void DestroyDomainServiceObject(DomainServiceObject *obj) {
static_cast<Domain *>(obj)->DestroySelf();
static_cast<Domain *>(obj)->DisposeImpl();
}
};

View File

@@ -84,18 +84,14 @@ namespace ams::sf::cmif {
}
};
template<size_t N, class = std::make_index_sequence<N>>
class ServiceDispatchTableImpl;
template<size_t N, size_t... Is>
class ServiceDispatchTableImpl<N, std::index_sequence<Is...>> : public ServiceDispatchTableBase {
private:
template<size_t>
using EntryType = ServiceCommandMeta;
template<size_t N>
class ServiceDispatchTableImpl : public ServiceDispatchTableBase {
public:
static constexpr size_t NumEntries = N;
private:
const std::array<ServiceCommandMeta, N> entries;
public:
explicit constexpr ServiceDispatchTableImpl(EntryType<Is>... args) : entries { args... } { /* ... */ }
explicit constexpr ServiceDispatchTableImpl(const std::array<ServiceCommandMeta, N> &e) : entries{e} { /* ... */ }
Result ProcessMessage(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
return this->ProcessMessageImpl(ctx, in_raw_data, this->entries.data(), this->entries.size());
@@ -104,20 +100,20 @@ namespace ams::sf::cmif {
Result ProcessMessageForMitm(ServiceDispatchContext &ctx, const cmif::PointerAndSize &in_raw_data) const {
return this->ProcessMessageForMitmImpl(ctx, in_raw_data, this->entries.data(), this->entries.size());
}
constexpr const std::array<ServiceCommandMeta, N> &GetEntries() const {
return this->entries;
}
};
}
template<typename ...Entries>
class ServiceDispatchTable : public impl::ServiceDispatchTableImpl<sizeof...(Entries)> {
template<size_t N>
class ServiceDispatchTable : public impl::ServiceDispatchTableImpl<N> {
public:
explicit constexpr ServiceDispatchTable(Entries... entries) : impl::ServiceDispatchTableImpl<sizeof...(Entries)>(entries...) { /* ... */ }
explicit constexpr ServiceDispatchTable(const std::array<ServiceCommandMeta, N> &e) : impl::ServiceDispatchTableImpl<N>(e) { /* ... */ }
};
#define AMS_SF_CMIF_IMPL_DEFINE_SERVICE_DISPATCH_TABLE \
template<typename ServiceImpl> \
static constexpr inline ::ams::sf::cmif::ServiceDispatchTable s_CmifServiceDispatchTable
struct ServiceDispatchMeta {
const impl::ServiceDispatchTableBase *DispatchTable;
Result (impl::ServiceDispatchTableBase::*ProcessHandler)(ServiceDispatchContext &, const cmif::PointerAndSize &) const;
@@ -140,6 +136,16 @@ namespace ams::sf::cmif {
static constexpr inline ServiceDispatchMeta Meta{&DispatchTable, ProcessHandlerImpl};
};
template<>
struct ServiceDispatchTraits<sf::IServiceObject> {
static constexpr inline auto DispatchTable = ServiceDispatchTable<0>(std::array<ServiceCommandMeta, 0>{});
};
template<>
struct ServiceDispatchTraits<sf::IMitmServiceObject> {
static constexpr inline auto DispatchTable = ServiceDispatchTable<0>(std::array<ServiceCommandMeta, 0>{});
};
template<typename T>
constexpr ALWAYS_INLINE const ServiceDispatchMeta *GetServiceDispatchMeta() {
return &ServiceDispatchTraits<T>::Meta;

View File

@@ -22,7 +22,7 @@ namespace ams::sf::cmif {
class ServiceObjectHolder {
private:
std::shared_ptr<sf::IServiceObject> srv;
SharedPointer<IServiceObject> srv;
const ServiceDispatchMeta *dispatch_meta;
private:
/* Copy constructor. */
@@ -30,7 +30,7 @@ namespace ams::sf::cmif {
ServiceObjectHolder &operator=(const ServiceObjectHolder &o) = delete;
public:
/* Default constructor, null all members. */
ServiceObjectHolder() : srv(nullptr), dispatch_meta(nullptr) { /* ... */ }
ServiceObjectHolder() : srv(nullptr, false), dispatch_meta(nullptr) { /* ... */ }
~ServiceObjectHolder() {
this->dispatch_meta = nullptr;
@@ -38,9 +38,8 @@ namespace ams::sf::cmif {
/* Ensure correct type id at runtime through template constructor. */
template<typename ServiceImpl>
constexpr explicit ServiceObjectHolder(std::shared_ptr<ServiceImpl> &&s) {
this->srv = std::move(s);
this->dispatch_meta = GetServiceDispatchMeta<ServiceImpl>();
constexpr explicit ServiceObjectHolder(SharedPointer<ServiceImpl> &&s) : srv(std::move(s)), dispatch_meta(GetServiceDispatchMeta<ServiceImpl>()) {
/* ... */
}
/* Move constructor, assignment operator. */
@@ -50,13 +49,13 @@ namespace ams::sf::cmif {
ServiceObjectHolder &operator=(ServiceObjectHolder &&o) {
ServiceObjectHolder tmp(std::move(o));
tmp.Swap(*this);
tmp.swap(*this);
return *this;
}
/* State management. */
void Swap(ServiceObjectHolder &o) {
std::swap(this->srv, o.srv);
void swap(ServiceObjectHolder &o) {
this->srv.swap(o.srv);
std::swap(this->dispatch_meta, o.dispatch_meta);
}
@@ -86,21 +85,21 @@ namespace ams::sf::cmif {
return 0;
}
template<typename ServiceImpl>
template<typename Interface>
constexpr inline bool IsServiceObjectValid() const {
return this->GetServiceId() == GetServiceDispatchMeta<ServiceImpl>()->GetServiceId();
return this->GetServiceId() == GetServiceDispatchMeta<Interface>()->GetServiceId();
}
template<typename ServiceImpl>
inline std::shared_ptr<ServiceImpl> GetServiceObject() const {
if (this->GetServiceId() == GetServiceDispatchMeta<ServiceImpl>()->GetServiceId()) {
return std::static_pointer_cast<ServiceImpl>(this->srv);
template<typename Interface>
inline Interface *GetServiceObject() const {
if (this->GetServiceId() == GetServiceDispatchMeta<Interface>()->GetServiceId()) {
return static_cast<Interface *>(this->srv.Get());
}
return nullptr;
}
inline sf::IServiceObject *GetServiceObjectUnsafe() const {
return this->srv.get();
return static_cast<sf::IServiceObject *>(this->srv.Get());
}
/* Processing. */

View File

@@ -46,75 +46,20 @@ namespace ams::sf::hipc {
protected:
using ServerDomainSessionManager::DomainEntryStorage;
using ServerDomainSessionManager::DomainStorage;
private:
class ServerBase : public os::WaitableHolderType {
protected:
class Server : public os::WaitableHolderType {
friend class ServerManagerBase;
template<size_t, typename, size_t>
friend class ServerManager;
NON_COPYABLE(ServerBase);
NON_MOVEABLE(ServerBase);
NON_COPYABLE(Server);
NON_MOVEABLE(Server);
protected:
cmif::ServiceObjectHolder static_object;
::Handle port_handle;
sm::ServiceName service_name;
int index;
bool service_managed;
public:
ServerBase(Handle ph, sm::ServiceName sn, bool m, cmif::ServiceObjectHolder &&sh) :
static_object(std::move(sh)), port_handle(ph), service_name(sn), service_managed(m)
{
hipc::AttachWaitableHolderForAccept(this, ph);
}
virtual ~ServerBase() = 0;
virtual void CreateSessionObjectHolder(cmif::ServiceObjectHolder *out_obj, std::shared_ptr<::Service> *out_fsrv) const = 0;
};
template<typename Interface, auto MakeShared>
class Server : public ServerBase {
NON_COPYABLE(Server);
NON_MOVEABLE(Server);
private:
static constexpr bool IsMitmServer = sf::IsMitmServiceObject<Interface>;
public:
Server(Handle ph, sm::ServiceName sn, bool m, cmif::ServiceObjectHolder &&sh) : ServerBase(ph, sn, m, std::forward<cmif::ServiceObjectHolder>(sh)) {
/* ... */
}
virtual ~Server() override {
if (this->service_managed) {
if constexpr (IsMitmServer) {
R_ABORT_UNLESS(sm::mitm::UninstallMitm(this->service_name));
} else {
R_ABORT_UNLESS(sm::UnregisterService(this->service_name));
}
R_ABORT_UNLESS(svc::CloseHandle(this->port_handle));
}
}
virtual void CreateSessionObjectHolder(cmif::ServiceObjectHolder *out_obj, std::shared_ptr<::Service> *out_fsrv) const override final {
/* If we're serving a static object, use it. */
if (this->static_object) {
*out_obj = std::move(this->static_object.Clone());
*out_fsrv = nullptr;
return;
}
/* Otherwise, we're either a mitm session or a non-mitm session. */
if constexpr (IsMitmServer) {
/* Custom deleter ensures that nothing goes awry. */
std::shared_ptr<::Service> forward_service = std::move(ServerSession::CreateForwardService());
/* Get mitm forward session. */
sm::MitmProcessInfo client_info;
R_ABORT_UNLESS(sm::mitm::AcknowledgeSession(forward_service.get(), &client_info, this->service_name));
*out_obj = std::move(cmif::ServiceObjectHolder(std::move(MakeShared(std::shared_ptr<::Service>(forward_service), client_info))));
*out_fsrv = std::move(forward_service);
} else {
*out_obj = std::move(cmif::ServiceObjectHolder(std::move(MakeShared())));
*out_fsrv = nullptr;
}
}
bool is_mitm_server;
};
private:
/* Management of waitables. */
@@ -139,33 +84,94 @@ namespace ams::sf::hipc {
Result ProcessForMitmServer(os::WaitableHolderType *holder);
Result ProcessForSession(os::WaitableHolderType *holder);
template<typename Interface, auto MakeShared>
void RegisterServerImpl(Handle port_handle, sm::ServiceName service_name, bool managed, cmif::ServiceObjectHolder &&static_holder) {
/* Allocate server memory. */
auto *server = this->AllocateServer();
AMS_ABORT_UNLESS(server != nullptr);
new (server) Server<Interface, MakeShared>(port_handle, service_name, managed, std::forward<cmif::ServiceObjectHolder>(static_holder));
void RegisterServerImpl(Server *server, Handle port_handle, bool is_mitm_server) {
server->port_handle = port_handle;
hipc::AttachWaitableHolderForAccept(server, port_handle);
if constexpr (!sf::IsMitmServiceObject<Interface>) {
/* Non-mitm server. */
os::SetWaitableHolderUserData(server, static_cast<uintptr_t>(UserDataTag::Server));
} else {
server->is_mitm_server = is_mitm_server;
if (is_mitm_server) {
/* Mitm server. */
os::SetWaitableHolderUserData(server, static_cast<uintptr_t>(UserDataTag::MitmServer));
} else {
/* Non-mitm server. */
os::SetWaitableHolderUserData(server, static_cast<uintptr_t>(UserDataTag::Server));
}
os::LinkWaitableHolder(std::addressof(this->waitable_manager), server);
}
template<typename Interface, typename ServiceImpl>
static constexpr inline std::shared_ptr<Interface> MakeSharedMitm(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &client_info) {
return sf::MakeShared<Interface, ServiceImpl>(std::forward<std::shared_ptr<::Service>>(s), client_info);
void RegisterServerImpl(int index, cmif::ServiceObjectHolder &&static_holder, Handle port_handle, bool is_mitm_server) {
/* Allocate server memory. */
auto *server = this->AllocateServer();
AMS_ABORT_UNLESS(server != nullptr);
server->service_managed = false;
if (static_holder) {
server->static_object = std::move(static_holder);
} else {
server->index = index;
}
this->RegisterServerImpl(server, port_handle, is_mitm_server);
}
Result RegisterServerImpl(int index, cmif::ServiceObjectHolder &&static_holder, sm::ServiceName service_name, size_t max_sessions) {
/* Register service. */
Handle port_handle;
R_TRY(sm::RegisterService(&port_handle, service_name, max_sessions, false));
/* Allocate server memory. */
auto *server = this->AllocateServer();
AMS_ABORT_UNLESS(server != nullptr);
server->service_managed = true;
server->service_name = service_name;
if (static_holder) {
server->static_object = std::move(static_holder);
} else {
server->index = index;
}
this->RegisterServerImpl(server, port_handle, false);
return ResultSuccess();
}
template<typename Interface>
Result RegisterMitmServerImpl(int index, cmif::ServiceObjectHolder &&static_holder, sm::ServiceName service_name) {
/* Install mitm service. */
Handle port_handle;
R_TRY(this->InstallMitmServerImpl(&port_handle, service_name, &Interface::ShouldMitm));
/* Allocate server memory. */
auto *server = this->AllocateServer();
AMS_ABORT_UNLESS(server != nullptr);
server->service_managed = true;
server->service_name = service_name;
if (static_holder) {
server->static_object = std::move(static_holder);
} else {
server->index = index;
}
this->RegisterServerImpl(server, port_handle, true);
return ResultSuccess();
}
Result InstallMitmServerImpl(Handle *out_port_handle, sm::ServiceName service_name, MitmQueryFunction query_func);
protected:
virtual ServerBase *AllocateServer() = 0;
virtual void DestroyServer(ServerBase *server) = 0;
virtual Server *AllocateServer() = 0;
virtual void DestroyServer(Server *server) = 0;
virtual Result OnNeedsToAccept(int port_index, Server *server) {
AMS_ABORT("OnNeedsToAccept must be overridden when using indexed ports");
}
template<typename Interface>
Result AcceptImpl(Server *server, SharedPointer<Interface> p) {
return ServerSessionManager::AcceptSession(server->port_handle, std::move(p));
}
public:
ServerManagerBase(DomainEntryStorage *entry_storage, size_t entry_count) :
ServerDomainSessionManager(entry_storage, entry_count),
@@ -181,40 +187,27 @@ namespace ams::sf::hipc {
os::InitializeWaitableManager(std::addressof(this->waitlist));
}
template<typename Interface, typename ServiceImpl, auto MakeShared = sf::MakeShared<Interface, ServiceImpl>> requires (sf::IsServiceObject<Interface> && !sf::IsMitmServiceObject<Interface>)
void RegisterServer(Handle port_handle, std::shared_ptr<Interface> static_object = nullptr) {
/* Register server. */
cmif::ServiceObjectHolder static_holder;
if (static_object != nullptr) {
static_holder = cmif::ServiceObjectHolder(std::move(static_object));
}
this->RegisterServerImpl<Interface, MakeShared>(port_handle, sm::InvalidServiceName, false, std::move(static_holder));
template<typename Interface>
void RegisterObjectForServer(SharedPointer<Interface> static_object, Handle port_handle) {
this->RegisterServerImpl(0, cmif::ServiceObjectHolder(std::move(static_object)), port_handle, false);
}
template<typename Interface, typename ServiceImpl, auto MakeShared = sf::MakeShared<Interface, ServiceImpl>> requires (sf::IsServiceObject<Interface> && !sf::IsMitmServiceObject<Interface>)
Result RegisterServer(sm::ServiceName service_name, size_t max_sessions, std::shared_ptr<Interface> static_object = nullptr) {
/* Register service. */
Handle port_handle;
R_TRY(sm::RegisterService(&port_handle, service_name, max_sessions, false));
/* Register server. */
cmif::ServiceObjectHolder static_holder;
if (static_object != nullptr) {
static_holder = cmif::ServiceObjectHolder(std::move(static_object));
}
this->RegisterServerImpl<Interface, MakeShared>(port_handle, service_name, true, std::move(static_holder));
return ResultSuccess();
template<typename Interface>
Result RegisterObjectForServer(SharedPointer<Interface> static_object, sm::ServiceName service_name, size_t max_sessions) {
return this->RegisterServerImpl(0, cmif::ServiceObjectHolder(std::move(static_object)), service_name, max_sessions);
}
template<typename Interface, typename ServiceImpl, auto MakeShared = MakeSharedMitm<Interface, ServiceImpl>>
requires (sf::IsMitmServiceObject<Interface> && sf::IsMitmServiceImpl<ServiceImpl>)
Result RegisterMitmServer(sm::ServiceName service_name) {
/* Install mitm service. */
Handle port_handle;
R_TRY(this->InstallMitmServerImpl(&port_handle, service_name, &ServiceImpl::ShouldMitm));
void RegisterServer(int port_index, Handle port_handle) {
this->RegisterServerImpl(port_index, cmif::ServiceObjectHolder(), port_handle, false);
}
this->RegisterServerImpl<Interface, MakeShared>(port_handle, service_name, true, cmif::ServiceObjectHolder());
return ResultSuccess();
Result RegisterServer(int port_index, sm::ServiceName service_name, size_t max_sessions) {
return this->RegisterServerImpl(port_index, cmif::ServiceObjectHolder(), service_name, max_sessions);
}
template<typename Interface>
Result RegisterMitmServer(int port_index, sm::ServiceName service_name) {
return this->template RegisterMitmServerImpl<Interface>(port_index, cmif::ServiceObjectHolder(), service_name);
}
/* Processing. */
@@ -251,7 +244,7 @@ namespace ams::sf::hipc {
private:
/* Resource storage. */
os::Mutex resource_mutex;
TYPED_STORAGE(ServerBase) server_storages[MaxServers];
TYPED_STORAGE(Server) server_storages[MaxServers];
bool server_allocated[MaxServers];
TYPED_STORAGE(ServerSession) session_storages[MaxSessions];
bool session_allocated[MaxSessions];
@@ -265,7 +258,7 @@ namespace ams::sf::hipc {
bool domain_allocated[ManagerOptions::MaxDomains];
DomainEntryStorage domain_entry_storages[ManagerOptions::MaxDomainObjects];
private:
constexpr inline size_t GetServerIndex(const ServerBase *server) const {
constexpr inline size_t GetServerIndex(const Server *server) const {
const size_t i = server - GetPointer(this->server_storages[0]);
AMS_ABORT_UNLESS(i < MaxServers);
return i;
@@ -299,7 +292,7 @@ namespace ams::sf::hipc {
this->session_allocated[index] = false;
}
virtual ServerBase *AllocateServer() override final {
virtual Server *AllocateServer() override final {
std::scoped_lock lk(this->resource_mutex);
for (size_t i = 0; i < MaxServers; i++) {
if (!this->server_allocated[i]) {
@@ -310,11 +303,22 @@ namespace ams::sf::hipc {
return nullptr;
}
virtual void DestroyServer(ServerBase *server) override final {
virtual void DestroyServer(Server *server) override final {
std::scoped_lock lk(this->resource_mutex);
const size_t index = this->GetServerIndex(server);
AMS_ABORT_UNLESS(this->server_allocated[index]);
server->~ServerBase();
{
os::UnlinkWaitableHolder(server);
os::FinalizeWaitableHolder(server);
if (server->service_managed) {
if (server->is_mitm_server) {
R_ABORT_UNLESS(sm::mitm::UninstallMitm(server->service_name));
} else {
R_ABORT_UNLESS(sm::UnregisterService(server->service_name));
}
R_ABORT_UNLESS(svc::CloseHandle(server->port_handle));
}
}
this->server_allocated[index] = false;
}

View File

@@ -34,14 +34,14 @@ namespace ams::sf::hipc {
namespace impl {
class HipcManager;
class HipcManagerImpl;
}
class ServerSession : public os::WaitableHolderType {
friend class ServerSessionManager;
friend class ServerManagerBase;
friend class impl::HipcManager;
friend class impl::HipcManagerImpl;
NON_COPYABLE(ServerSession);
NON_MOVEABLE(ServerSession);
private:
@@ -92,16 +92,13 @@ namespace ams::sf::hipc {
/* Allocate session. */
ServerSession *session_memory = this->AllocateSession();
R_UNLESS(session_memory != nullptr, sf::hipc::ResultOutOfSessionMemory());
/* Register session. */
bool succeeded = false;
ON_SCOPE_EXIT {
if (!succeeded) {
this->DestroySession(session_memory);
}
};
auto register_guard = SCOPE_GUARD { this->DestroySession(session_memory); };
R_TRY(ctor(session_memory));
/* Save new session to output. */
succeeded = true;
register_guard.Cancel();
*out = session_memory;
return ResultSuccess();
}
@@ -162,13 +159,13 @@ namespace ams::sf::hipc {
Result RegisterMitmSession(Handle session_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
Result AcceptMitmSession(Handle mitm_port_handle, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv);
template<typename ServiceImpl>
Result AcceptSession(Handle port_handle, std::shared_ptr<ServiceImpl> obj) {
template<typename Interface>
Result AcceptSession(Handle port_handle, SharedPointer<Interface> obj) {
return this->AcceptSession(port_handle, cmif::ServiceObjectHolder(std::move(obj)));
}
template<typename ServiceImpl>
Result AcceptMitmSession(Handle mitm_port_handle, std::shared_ptr<ServiceImpl> obj, std::shared_ptr<::Service> &&fsrv) {
template<typename Interface>
Result AcceptMitmSession(Handle mitm_port_handle, SharedPointer<Interface> obj, std::shared_ptr<::Service> &&fsrv) {
return this->AcceptMitmSession(mitm_port_handle, cmif::ServiceObjectHolder(std::move(obj)), std::forward<std::shared_ptr<::Service>>(fsrv));
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2018-2020 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 <vapours.hpp>
#include <stratosphere/sf/impl/sf_impl_autogen_interface_macros.hpp>
#include <stratosphere/sf/impl/sf_impl_template_base.hpp>
namespace ams::sf::impl {
#define AMS_SF_IMPL_DEFINE_IMPL_SYNC_METHOD(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
virtual RETURN AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME) ARGS override { \
return ImplGetter::GetImplPointer(static_cast<ImplHolder *>(this))->NAME ARGNAMES; \
}
#define AMS_SF_DEFINE_INTERFACE(NAMESPACE, INTERFACE, CMD_MACRO) \
namespace NAMESPACE { \
\
AMS_SF_DEFINE_INTERFACE_IMPL(::ams::sf::IServiceObject, INTERFACE, CMD_MACRO) \
\
} \
\
namespace ams::sf::impl { \
\
template<typename Base, typename ImplHolder, typename ImplGetter, typename Root> \
class ImplTemplateBaseT<::NAMESPACE::INTERFACE, Base, ImplHolder, ImplGetter, Root> : public Base, public ImplHolder { \
public: \
template<typename... Args> \
constexpr explicit ImplTemplateBaseT(Args &&...args) : ImplHolder(std::forward<Args>(args)...) { /* ... */ } \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_IMPL_SYNC_METHOD) \
}; \
\
}
#define AMS_SF_DEFINE_INTERFACE_WITH_BASE(NAMESPACE, INTERFACE, BASE, CMD_MACRO) \
namespace NAMESPACE { \
\
AMS_SF_DEFINE_INTERFACE_IMPL(BASE, INTERFACE, CMD_MACRO) \
\
} \
\
namespace ams::sf::impl { \
\
template<typename Base, typename ImplHolder, typename ImplGetter, typename Root> \
class ImplTemplateBaseT<::NAMESPACE::INTERFACE, Base, ImplHolder, ImplGetter, Root> : public ImplTemplateBaseT<BASE, Base, ImplHolder, ImplGetter, Root> { \
private: \
using BaseImplTemplateBase = ImplTemplateBaseT<BASE, Base, ImplHolder, ImplGetter, Root>; \
public: \
template<typename... Args> \
constexpr explicit ImplTemplateBaseT(Args &&...args) : BaseImplTemplateBase(std::forward<Args>(args)...) { /* ... */ } \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_IMPL_SYNC_METHOD) \
}; \
\
}
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2018-2020 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 <vapours.hpp>
namespace ams::sf::impl {
struct SyncFunctionTraits {
public:
template<typename R, typename C, typename... A>
static std::tuple<A...> GetArgsImpl(R(C::*)(A...));
};
template<auto F>
using SyncFunctionArgsType = decltype(SyncFunctionTraits::GetArgsImpl(F));
template<typename T>
struct TypeTag{};
template<size_t First, size_t... Ix>
static constexpr inline size_t ParameterCount = sizeof...(Ix);
#define AMS_SF_IMPL_SYNC_FUNCTION_NAME(FUNCNAME) \
_ams_sf_sync_##FUNCNAME
#define AMS_SF_IMPL_DEFINE_INTERFACE_SYNC_METHOD(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
virtual RETURN AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME) ARGS = 0;
#define AMS_SF_IMPL_EXTRACT_INTERFACE_SYNC_METHOD_ARGUMENTS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
using NAME##ArgumentsType = ::ams::sf::impl::SyncFunctionArgsType<&CLASSNAME::AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME)>;
#define AMS_SF_IMPL_DEFINE_INTERFACE_METHOD(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
ALWAYS_INLINE RETURN NAME ARGS { \
return this->AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME) ARGNAMES; \
}
#define AMS_SF_IMPL_DEFINE_INTERFACE_SERVICE_COMMAND_META_HOLDER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
template<typename Interface, typename A> struct NAME##ServiceCommandMetaHolder; \
\
template<typename Interface, typename ...Arguments> \
requires std::same_as<std::tuple<Arguments...>, NAME##ArgumentsType> \
struct NAME##ServiceCommandMetaHolder<Interface, std::tuple<Arguments...>> { \
static constexpr auto Value = ::ams::sf::impl::MakeServiceCommandMeta<VERSION_MIN, VERSION_MAX, CMD_ID, &Interface::AMS_SF_IMPL_SYNC_FUNCTION_NAME(NAME), RETURN, Interface, Arguments...>(); \
};
#define AMS_SF_IMPL_GET_NULL_FOR_PARAMETER_COUNT(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
, 0
#define AMS_SF_IMPL_DEFINE_CMIF_SERVICE_COMMAND_META_TABLE_ENTRY(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
NAME##ServiceCommandMetaHolder<Interface, NAME##ArgumentsType>::Value,
template<typename...>
struct Print;
#define AMS_SF_IMPL_DEFINE_INTERFACE(BASECLASS, CLASSNAME, CMD_MACRO) \
class CLASSNAME : public BASECLASS { \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_SYNC_METHOD) \
public: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_EXTRACT_INTERFACE_SYNC_METHOD_ARGUMENTS) \
public: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_METHOD) \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_SERVICE_COMMAND_META_HOLDER) \
public: \
template<typename Interface> \
static constexpr inline ::ams::sf::cmif::ServiceDispatchTable s_CmifServiceDispatchTable { \
[] { \
constexpr size_t CurSize = ::ams::sf::impl::ParameterCount<0 CMD_MACRO(CLASSNAME, AMS_SF_IMPL_GET_NULL_FOR_PARAMETER_COUNT) >; \
std::array<::ams::sf::cmif::ServiceCommandMeta, CurSize> cur_entries { CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_CMIF_SERVICE_COMMAND_META_TABLE_ENTRY) }; \
\
constexpr const auto &BaseEntries = ::ams::sf::cmif::ServiceDispatchTraits<BASECLASS>::DispatchTable.GetEntries(); \
constexpr size_t BaseSize = BaseEntries.size(); \
\
std::array<::ams::sf::cmif::ServiceCommandMeta, BaseSize + CurSize> combined_entries{}; \
for (size_t i = 0; i < BaseSize; ++i) { \
combined_entries[i] = BaseEntries[i]; \
} \
for (size_t i = 0; i < CurSize; ++i) { \
combined_entries[BaseSize + i] = cur_entries[i]; \
} \
\
return ::ams::sf::cmif::ServiceDispatchTable { combined_entries }; \
} () \
}; \
};
#define AMS_SF_IMPL_DEFINE_CONCEPT_HELPERS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
template<typename T, typename... Args> \
concept Is##CLASSNAME##__##NAME##Impl = requires (T &t, Args &&... args) { \
{ t.NAME(std::forward<Args>(args)...) } -> std::same_as<RETURN>; \
}; \
\
template<typename T, typename A> \
struct Is##CLASSNAME##__##NAME##Holder : std::false_type{}; \
\
template<typename T, typename... Args> requires std::same_as<std::tuple<Args...>, CLASSNAME::NAME##ArgumentsType> \
struct Is##CLASSNAME##__##NAME##Holder<T, std::tuple<Args...>> : std::bool_constant<Is##CLASSNAME##__##NAME##Impl<T, Args...>>{}; \
\
template<typename T> \
static constexpr inline bool Is##CLASSNAME##__##NAME = Is##CLASSNAME##__##NAME##Holder<T, CLASSNAME::NAME##ArgumentsType>::value;
#define AMS_SF_IMPL_CHECK_CONCEPT_HELPER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
Is##CLASSNAME##__##NAME<T> &&
#define AMS_SF_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_CONCEPT_HELPERS) \
\
template<typename T> \
concept Is##CLASSNAME = CMD_MACRO(CLASSNAME, AMS_SF_IMPL_CHECK_CONCEPT_HELPER) true;
#define AMS_SF_DEFINE_INTERFACE_IMPL(BASECLASS, CLASSNAME, CMD_MACRO) \
AMS_SF_IMPL_DEFINE_INTERFACE(::ams::sf::IServiceObject, CLASSNAME, CMD_MACRO) \
AMS_SF_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \
static_assert(Is##CLASSNAME<CLASSNAME>);
#define AMS_SF_METHOD_INFO_7(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES) \
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, hos::Version_Min, hos::Version_Max)
#define AMS_SF_METHOD_INFO_8(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN) \
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, hos::Version_Max)
#define AMS_SF_METHOD_INFO_9(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX) \
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, ARGNAMES, VERSION_MIN, VERSION_MAX)
#define AMS_SF_METHOD_INFO_X(_, _0, _1, _2, _3, _4, _5, _6, _7, _8, FUNC, ...) FUNC
#define AMS_SF_METHOD_INFO(...) \
AMS_SF_METHOD_INFO_X(, ## __VA_ARGS__, AMS_SF_METHOD_INFO_9(__VA_ARGS__), AMS_SF_METHOD_INFO_8(__VA_ARGS__), AMS_SF_METHOD_INFO_7(__VA_ARGS__))
}

View File

@@ -68,34 +68,78 @@ namespace ams::sf {
struct OutObjectTag{};
template<size_t, size_t>
class InOutObjectHolder;
}
template<typename T>
class IsOutForceEnabled<std::shared_ptr<T>> : public std::true_type{};
template<typename ServiceImpl>
class Out<std::shared_ptr<ServiceImpl>> : public impl::OutObjectTag {
static_assert(std::is_base_of<sf::IServiceObject, ServiceImpl>::value, "Out<std::shared_ptr<ServiceImpl>> requires ServiceObject base.");
template<typename ServiceImpl> requires std::derived_from<ServiceImpl, IServiceObject>
class Out<SharedPointer<ServiceImpl>> : public impl::OutObjectTag {
template<typename>
friend class Out;
public:
using ServiceImplType = ServiceImpl;
using Interface = ServiceImpl;
private:
cmif::ServiceObjectHolder *srv;
cmif::DomainObjectId *object_id;
impl::SharedPointerBase *m_out;
cmif::DomainObjectId *m_object_id;
private:
Out(impl::SharedPointerBase *p, cmif::DomainObjectId *o = nullptr) : m_out(p), m_object_id(o) { /* ... */ }
public:
Out(cmif::ServiceObjectHolder *s) : srv(s), object_id(nullptr) { /* ... */ }
Out(cmif::ServiceObjectHolder *s, cmif::DomainObjectId *o) : srv(s), object_id(o) { /* ... */ }
Out(const Out &rhs) : m_out(rhs.m_out), m_object_id(rhs.m_object_id) { /* ... */ }
void SetValue(std::shared_ptr<ServiceImpl> &&s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) {
*this->srv = cmif::ServiceObjectHolder(std::move(s));
Out(SharedPointer<ServiceImpl> *out, cmif::DomainObjectId *o = nullptr) : m_out(std::addressof(out->m_base)), m_object_id(o) { /* .... */ }
template<typename U> requires std::derived_from<U, ServiceImpl>
Out(Out<SharedPointer<U>> out) : m_out(out.m_out), m_object_id(out.m_object_id) { /* ... */ }
template<typename U> requires std::derived_from<U, ServiceImpl>
Out(SharedPointer<U> *out, cmif::DomainObjectId *o = nullptr) : m_out(std::addressof(out->m_base)), m_object_id(o) { /* .... */ }
void SetValue(SharedPointer<ServiceImpl> s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) {
*m_out = std::move(s.m_base);
if (new_object_id != cmif::InvalidDomainObjectId) {
AMS_ABORT_UNLESS(object_id != nullptr);
*this->object_id = new_object_id;
AMS_ABORT_UNLESS(m_object_id != nullptr);
*m_object_id = new_object_id;
}
}
template<typename U> requires std::derived_from<U, ServiceImpl>
void SetValue(SharedPointer<U> s, cmif::DomainObjectId new_object_id = cmif::InvalidDomainObjectId) {
*m_out = std::move(s.m_base);
if (new_object_id != cmif::InvalidDomainObjectId) {
AMS_ABORT_UNLESS(m_object_id != nullptr);
*m_object_id = new_object_id;
}
}
class DerefProxy {
template<typename>
friend class Out;
private:
Out &m_target;
private:
explicit DerefProxy(Out &t) : m_target(t) { /* ... */ }
public:
DerefProxy &operator=(SharedPointer<ServiceImpl> p) {
m_target.SetValue(std::move(p));
return *this;
}
template<typename U> requires std::derived_from<U, ServiceImpl>
DerefProxy &operator=(SharedPointer<U> p) {
m_target.SetValue(std::move(p));
return *this;
}
};
DerefProxy operator *() {
return DerefProxy(*this);
}
template<typename U>
Out<SharedPointer<U>> DownCast() {
return Out<SharedPointer<U>>(m_out, m_object_id);
}
};
}
@@ -149,8 +193,8 @@ namespace ams::sf::impl {
struct IsInObject : public std::false_type{};
template<typename T>
struct IsInObject<std::shared_ptr<T>> : public std::true_type {
static_assert(std::is_base_of<sf::IServiceObject, T>::value, "Invalid IsInObject<std::shared_ptr<T>>");
struct IsInObject<sf::SharedPointer<T>> : public std::true_type {
static_assert(std::is_base_of<sf::IServiceObject, T>::value, "Invalid IsInObject<sf::SharedPointer<T>>");
};
template<typename T>
@@ -628,6 +672,7 @@ namespace ams::sf::impl {
private:
std::array<cmif::ServiceObjectHolder, NumInObjects> in_object_holders;
std::array<cmif::ServiceObjectHolder, NumOutObjects> out_object_holders;
std::array<TYPED_STORAGE(SharedPointer<sf::IServiceObject>), NumOutObjects> out_shared_pointers;
std::array<cmif::DomainObjectId, NumOutObjects> out_object_ids;
public:
constexpr InOutObjectHolder() : in_object_holders(), out_object_holders() {
@@ -655,8 +700,8 @@ namespace ams::sf::impl {
static_assert(std::tuple_size<ServiceImplTuple>::value == NumInObjects);
#define _SF_IN_OUT_HOLDER_VALIDATE_IN_OBJECT(n) do { \
if constexpr (NumInObjects > n) { \
using SharedPtrToServiceImplType = typename std::tuple_element<n, ServiceImplTuple>::type; \
using ServiceImplType = typename SharedPtrToServiceImplType::element_type; \
using SharedPointerType = typename std::tuple_element<n, ServiceImplTuple>::type; \
using ServiceImplType = typename SharedPointerType::Interface; \
R_UNLESS((this->in_object_holders[n].template IsServiceObjectValid<ServiceImplType>()), sf::cmif::ResultInvalidInObject()); \
} \
} while (0)
@@ -672,15 +717,21 @@ namespace ams::sf::impl {
return ResultSuccess();
}
template<size_t Index, typename ServiceImpl>
std::shared_ptr<ServiceImpl> GetInObject() const {
/* We know from ValidateInObjects() that this will succeed always. */
return this->in_object_holders[Index].template GetServiceObject<ServiceImpl>();
template<size_t Index, typename Interface>
SharedPointer<Interface> *GetOutObjectSharedPointer() {
static_assert(sizeof(SharedPointer<Interface>) == sizeof(SharedPointer<sf::IServiceObject>));
return static_cast<SharedPointer<Interface> *>(static_cast<void *>(&out_shared_pointers[Index]));
}
template<size_t Index, typename ServiceImpl>
Out<std::shared_ptr<ServiceImpl>> GetOutObject() {
return Out<std::shared_ptr<ServiceImpl>>(&this->out_object_holders[Index], &this->out_object_ids[Index]);
template<size_t Index, typename Interface>
Out<SharedPointer<Interface>> GetOutObject() {
auto sp = new (GetOutObjectSharedPointer<Index, Interface>()) SharedPointer<Interface>;
return Out<SharedPointer<Interface>>(sp, &this->out_object_ids[Index]);
}
template<size_t Index, typename Interface>
void SetOutObject() {
this->out_object_holders[Index] = cmif::ServiceObjectHolder(std::move(*GetOutObjectSharedPointer<Index, Interface>()));
}
constexpr void SetOutObjects(const cmif::ServiceDispatchContext &ctx, const HipcRequest &response) {
@@ -985,10 +1036,10 @@ namespace ams::sf::impl {
}
} else if constexpr (Info.arg_type == ArgumentType::InObject) {
/* New InObject. */
return in_out_objects_holder.template GetInObject<Info.in_object_index, typename T::element_type>();
return in_out_objects_holder.template GetInObject<Info.in_object_index, typename T::Interface>();
} else if constexpr (Info.arg_type == ArgumentType::OutObject) {
/* New OutObject. */
return in_out_objects_holder.template GetOutObject<Info.out_object_index, typename T::ServiceImplType>();
return in_out_objects_holder.template GetOutObject<Info.out_object_index, typename T::Interface>();
} else if constexpr (Info.arg_type == ArgumentType::Buffer) {
/* Buffers were already processed earlier. */
if constexpr (sf::IsLargeData<T>) {
@@ -1124,6 +1175,21 @@ namespace ams::sf::impl {
out_handles_holder.CopyTo(response, runtime_metadata.GetOutObjectCount());
/* Set output objects. */
#define _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(n) do { \
if constexpr (n < CommandMeta::NumOutObjects) { \
in_out_objects_holder.template SetOutObject<n, typename std::tuple_element_t<n, typename CommandMeta::OutObjects>::Interface>(); \
} \
} while (0)
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(0);
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(1);
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(2);
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(3);
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(4);
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(5);
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(6);
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(7);
_SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT(8);
#undef _SF_IMPL_PROCESSOR_MARSHAL_OUT_OBJECT
in_out_objects_holder.SetOutObjects(ctx, response);
return ResultSuccess();

View File

@@ -1,327 +0,0 @@
/*
* Copyright (c) 2018-2020 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 <vapours.hpp>
namespace ams::sf::impl {
template<typename T>
concept ServiceCommandResult = std::same_as<::ams::Result, T> || std::same_as<void, T>;
template<auto F, typename ...Arguments>
concept Invokable = requires (Arguments &&... args) {
{ F(std::forward<Arguments>(args)...) };
};
struct FunctionTraits {
public:
template<typename R, typename... A>
static std::tuple<A...> GetArgsImpl(R(A...));
};
template<auto F>
using FunctionArgsType = decltype(FunctionTraits::GetArgsImpl(F));
template<typename Class, typename Return, typename ArgsTuple>
struct ClassFunctionPointerHelper;
template<typename Class, typename Return, typename... Arguments>
struct ClassFunctionPointerHelper<Class, Return, std::tuple<Arguments...>> {
using Type = Return (*)(Class *, Arguments &&...);
};
template<typename Class, typename Return, typename ArgsTuple>
using ClassFunctionPointer = typename ClassFunctionPointerHelper<Class, Return, ArgsTuple>::Type;
template<typename T>
struct TypeTag{};
#define AMS_SF_IMPL_HELPER_FUNCTION_NAME_IMPL(CLASSNAME, FUNCNAME, SUFFIX) \
__ams_sf_impl_helper_##CLASSNAME##_##FUNCNAME##_##SUFFIX
#define AMS_SF_IMPL_HELPER_FUNCTION_NAME(CLASSNAME, FUNCNAME) \
AMS_SF_IMPL_HELPER_FUNCTION_NAME_IMPL(CLASSNAME, FUNCNAME, intf)
#define AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, FUNCNAME) \
::ams::sf::impl::FunctionArgsType<AMS_SF_IMPL_HELPER_FUNCTION_NAME(CLASSNAME, FUNCNAME)>
#define AMS_SF_IMPL_CONCEPT_HELPER_FUNCTION_NAME(CLASSNAME, FUNCNAME) \
AMS_SF_IMPL_HELPER_FUNCTION_NAME_IMPL(CLASSNAME, FUNCNAME, intf_for_concept)
#define AMS_SF_IMPL_DECLARE_HELPER_FUNCTIONS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
static void AMS_SF_IMPL_HELPER_FUNCTION_NAME(CLASSNAME, NAME) ARGS { __builtin_unreachable(); } \
template<typename T, typename... Arguments> \
requires std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> \
static auto AMS_SF_IMPL_CONCEPT_HELPER_FUNCTION_NAME(CLASSNAME, NAME) (T &t, std::tuple<Arguments...> a) { \
return [&]<size_t... Ix>(std::index_sequence<Ix...>) { \
return t.NAME(std::forward<typename std::tuple_element<Ix, decltype(a)>::type>(std::get<Ix>(a))...); \
}(std::make_index_sequence<sizeof...(Arguments)>()); \
}
#define AMS_SF_IMPL_DECLARE_HELPERS(CLASSNAME, CMD_MACRO) \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_HELPER_FUNCTIONS)
#define AMS_SF_IMPL_DECLARE_CONCEPT_REQUIREMENT(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
{ AMS_SF_IMPL_CONCEPT_HELPER_FUNCTION_NAME(CLASSNAME, NAME) (impl, std::declval<AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)>()) } -> ::ams::sf::impl::ServiceCommandResult;
#define AMS_SF_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \
template<typename Impl> \
concept Is##CLASSNAME = requires (Impl &impl) { \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_CONCEPT_REQUIREMENT) \
};
#define AMS_SF_IMPL_FUNCTION_POINTER_TYPE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
::ams::sf::impl::ClassFunctionPointer<CLASSNAME, RETURN, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)>
#define AMS_SF_IMPL_DECLARE_FUNCTION_POINTER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
AMS_SF_IMPL_FUNCTION_POINTER_TYPE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) NAME;
#define AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
template<typename ...Arguments> \
requires std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> \
RETURN Invoke##NAME##ByCommandTable (Arguments &&... args) { \
return this->cmd_table->NAME(this, std::forward<Arguments>(args)...); \
} \
template<typename ...Arguments> \
requires (::ams::sf::impl::Invokable<AMS_SF_IMPL_HELPER_FUNCTION_NAME(CLASSNAME, NAME), Arguments...> && \
std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)>) \
ALWAYS_INLINE RETURN NAME (Arguments &&... args) { \
return this->Invoke##NAME##ByCommandTable(std::forward<Arguments>(args)...); \
} \
template<typename ...Arguments> \
requires (::ams::sf::impl::Invokable<AMS_SF_IMPL_HELPER_FUNCTION_NAME(CLASSNAME, NAME), Arguments...> && \
!std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)>) \
ALWAYS_INLINE RETURN NAME (Arguments &&... args) { \
return [this] <typename... CorrectArguments, typename... PassedArguments> ALWAYS_INLINE_LAMBDA (::ams::sf::impl::TypeTag<std::tuple<CorrectArguments...>>, PassedArguments &&...args_) -> RETURN { \
return this->template NAME<CorrectArguments...>(std::forward<CorrectArguments>(args_)...); \
}(::ams::sf::impl::TypeTag<AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)>{}, std::forward<Arguments>(args)...); \
}
#define AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_INVOKER_HOLDER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
template<typename ...Arguments> \
requires std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> \
static RETURN NAME##Invoker (CLASSNAME *_this, Arguments &&... args) { \
return static_cast<ImplHolder *>(_this)->NAME(std::forward<Arguments>(args)...); \
}
#define AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_INVOKER_POINTER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
template<typename ...Arguments> \
requires std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> \
static RETURN NAME##Invoker (CLASSNAME *_this, Arguments &&... args) { \
return static_cast<ImplPointer *>(_this)->NAME(std::forward<Arguments>(args)...); \
}
#define AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_INVOKER_SHARED_POINTER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
template<typename ...Arguments> \
requires std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> \
static RETURN NAME##Invoker (CLASSNAME *_this, Arguments &&... args) { \
return static_cast<ImplSharedPointer *>(_this)->NAME(std::forward<Arguments>(args)...); \
}
#define AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_IMPL(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
template<typename ...Arguments> \
requires (std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> && \
std::same_as<RETURN, decltype(impl.NAME(std::declval<Arguments>()...))>) \
RETURN NAME (Arguments &&... args) { \
return this->impl.NAME(std::forward<Arguments>(args)...); \
}
#define AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_IMPL_PTR(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
template<typename ...Arguments> \
requires (std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> && \
std::same_as<RETURN, decltype(impl->NAME(std::declval<Arguments>()...))>) \
RETURN NAME (Arguments &&... args) { \
return this->impl->NAME(std::forward<Arguments>(args)...); \
}
#define AMS_SF_IMPL_DEFINE_INTERFACE_IMPL_FUNCTION_POINTER_HOLDER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
template<typename A> struct NAME##FunctionPointerHolder; \
\
template<typename ...Arguments> \
requires std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> \
struct NAME##FunctionPointerHolder<std::tuple<Arguments...>> { \
static constexpr auto Value = static_cast<AMS_SF_IMPL_FUNCTION_POINTER_TYPE(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX)>(&NAME##Invoker<Arguments...>); \
};
#define AMS_SF_IMPL_DEFINE_INTERFACE_SERVICE_COMMAND_META_HOLDER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
template<typename ServiceImpl, typename A> struct NAME##ServiceCommandMetaHolder; \
\
template<typename ServiceImpl, typename ...Arguments> \
requires std::same_as<std::tuple<Arguments...>, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)> \
struct NAME##ServiceCommandMetaHolder<ServiceImpl, std::tuple<Arguments...>> { \
static constexpr auto Value = ::ams::sf::impl::MakeServiceCommandMeta<VERSION_MIN, VERSION_MAX, CMD_ID, &ServiceImpl::template Invoke##NAME##ByCommandTable<Arguments...>, RETURN, CLASSNAME, Arguments...>(); \
};
#define AMS_SF_IMPL_DEFINE_INTERFACE_COMMAND_POINTER_TABLE_MEMBER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
.NAME = NAME##FunctionPointerHolder<AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)>::Value,
#define AMS_SF_IMPL_DEFINE_CMIF_SERVICE_COMMAND_META_TABLE_ENTRY(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
NAME##ServiceCommandMetaHolder<ServiceImpl, AMS_SF_IMPL_HELPER_FUNCTION_ARGS(CLASSNAME, NAME)>::Value,
template<typename T>
struct Print;
#define AMS_SF_IMPL_DEFINE_CLASS(BASECLASS, CLASSNAME, CMD_MACRO) \
class CLASSNAME : public BASECLASS { \
NON_COPYABLE(CLASSNAME); \
NON_MOVEABLE(CLASSNAME); \
private: \
struct CommandPointerTable { \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_FUNCTION_POINTER) \
}; \
private: \
const CommandPointerTable * const cmd_table; \
private: \
CLASSNAME() = delete; \
protected: \
constexpr CLASSNAME(const CommandPointerTable *ct) \
: cmd_table(ct) { /* ... */ } \
virtual ~CLASSNAME() { /* ... */ } \
public: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION) \
private: \
template<typename S, typename T> \
requires ((std::same_as<CLASSNAME, S> && !std::same_as<CLASSNAME, T>&& Is##CLASSNAME<T>) && \
(::ams::sf::IsMitmServiceObject<S> == ::ams::sf::IsMitmServiceImpl<T>)) \
struct ImplGenerator { \
public: \
class ImplHolder : public S { \
private: \
T impl; \
public: \
template<typename... Args> requires std::constructible_from<T, Args...> \
constexpr ImplHolder(Args &&... args) \
: S(std::addressof(CommandPointerTableImpl)), impl(std::forward<Args>(args)...) \
{ \
/* ... */ \
} \
ALWAYS_INLINE T &GetImpl() { return this->impl; } \
ALWAYS_INLINE const T &GetImpl() const { return this->impl; } \
\
template<typename U = S> requires ::ams::sf::IsMitmServiceObject<S> && std::same_as<U, S> \
static ALWAYS_INLINE bool ShouldMitm(os::ProcessId p, ncm::ProgramId r) { return T::ShouldMitm(p, r); } \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_INVOKER_HOLDER) \
public: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_IMPL) \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_IMPL_FUNCTION_POINTER_HOLDER) \
public: \
static constexpr CommandPointerTable CommandPointerTableImpl = { \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_COMMAND_POINTER_TABLE_MEMBER) \
}; \
}; \
static_assert(Is##CLASSNAME<ImplHolder>); \
\
class ImplPointer : public S { \
private: \
T *impl; \
public: \
constexpr ImplPointer(T *t) \
: S(std::addressof(CommandPointerTableImpl)), impl(t) \
{ \
/* ... */ \
} \
ALWAYS_INLINE T &GetImpl() { return *this->impl; } \
ALWAYS_INLINE const T &GetImpl() const { return *this->impl; } \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_INVOKER_POINTER) \
public: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_IMPL_PTR) \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_IMPL_FUNCTION_POINTER_HOLDER) \
public: \
static constexpr CommandPointerTable CommandPointerTableImpl = { \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_COMMAND_POINTER_TABLE_MEMBER) \
}; \
}; \
\
class ImplSharedPointer : public S { \
private: \
std::shared_ptr<T> impl; \
public: \
constexpr ImplSharedPointer(std::shared_ptr<T> &&t) \
: S(std::addressof(CommandPointerTableImpl)), impl(std::move(t)) \
{ \
/* ... */ \
} \
ALWAYS_INLINE T &GetImpl() { return *this->impl; } \
ALWAYS_INLINE const T &GetImpl() const { return *this->impl; } \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_INVOKER_SHARED_POINTER) \
public: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DECLARE_INTERFACE_FUNCTION_IMPL_PTR) \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_IMPL_FUNCTION_POINTER_HOLDER) \
public: \
static constexpr CommandPointerTable CommandPointerTableImpl = { \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_COMMAND_POINTER_TABLE_MEMBER) \
}; \
}; \
static_assert(Is##CLASSNAME<ImplHolder>); \
}; \
private: \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_INTERFACE_SERVICE_COMMAND_META_HOLDER) \
public: \
template<typename T> requires (!std::same_as<CLASSNAME, T>&& Is##CLASSNAME<T>) \
using ImplHolder = typename ImplGenerator<CLASSNAME, T>::ImplHolder; \
\
template<typename T> requires (!std::same_as<CLASSNAME, T>&& Is##CLASSNAME<T>) \
using ImplPointer = typename ImplGenerator<CLASSNAME, T>::ImplPointer; \
\
template<typename T> requires (!std::same_as<CLASSNAME, T>&& Is##CLASSNAME<T> && \
std::derived_from<T, std::enable_shared_from_this<T>>) \
using ImplSharedPointer = typename ImplGenerator<CLASSNAME, T>::ImplSharedPointer; \
\
AMS_SF_CMIF_IMPL_DEFINE_SERVICE_DISPATCH_TABLE { \
CMD_MACRO(CLASSNAME, AMS_SF_IMPL_DEFINE_CMIF_SERVICE_COMMAND_META_TABLE_ENTRY) \
}; \
};
#define AMS_SF_METHOD_INFO_6(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS) \
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, hos::Version_Min, hos::Version_Max)
#define AMS_SF_METHOD_INFO_7(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN) \
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, hos::Version_Max)
#define AMS_SF_METHOD_INFO_8(CLASSNAME, HANDLER, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
HANDLER(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX)
#define AMS_SF_METHOD_INFO_X(_, _0, _1, _2, _3, _4, _5, _6, _7, FUNC, ...) FUNC
#define AMS_SF_METHOD_INFO(...) \
AMS_SF_METHOD_INFO_X(, ## __VA_ARGS__, AMS_SF_METHOD_INFO_8(__VA_ARGS__), AMS_SF_METHOD_INFO_7(__VA_ARGS__), AMS_SF_METHOD_INFO_6(__VA_ARGS__))
#define AMS_SF_DEFINE_INTERFACE(CLASSNAME, CMD_MACRO) \
AMS_SF_IMPL_DECLARE_HELPERS(CLASSNAME,CMD_MACRO) \
AMS_SF_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \
AMS_SF_IMPL_DEFINE_CLASS( ::ams::sf::IServiceObject, CLASSNAME, CMD_MACRO) \
static_assert(Is##CLASSNAME<CLASSNAME>);
#define AMS_SF_DEFINE_MITM_INTERFACE(CLASSNAME, CMD_MACRO) \
AMS_SF_IMPL_DECLARE_HELPERS(CLASSNAME,CMD_MACRO) \
AMS_SF_IMPL_DEFINE_CONCEPT(CLASSNAME, CMD_MACRO) \
AMS_SF_IMPL_DEFINE_CLASS(::ams::sf::IMitmServiceObject, CLASSNAME, CMD_MACRO) \
static_assert(Is##CLASSNAME<CLASSNAME>);
#define AMS_SF_IMPL_DECLARE_INTERFACE_METHODS(CLASSNAME, CMD_ID, RETURN, NAME, ARGS, VERSION_MIN, VERSION_MAX) \
RETURN NAME ARGS;
#define AMS_SF_DECLARE_INTERFACE_METHODS(CMD_MACRO) \
CMD_MACRO(_, AMS_SF_IMPL_DECLARE_INTERFACE_METHODS)
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 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 <vapours.hpp>
namespace ams::sf::impl {
template<typename Interface, typename Base, typename ImplHolder, typename ImplGetter, typename Root>
class ImplTemplateBaseT;
template<typename Interface, typename Base, typename ImplHolder, typename ImplGetter>
class ImplTemplateBase : public ImplTemplateBaseT<Interface, Base, ImplHolder, ImplGetter, Interface> {
private:
using BaseImpl = ImplTemplateBaseT<Interface, Base, ImplHolder, ImplGetter, Interface>;
public:
using BaseImpl::BaseImpl;
};
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2018-2020 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 <vapours.hpp>
namespace ams::sf::impl {
class ServiceObjectImplBase2 {
private:
std::atomic<u32> m_ref_count;
protected:
constexpr ServiceObjectImplBase2() : m_ref_count(1) { /* ... */ }
void AddReferenceImpl() {
const auto prev = m_ref_count.fetch_add(1);
AMS_ABORT_UNLESS(prev < std::numeric_limits<u32>::max());
}
bool ReleaseImpl() {
const auto prev = m_ref_count.fetch_sub(1);
AMS_ABORT_UNLESS(prev != 0);
return prev == 1;
}
};
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2018-2020 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 <vapours.hpp>
namespace ams::sf {
namespace impl {
struct StatelessDummyAllocator;
}
template<typename A>
class StatelessAllocationPolicy {
public:
static constexpr bool HasStatefulAllocator = false;
using Allocator = impl::StatelessDummyAllocator;
template<typename>
using StatelessAllocator = A;
template<typename>
static void *AllocateAligned(size_t size, size_t align) {
return A().Allocate(size);
}
template<typename>
static void DeallocateAligned(void *ptr, size_t size, size_t align) {
A().Deallocate(ptr, size);
}
};
template<template<typename> typename A>
class StatelessTypedAllocationPolicy {
public:
static constexpr bool HasStatefulAllocator = false;
using Allocator = impl::StatelessDummyAllocator;
template<typename T>
using StatelessAllocator = A<T>;
template<typename T>
static void *AllocateAligned(size_t size, size_t align) {
return StatelessAllocator<T>().Allocate(size);
}
template<typename T>
static void DeallocateAligned(void *ptr, size_t size, size_t align) {
StatelessAllocator<T>().Deallocate(ptr, size);
}
};
template<typename A>
class StatefulAllocationPolicy {
public:
static constexpr bool HasStatefulAllocator = true;
using Allocator = A;
static void *AllocateAligned(Allocator *allocator, size_t size, size_t align) {
return allocator->Allocate(size);
}
static void DeallocateAligned(Allocator *allocator, void *ptr, size_t size, size_t align) {
allocator->Deallocate(ptr, size);
}
};
template<typename T>
concept IsStatefulPolicy = T::HasStatefulAllocator;
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2018-2020 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/sf_allocation_policies.hpp>
namespace ams::sf {
namespace impl {
void *DefaultAllocateImpl(size_t size, size_t align, size_t offset);
void DefaultDeallocateImpl(void *ptr, size_t size, size_t align, size_t offset);
template<typename T>
class DefaultAllocationPolicyAllocator {
private:
struct Holder {
MemoryResource *allocator;
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
};
public:
void *Allocate(size_t size) {
AMS_ASSERT(size == sizeof(T));
return DefaultAllocateImpl(sizeof(Holder), alignof(Holder), offsetof(Holder, storage));
}
void Deallocate(void *ptr, size_t size) {
AMS_ASSERT(size == sizeof(T));
return DefaultDeallocateImpl(ptr, sizeof(Holder), alignof(Holder), offsetof(Holder, storage));
}
};
}
using DefaultAllocationPolicy = StatelessTypedAllocationPolicy<impl::DefaultAllocationPolicyAllocator>;
MemoryResource *GetGlobalDefaultMemoryResource();
MemoryResource *GetCurrentEffectiveMemoryResource();
MemoryResource *GetCurrentMemoryResource();
MemoryResource *GetNewDeleteMemoryResource();
MemoryResource *SetGlobalDefaultMemoryResource(MemoryResource *mr);
MemoryResource *SetCurrentMemoryResource(MemoryResource *mr);
class ScopedCurrentMemoryResourceSetter {
NON_COPYABLE(ScopedCurrentMemoryResourceSetter);
NON_MOVEABLE(ScopedCurrentMemoryResourceSetter);
private:
MemoryResource *m_prev;
public:
explicit ScopedCurrentMemoryResourceSetter(MemoryResource *mr);
~ScopedCurrentMemoryResourceSetter();
};
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2018-2020 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/sf_allocation_policies.hpp>
namespace ams::sf {
struct ExpHeapAllocator {
using Policy = StatefulAllocationPolicy<ExpHeapAllocator>;
lmem::HeapHandle _handle;
os::SdkMutexType _mutex;
void Attach(lmem::HeapHandle h) {
this->_handle = h;
os::InitializeSdkMutex(std::addressof(this->_mutex));
}
void Detach() {
this->_handle = 0;
}
void *Allocate(size_t size) {
os::LockSdkMutex(std::addressof(this->_mutex));
auto ptr = lmem::AllocateFromExpHeap(this->_handle, size);
os::UnlockSdkMutex(std::addressof(this->_mutex));
return ptr;
}
void Deallocate(void *ptr, size_t size) {
os::LockSdkMutex(std::addressof(this->_mutex));
lmem::FreeToExpHeap(this->_handle, ptr);
os::UnlockSdkMutex(std::addressof(this->_mutex));
}
};
static_assert(util::is_pod<ExpHeapAllocator>::value);
template<size_t Size, typename Tag = void>
struct ExpHeapStaticAllocator {
using Policy = StatelessAllocationPolicy<ExpHeapStaticAllocator<Size, Tag>>;
struct Globals {
ExpHeapAllocator allocator;
typename std::aligned_storage<Size == 0 ? 1 : Size>::type buffer;
};
static constinit inline Globals _globals;
static void Initialize(int option) {
_globals.allocator.Attach(lmem::CreateExpHeap(std::addressof(_globals.buffer), Size, option));
}
static void Initialize(lmem::HeapHandle handle) {
_globals.allocator.Attach(handle);
}
static void *Allocate(size_t size) {
return _globals.allocator.Allocate(size);
}
static void Deallocate(void *ptr, size_t size) {
return _globals.allocator.Deallocate(ptr, size);
}
};
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2018-2020 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/sf_allocation_policies.hpp>
namespace ams::sf {
struct MemoryResourceAllocationPolicy {
static constexpr bool HasStatefulAllocator = true;
using Allocator = MemoryResource;
static void *AllocateAligned(MemoryResource *mr, size_t size, size_t align) {
return mr->allocate(size, align);
}
static void DeallocateAligned(MemoryResource *mr, void *ptr, size_t size, size_t align) {
return mr->deallocate(ptr, size, align);
}
};
template<typename T>
struct MemoryResourceStaticAllocator {
static constinit inline MemoryResource *g_memory_resource = nullptr;
static constexpr void Initialize(MemoryResource *mr) {
g_memory_resource = mr;
}
struct Policy {
static constexpr bool HasStatefulAllocator = false;
using Allocator = MemoryResource;
template<typename>
using StatelessAllocator = Allocator;
template<typename>
static void *AllocateAligned(size_t size, size_t align) {
return g_memory_resource->allocate(size, align);
}
template<typename>
static void DeallocateAligned(void *ptr, size_t size, size_t align) {
g_memory_resource->deallocate(ptr, size, align);
}
};
};
}

View File

@@ -0,0 +1,352 @@
/*
* Copyright (c) 2018-2020 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 <vapours.hpp>
#include <stratosphere/sf/sf_common.hpp>
#include <stratosphere/sf/impl/sf_impl_template_base.hpp>
#include <stratosphere/sf/sf_object_impl_factory.hpp>
#include <stratosphere/sf/sf_memory_resource.hpp>
#include <stratosphere/sf/sf_default_allocation_policy.hpp>
namespace ams::sf {
namespace impl {
template<typename>
struct IsSmartPointer : public std::false_type{};
template<typename T>
struct IsSmartPointer<SharedPointer<T>> : public std::true_type{};
template<typename T>
struct IsSmartPointer<std::shared_ptr<T>> : public std::true_type{};
template<typename T, typename D>
struct IsSmartPointer<std::unique_ptr<T, D>> : public std::true_type{};
template<typename Impl>
struct UnmanagedEmplaceImplHolderBaseGetter {
using Type = Impl;
};
template<typename Impl> requires (std::is_abstract<Impl>::value )
struct UnmanagedEmplaceImplHolderBaseGetter<Impl> {
class Impl2 : public Impl {
public:
using Impl::Impl;
private:
constexpr virtual void AddReference() override { /* ... */ }
constexpr virtual void Release() override { /* ... */ }
};
using Type = Impl2;
};
template<typename Impl>
class UnmanagedEmplacedImplHolder {
template<typename, typename, typename, typename, typename>
friend class impl::ImplTemplateBaseT;
private:
using Impl2 = typename UnmanagedEmplaceImplHolderBaseGetter<Impl>::Type;
static_assert(!std::is_abstract<Impl2>::value);
private:
Impl2 m_impl;
private:
template<typename... Args>
constexpr explicit UnmanagedEmplacedImplHolder(Args &&... args) : m_impl(std::forward<Args>(args)...) { /* ... */ }
public:
static constexpr Impl *GetImplPointer(UnmanagedEmplacedImplHolder *holder) {
return std::addressof(holder->m_impl);
}
};
template<typename Impl>
class EmplacedImplHolder : private Impl {
template<typename, typename, typename, typename, typename>
friend class impl::ImplTemplateBaseT;
private:
template<typename... Args>
constexpr explicit EmplacedImplHolder(Args &&... args) : Impl(std::forward<Args>(args)...) { /* ... */ }
public:
static constexpr Impl *GetImplPointer(EmplacedImplHolder *holder) {
return holder;
}
template<typename Interface>
static constexpr Impl *GetEmplacedImplPointerImpl(const SharedPointer<Interface> &sp) {
using Base = impl::ImplTemplateBase<Interface, Interface, EmplacedImplHolder, EmplacedImplHolder>;
return static_cast<Base *>(sp.Get());
}
};
template<typename Impl> requires (IsSmartPointer<Impl>::value)
class EmplacedImplHolder<Impl> : private Impl {
template<typename, typename, typename, typename, typename>
friend class impl::ImplTemplateBaseT;
private:
template<typename... Args>
constexpr explicit EmplacedImplHolder(Args &&... args) : Impl(std::forward<Args>(args)...) { /* ... */ }
public:
static constexpr auto *GetImplPointer(EmplacedImplHolder *holder) {
return static_cast<Impl *>(holder)->operator ->();
}
template<typename Interface>
static constexpr Impl *GetEmplacedImplPointerImpl(const SharedPointer<Interface> &sp) {
using Base = impl::ImplTemplateBase<Interface, Interface, EmplacedImplHolder, EmplacedImplHolder>;
return static_cast<Base *>(sp.Get());
}
};
template<typename T>
using SmartPointerHolder = EmplacedImplHolder<T>;
template<typename T>
class ManagedPointerHolder {
template<typename, typename, typename, typename, typename>
friend class impl::ImplTemplateBaseT;
private:
T *m_p;
private:
constexpr explicit ManagedPointerHolder(T *p) : m_p(p) { /* ... */ }
constexpr ~ManagedPointerHolder() { m_p->Release(); }
static constexpr T *GetImplPointer(ManagedPointerHolder *holder) {
return holder->m_p;
}
};
template<typename T>
class UnmanagedPointerHolder {
template<typename, typename, typename, typename, typename>
friend class impl::ImplTemplateBaseT;
private:
T *m_p;
private:
constexpr explicit UnmanagedPointerHolder(T *p) : m_p(p) { /* ... */ }
static constexpr T *GetImplPointer(UnmanagedPointerHolder *holder) {
return holder->m_p;
}
};
}
template<typename Interface, typename Impl>
class UnmanagedServiceObject final : public impl::ImplTemplateBase<Interface, Interface, impl::UnmanagedEmplacedImplHolder<Impl>, impl::UnmanagedEmplacedImplHolder<Impl>> {
private:
using ImplBase = impl::ImplTemplateBase<Interface, Interface, impl::UnmanagedEmplacedImplHolder<Impl>, impl::UnmanagedEmplacedImplHolder<Impl>>;
public:
using ImplBase::ImplBase;
constexpr virtual void AddReference() override { /* ... */ }
constexpr virtual void Release() override { /* ... */ }
constexpr Impl &GetImpl() { return impl::UnmanagedEmplacedImplHolder<Impl>::GetImplPointer(this); }
constexpr SharedPointer<Interface> GetShared() { return SharedPointer<Interface>(this, false); }
};
template<typename Interface, typename T>
class UnmanagedServiceObjectByPointer final : public impl::ImplTemplateBase<Interface, Interface, impl::UnmanagedPointerHolder<T>, impl::UnmanagedPointerHolder<T>> {
private:
using ImplBase = impl::ImplTemplateBase<Interface, Interface, impl::UnmanagedPointerHolder<T>, impl::UnmanagedPointerHolder<T>>;
public:
constexpr explicit UnmanagedServiceObjectByPointer(T *ptr) : ImplBase(ptr) { /* ... */ }
constexpr virtual void AddReference() override { /* ... */ }
constexpr virtual void Release() override { /* ... */ }
constexpr SharedPointer<Interface> GetShared() { return SharedPointer<Interface>(this, false); }
};
template<typename Policy>
class ObjectFactory;
template<typename Interface, typename Impl>
class EmplacedRef : public SharedPointer<Interface> {
template<typename> friend class ObjectFactory;
private:
constexpr explicit EmplacedRef(Interface *ptr, bool incref) : SharedPointer<Interface>(ptr, incref) { /* ... */ }
public:
constexpr EmplacedRef() { /* ... */ }
constexpr Impl &GetImpl() const {
return *impl::EmplacedImplHolder<Impl>::template GetEmplacedImplPointerImpl<Interface>(*this);
}
};
template<typename Policy> requires (!IsStatefulPolicy<Policy>)
class ObjectFactory<Policy> {
private:
template<typename Interface, typename Holder, typename T>
static constexpr SharedPointer<Interface> CreateSharedForPointer(T t) {
using Base = impl::ImplTemplateBase<Interface, Interface, Holder, Holder>;
return SharedPointer<Interface>(ObjectImplFactory<Base, Policy>::Create(std::forward<T>(t)), false);
}
public:
template<typename Interface, typename Impl, typename... Args>
static constexpr EmplacedRef<Interface, Impl> CreateSharedEmplaced(Args &&... args) {
using Base = impl::ImplTemplateBase<Interface, Interface, impl::EmplacedImplHolder<Impl>, impl::EmplacedImplHolder<Impl>>;
return EmplacedRef<Interface, Impl>(ObjectImplFactory<Base, Policy>::Create(std::forward<Args>(args)...), false);
}
template<typename T, typename... Args>
static constexpr SharedPointer<T> CreateUserSharedObject(Args &&... args) {
return SharedPointer<T>(ObjectImplFactory<T, Policy>::Create(std::forward<Args>(args)...), false);
}
template<typename Impl, typename Interface>
static constexpr Impl *GetEmplacedImplPointer(const SharedPointer<Interface> &sp) {
return impl::EmplacedImplHolder<Impl>::template GetEmplacedImplPointerImpl<Interface>(sp);
}
template<typename Interface, typename Smart>
static constexpr SharedPointer<Interface> CreateShared(Smart &&sp) {
return CreateSharedForPointer<Interface, impl::SmartPointerHolder<typename std::decay<decltype(sp)>::type>>(std::forward<Smart>(sp));
}
template<typename Interface, typename T>
static constexpr SharedPointer<Interface> CreateShared(T *p) {
return CreateSharedForPointer<Interface, impl::ManagedPointerHolder<T>>(p);
}
template<typename Interface, typename T>
static constexpr SharedPointer<Interface> CreateSharedWithoutManagement(T *p) {
return CreateSharedForPointer<Interface, impl::UnmanagedPointerHolder<T>>(p);
}
};
template<typename Policy> requires (IsStatefulPolicy<Policy>)
class ObjectFactory<Policy> {
public:
using Allocator = typename Policy::Allocator;
private:
template<typename Interface, typename Holder, typename T>
static constexpr SharedPointer<Interface> CreateSharedForPointer(Allocator *a, T t) {
using Base = impl::ImplTemplateBase<Interface, Interface, Holder, Holder>;
return SharedPointer<Interface>(ObjectImplFactory<Base, Policy>::Create(a, std::forward<T>(t)), false);
}
public:
template<typename Interface, typename Impl, typename... Args>
static constexpr EmplacedRef<Interface, Impl> CreateSharedEmplaced(Allocator *a, Args &&... args) {
using Base = impl::ImplTemplateBase<Interface, Interface, impl::EmplacedImplHolder<Impl>, impl::EmplacedImplHolder<Impl>>;
return EmplacedRef<Interface, Impl>(ObjectImplFactory<Base, Policy>::Create(a, std::forward<Args>(args)...), false);
}
template<typename T, typename... Args>
static constexpr SharedPointer<T> CreateUserSharedObject(Allocator *a, Args &&... args) {
return SharedPointer<T>(ObjectImplFactory<T, Policy>::Create(a, std::forward<Args>(args)...), false);
}
template<typename Impl, typename Interface>
static constexpr Impl *GetEmplacedImplPointer(const SharedPointer<Interface> &sp) {
return impl::EmplacedImplHolder<Impl>::template GetEmplacedImplPointerImpl<Interface>(sp);
}
template<typename Interface, typename Smart>
static constexpr SharedPointer<Interface> CreateShared(Allocator *a, Smart &&sp) {
return CreateSharedForPointer<Interface, impl::SmartPointerHolder<typename std::decay<decltype(sp)>::type>>(a, std::forward<Smart>(sp));
}
template<typename Interface, typename T>
static constexpr SharedPointer<Interface> CreateShared(Allocator *a, T *p) {
return CreateSharedForPointer<Interface, impl::ManagedPointerHolder<T>>(a, p);
}
template<typename Interface, typename T>
static constexpr SharedPointer<Interface> CreateSharedWithoutManagement(Allocator *a, T *p) {
return CreateSharedForPointer<Interface, impl::UnmanagedPointerHolder<T>>(a, p);
}
};
template<typename Policy>
class StatefulObjectFactory {
public:
using Allocator = typename Policy::Allocator;
private:
using StaticObjectFactory = ObjectFactory<Policy>;
private:
Allocator *m_allocator;
public:
constexpr explicit StatefulObjectFactory(Allocator *a) : m_allocator(a) { /* ... */ }
template<typename Interface, typename Impl, typename... Args>
constexpr EmplacedRef<Interface, Impl> CreateSharedEmplaced(Args &&... args) {
return StaticObjectFactory::template CreateSharedEmplaced<Interface, Impl>(m_allocator, std::forward<Args>(args)...);
}
template<typename Impl, typename Interface>
static constexpr Impl *GetEmplacedImplPointer(const SharedPointer<Interface> &sp) {
return StaticObjectFactory::template GetEmplacedImplPointer<Impl, Interface>(sp);
}
template<typename Interface, typename Smart>
constexpr SharedPointer<Interface> CreateShared(Allocator *a, Smart &&sp) {
return StaticObjectFactory::template CreateShared<Interface>(m_allocator, std::forward<Smart>(sp));
}
template<typename Interface, typename T>
constexpr SharedPointer<Interface> CreateShared(Allocator *a, T *p) {
return StaticObjectFactory::template CreateShared<Interface>(m_allocator, p);
}
template<typename Interface, typename T>
constexpr SharedPointer<Interface> CreateSharedWithoutManagement(Allocator *a, T *p) {
return StaticObjectFactory::template CreateSharedWithoutManagement<Interface>(m_allocator, p);
}
};
using DefaultObjectFactory = ObjectFactory<DefaultAllocationPolicy>;
using MemoryResourceObjectFactory = ObjectFactory<MemoryResourceAllocationPolicy>;
template<typename Interface, typename Impl, typename... Args>
inline EmplacedRef<Interface, Impl> CreateSharedObjectEmplaced(Args &&... args) {
return DefaultObjectFactory::CreateSharedEmplaced<Interface, Impl>(std::forward<Args>(args)...);
}
template<typename Interface, typename Impl, typename... Args>
inline EmplacedRef<Interface, Impl> CreateSharedObjectEmplaced(MemoryResource *mr, Args &&... args) {
return MemoryResourceObjectFactory::CreateSharedEmplaced<Interface, Impl>(mr, std::forward<Args>(args)...);
}
template<typename Interface, typename Smart>
inline SharedPointer<Interface> CreateSharedObject(Smart &&sp) {
return DefaultObjectFactory::CreateShared<Interface, Smart>(std::forward<Smart>(sp));
}
template<typename Interface, typename Smart>
inline SharedPointer<Interface> CreateSharedObject(MemoryResource *mr, Smart &&sp) {
return MemoryResourceObjectFactory::CreateShared<Interface, Smart>(mr, std::forward<Smart>(sp));
}
template<typename Interface, typename T>
inline SharedPointer<Interface> CreateSharedObject(T *ptr) {
return DefaultObjectFactory::CreateShared<Interface, T>(std::move(ptr));
}
template<typename Interface, typename T>
inline SharedPointer<Interface> CreateSharedObjectWithoutManagement(T *ptr) {
return DefaultObjectFactory::CreateSharedWithoutManagement<Interface, T>(std::move(ptr));
}
template<typename Interface, typename T>
inline SharedPointer<Interface> CreateSharedObjectWithoutManagement(MemoryResource *mr, T *ptr) {
return DefaultObjectFactory::CreateSharedWithoutManagement<Interface, T>(mr, std::move(ptr));
}
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright (c) 2018-2020 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 <vapours.hpp>
#include <stratosphere/sf/sf_common.hpp>
#include <stratosphere/sf/sf_allocation_policies.hpp>
#include <stratosphere/sf/impl/sf_service_object_impl.hpp>
namespace ams::sf {
namespace impl {
struct StatelessDummyAllocator{};
template<typename Base, typename Policy>
class ObjectImplFactoryWithStatelessAllocator {
public:
class Object;
using Allocator = StatelessDummyAllocator;
using StatelessAllocator = typename Policy::StatelessAllocator<Object>;
class Object final : private ::ams::sf::impl::ServiceObjectImplBase2, public Base {
NON_COPYABLE(Object);
NON_MOVEABLE(Object);
friend class ObjectImplFactoryWithStatelessAllocator;
private:
template<typename... Args>
explicit Object(Args &&... args) : Base(std::forward<Args>(args)...) { /* ... */ }
static void *operator new(size_t size) {
return Policy::template AllocateAligned<Object>(size, alignof(Object));
}
static void operator delete(void *ptr, size_t size) {
return Policy::template DeallocateAligned<Object>(ptr, size, alignof(Object));
}
static void *operator new(size_t size, Allocator *);
static void operator delete(void *ptr, Allocator *);
void DisposeImpl() {
delete this;
}
public:
void AddReference() {
ServiceObjectImplBase2::AddReferenceImpl();
}
void Release() {
if (ServiceObjectImplBase2::ReleaseImpl()) {
this->DisposeImpl();
}
}
Allocator *GetAllocator() const {
return nullptr;
}
};
template<typename... Args>
static Object *Create(Args &&... args) {
return new Object(std::forward<Args>(args)...);
}
template<typename... Args>
static Object *Create(Allocator *, Args &&... args) {
return new Object(std::forward<Args>(args)...);
}
};
template<typename Base, typename Policy>
class ObjectImplFactoryWithStatefulAllocator {
public:
using Allocator = typename Policy::Allocator;
class Object final : private ::ams::sf::impl::ServiceObjectImplBase2, public Base {
NON_COPYABLE(Object);
NON_MOVEABLE(Object);
friend class ObjectImplFactoryWithStatefulAllocator;
private:
Allocator *m_allocator;
private:
template<typename... Args>
explicit Object(Args &&... args) : Base(std::forward<Args>(args)...) { /* ... */ }
static void *operator new(size_t size);
static void operator delete(void *ptr, size_t size) {
/* ... */
}
static void *operator new(size_t size, Allocator *a) {
return Policy::AllocateAligned(a, size, alignof(Object));
}
static void operator delete(void *ptr, Allocator *a) {
return Policy::DeallocateAligned(a, ptr, sizeof(Object), alignof(Object));
}
void DisposeImpl() {
Allocator *a = this->GetAllocator();
this->~Object();
operator delete(this, a);
}
public:
void AddReference() {
ServiceObjectImplBase2::AddReferenceImpl();
}
void Release() {
if (ServiceObjectImplBase2::ReleaseImpl()) {
this->DisposeImpl();
}
}
Allocator *GetAllocator() const {
return m_allocator;
}
};
template<typename... Args>
static Object *Create(Allocator *a, Args &&... args) {
auto *ptr = new (a) Object(std::forward<Args>(args)...);
if (ptr != nullptr) {
ptr->m_allocator = a;
}
return ptr;
}
};
}
template<typename Base, typename Policy>
class ObjectImplFactory;
template<typename Base, typename Policy> requires (!IsStatefulPolicy<Policy>)
class ObjectImplFactory<Base, Policy> : public impl::ObjectImplFactoryWithStatelessAllocator<Base, Policy>{};
template<typename Base, typename Policy> requires (IsStatefulPolicy<Policy>)
class ObjectImplFactory<Base, Policy> : public impl::ObjectImplFactoryWithStatefulAllocator<Base, Policy>{};
}

View File

@@ -13,10 +13,9 @@
* 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 "sf_common.hpp"
#include "cmif/sf_cmif_pointer_and_size.hpp"
#include <stratosphere/sf/sf_common.hpp>
#include <stratosphere/sf/cmif/sf_cmif_pointer_and_size.hpp>
namespace ams::sf {
@@ -35,8 +34,9 @@ namespace ams::sf {
template<typename T>
concept OutEnabled = (std::is_trivial<T>::value || IsOutForceEnabled<T>::value) && !std::is_pointer<T>::value;
template<typename T> requires OutEnabled<T>
template<typename T>
class Out : public impl::OutBaseTag {
static_assert(OutEnabled<T>);
public:
static constexpr size_t TypeSize = sizeof(T);
private:

View File

@@ -15,12 +15,13 @@
*/
#pragma once
#include "sf_common.hpp"
#include "sf_out.hpp"
#include <stratosphere/sf/sf_common.hpp>
#include <stratosphere/sf/sf_out.hpp>
#include <stratosphere/sf/sf_shared_object.hpp>
namespace ams::sf {
class IServiceObject {
class IServiceObject : public ISharedObject {
public:
virtual ~IServiceObject() { /* ... */ }
};
@@ -50,71 +51,4 @@ namespace ams::sf {
{ T::ShouldMitm(c) } -> std::same_as<bool>;
};
template<typename Interface, typename Impl, typename... Arguments>
requires std::constructible_from<Impl, Arguments...>
constexpr ALWAYS_INLINE std::shared_ptr<typename Interface::ImplHolder<Impl>> MakeShared(Arguments &&... args) {
return std::make_shared<typename Interface::ImplHolder<Impl>>(std::forward<Arguments>(args)...);
}
template<typename Interface, typename Impl, typename... Arguments>
requires (std::constructible_from<Impl, Arguments...> && std::derived_from<Impl, std::enable_shared_from_this<Impl>>)
constexpr ALWAYS_INLINE std::shared_ptr<typename Interface::ImplSharedPointer<Impl>> MakeShared(Arguments &&... args) {
return std::make_shared<typename Interface::ImplSharedPointer<Impl>>(std::make_shared<Impl>(std::forward<Arguments>(args)...));
}
template<typename T>
class ServiceObjectAllocatorImpl {
private:
template<typename>
friend class ServiceObjectAllocatorImpl;
public:
using value_type = T;
private:
MemoryResource * const memory_resource;
public:
constexpr ServiceObjectAllocatorImpl(MemoryResource *mr) : memory_resource(mr) { /* ... */ }
template<typename U>
constexpr ServiceObjectAllocatorImpl(const ServiceObjectAllocatorImpl<U> &rhs) : memory_resource(rhs.memory_resource) { /* ... */ }
value_type *allocate(size_t n) const {
void *mem = this->memory_resource->Allocate(n * sizeof(value_type), alignof(value_type));
AMS_ABORT_UNLESS(mem != nullptr);
return static_cast<value_type *>(mem);
}
void deallocate(void *p, size_t n) const {
this->memory_resource->Deallocate(p, n * sizeof(value_type), alignof(value_type));
}
template<typename U>
inline bool operator==(const ServiceObjectAllocatorImpl<U> &rhs) const {
return this->memory_resource->is_equal(*rhs->memory_resource);
}
template<typename U>
inline bool operator!=(const ServiceObjectAllocatorImpl<U> &rhs) const {
return !(*this == rhs);
}
};
template <typename Interface, typename Impl>
using ServiceObjectAllocator = ServiceObjectAllocatorImpl<typename Interface::ImplHolder<Impl>>;
template<typename Interface, typename Impl, typename Allocator, typename... Arguments>
requires std::constructible_from<Impl, Arguments...>
constexpr ALWAYS_INLINE std::shared_ptr<typename Interface::ImplHolder<Impl>> AllocateShared(const Allocator &allocator, Arguments &&... args) {
return std::allocate_shared<typename Interface::ImplHolder<Impl>>(allocator, std::forward<Arguments>(args)...);
}
template<typename Interface, typename Impl>
constexpr ALWAYS_INLINE std::shared_ptr<typename Interface::ImplPointer<Impl>> GetSharedPointerTo(Impl *impl) {
return std::make_shared<typename Interface::ImplPointer<Impl>>(impl);
}
template<typename Interface, typename Impl>
constexpr ALWAYS_INLINE std::shared_ptr<typename Interface::ImplPointer<Impl>> GetSharedPointerTo(Impl &impl) {
return GetSharedPointerTo<Interface, Impl>(std::addressof(impl));
}
}

View File

@@ -0,0 +1,199 @@
/*
* Copyright (c) 2018-2020 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/sf_out.hpp>
namespace ams::sf {
class ISharedObject {
NON_COPYABLE(ISharedObject);
NON_MOVEABLE(ISharedObject);
protected:
constexpr ISharedObject() { /* ... */ }
~ISharedObject() { /* ... */ }
public:
constexpr virtual void AddReference() = 0;
constexpr virtual void Release() = 0;
};
namespace impl {
class SharedPointerBase {
private:
ISharedObject *m_ptr;
private:
constexpr void AddReferenceImpl() const {
if (m_ptr != nullptr) {
m_ptr->AddReference();
}
}
constexpr void ReleaseImpl() const {
if (m_ptr != nullptr) {
m_ptr->Release();
}
}
public:
constexpr SharedPointerBase() : m_ptr(nullptr) { /* ... */ }
constexpr SharedPointerBase(ISharedObject *ptr, bool incref) : m_ptr(ptr) {
if (incref) {
this->AddReferenceImpl();
}
}
constexpr ~SharedPointerBase() {
this->ReleaseImpl();
}
constexpr SharedPointerBase(const SharedPointerBase &rhs) : m_ptr(rhs.m_ptr) {
this->AddReferenceImpl();
}
constexpr SharedPointerBase(SharedPointerBase &&rhs) : m_ptr(rhs.m_ptr) {
rhs.m_ptr = nullptr;
}
constexpr SharedPointerBase &operator=(const SharedPointerBase &rhs) {
SharedPointerBase tmp(rhs);
tmp.swap(*this);
return *this;
}
constexpr SharedPointerBase &operator=(SharedPointerBase &&rhs) {
SharedPointerBase tmp(std::move(rhs));
tmp.swap(*this);
return *this;
}
constexpr void swap(SharedPointerBase &rhs) {
std::swap(m_ptr, rhs.m_ptr);
}
constexpr ISharedObject *Detach() {
ISharedObject *ret = m_ptr;
m_ptr = nullptr;
return ret;
}
constexpr ISharedObject *Get() const {
return m_ptr;
}
};
}
template<typename I>
class SharedPointer {
template<typename> friend class ::ams::sf::SharedPointer;
template<typename> friend class ::ams::sf::Out;
public:
using Interface = I;
private:
impl::SharedPointerBase m_base;
public:
constexpr SharedPointer() : m_base() { /* ... */ }
constexpr SharedPointer(std::nullptr_t) : m_base() { /* ... */ }
constexpr SharedPointer(Interface *ptr, bool incref) : m_base(static_cast<ISharedObject *>(ptr), incref) { /* ... */ }
constexpr SharedPointer(const SharedPointer &rhs) : m_base(rhs.m_base) { /* ... */ }
constexpr SharedPointer(SharedPointer &&rhs) : m_base(std::move(rhs.m_base)) { /* ... */ }
template<typename U> requires std::derived_from<U, Interface>
constexpr SharedPointer(const SharedPointer<U> &rhs) : m_base(rhs.m_base) { /* ... */ }
template<typename U> requires std::derived_from<U, Interface>
constexpr SharedPointer(SharedPointer<U> &&rhs) : m_base(std::move(rhs.m_base)) { /* ... */ }
constexpr SharedPointer &operator=(std::nullptr_t) {
SharedPointer().swap(*this);
return *this;
}
constexpr SharedPointer &operator=(const SharedPointer &rhs) {
SharedPointer tmp(rhs);
tmp.swap(*this);
return *this;
}
constexpr SharedPointer &operator=(SharedPointer &&rhs) {
SharedPointer tmp(std::move(rhs));
tmp.swap(*this);
return *this;
}
template<typename U> requires std::derived_from<U, Interface>
constexpr SharedPointer &operator=(const SharedPointer<U> &rhs) {
SharedPointer tmp(rhs);
tmp.swap(*this);
return *this;
}
template<typename U> requires std::derived_from<U, Interface>
constexpr SharedPointer &operator=(SharedPointer<U> &&rhs) {
SharedPointer tmp(std::move(rhs));
tmp.swap(*this);
return *this;
}
constexpr void swap(SharedPointer &rhs) {
m_base.swap(rhs.m_base);
}
constexpr Interface *Detach() {
return static_cast<Interface *>(m_base.Detach());
}
constexpr void Reset() {
*this = nullptr;
}
constexpr Interface *Get() const {
return static_cast<Interface *>(m_base.Get());
}
constexpr Interface *operator->() const {
AMS_ASSERT(this->Get() != nullptr);
return this->Get();
}
constexpr bool operator!() const {
return this->Get() == nullptr;
}
constexpr bool operator==(std::nullptr_t) const {
return this->Get() == nullptr;
}
constexpr bool operator!=(std::nullptr_t) const {
return this->Get() != nullptr;
}
};
template<typename Interface>
constexpr void Swap(SharedPointer<Interface> &lhs, SharedPointer<Interface> &rhs) {
lhs.swap(rhs);
}
constexpr inline void ReleaseSharedObject(ISharedObject *ptr) {
ptr->Release();
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2018-2020 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_default_allocation_policy.hpp>
namespace ams::sf {
using StandardAllocationPolicy = DefaultAllocationPolicy;
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2018-2020 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/sf_allocation_policies.hpp>
namespace ams::sf {
template<template<typename> class StdAllocator>
class StdAllocationPolicy {
public:
static constexpr bool HasStatefulAllocator = false;
using Allocator = impl::StatelessDummyAllocator;
template<typename T>
struct StatelessAllocator {
static void *Allocate(size_t size) {
return StdAllocator<T>().allocate(size / sizeof(T));
}
static void Deallocate(void *ptr, size_t size) {
StdAllocator<T>().deallocate(static_cast<T *>(ptr), size / sizeof(T));
}
};
template<typename T>
static void *AllocateAligned(size_t size, size_t align) {
return StdAllocator<T>().allocate(size / sizeof(T));
}
template<typename T>
static void DeallocateAligned(void *ptr, size_t size, size_t align) {
StdAllocator<T>().deallocate(static_cast<T *>(ptr), size / sizeof(T));
}
};
}