libstrat: convert to experimental new (super-accurate) sf allocation semantics
This commit is contained in:
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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) \
|
||||
}; \
|
||||
\
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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__))
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>{};
|
||||
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user