mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
tipc: implement special-case templating used by 13.0.0 pgl
This commit is contained in:
parent
ff5f376c33
commit
2541f6dd71
2 changed files with 695 additions and 492 deletions
|
@ -38,10 +38,12 @@ namespace ams::tipc {
|
|||
template<size_t N>
|
||||
struct DummyDeferralManager : public DummyDeferralManagerBase {};
|
||||
|
||||
template<size_t ThreadStackSize, typename... PortInfos>
|
||||
namespace impl {
|
||||
|
||||
template<size_t ThreadStackSize, bool IsDeferralSupported, size_t NumPorts, typename... PortInfos>
|
||||
class ServerManagerImpl {
|
||||
private:
|
||||
static constexpr inline size_t NumPorts = sizeof...(PortInfos);
|
||||
static_assert(NumPorts == sizeof...(PortInfos));
|
||||
static constexpr inline size_t MaxSessions = (PortInfos::MaxSessions + ...);
|
||||
|
||||
/* Verify that we have at least one port. */
|
||||
|
@ -60,7 +62,7 @@ namespace ams::tipc {
|
|||
template<size_t Ix> requires (Ix < NumPorts)
|
||||
using PortInfo = typename std::tuple_element<Ix, std::tuple<PortInfos...>>::type;
|
||||
|
||||
static constexpr inline bool IsDeferralSupported = (PortInfos::CanDeferInvokeRequest || ...);
|
||||
static_assert(IsDeferralSupported == (PortInfos::CanDeferInvokeRequest || ...));
|
||||
|
||||
template<size_t Sessions>
|
||||
using DeferralManagerImplType = typename std::conditional<IsDeferralSupported, DeferralManager<Sessions>, DummyDeferralManager<Sessions>>::type;
|
||||
|
@ -625,6 +627,219 @@ namespace ams::tipc {
|
|||
}
|
||||
};
|
||||
|
||||
template<size_t ThreadStackSize, typename PortInfo>
|
||||
class ServerManagerImpl<ThreadStackSize, false, 1, PortInfo> {
|
||||
private:
|
||||
static constexpr inline size_t NumPorts = 1;
|
||||
static constexpr inline size_t MaxSessions = PortInfo::MaxSessions;
|
||||
|
||||
/* Verify that it's possible to service this many sessions, with our port manager count. */
|
||||
static_assert(MaxSessions <= svc::ArgumentHandleCountMax);
|
||||
public:
|
||||
class PortManagerBase {
|
||||
protected:
|
||||
os::MultiWaitType m_multi_wait;
|
||||
ObjectManagerBase *m_object_manager;
|
||||
public:
|
||||
constexpr PortManagerBase() : m_multi_wait(), m_object_manager() { /* ... */ }
|
||||
|
||||
void InitializeBase(ObjectManagerBase *om) {
|
||||
/* Initialize our multi wait. */
|
||||
os::InitializeMultiWait(std::addressof(m_multi_wait));
|
||||
|
||||
/* Initialize our object manager. */
|
||||
m_object_manager = om;
|
||||
}
|
||||
|
||||
void RegisterPort(os::NativeHandle port_handle) {
|
||||
/* Create an object holder for the port. */
|
||||
tipc::ObjectHolder object;
|
||||
|
||||
/* Setup the object. */
|
||||
object.InitializeAsPort(port_handle);
|
||||
|
||||
/* Register the object. */
|
||||
m_object_manager->AddObject(object);
|
||||
}
|
||||
|
||||
os::NativeHandle ProcessRequest(ObjectHolder &object) {
|
||||
/* Process the request. */
|
||||
const Result result = m_object_manager->ProcessRequest(object);
|
||||
if (R_SUCCEEDED(result)) {
|
||||
/* We should reply only if the request isn't deferred. */
|
||||
return object.GetHandle();
|
||||
} else {
|
||||
/* Processing failed, so close the session if we need to. */
|
||||
if (!tipc::ResultSessionClosed::Includes(result)) {
|
||||
this->CloseSession(object);
|
||||
}
|
||||
|
||||
/* We shouldn't reply on failure. */
|
||||
return os::InvalidNativeHandle;
|
||||
}
|
||||
}
|
||||
|
||||
bool ReplyAndReceive(ObjectHolder *out_object, os::NativeHandle reply_target) {
|
||||
/* If we don't have a reply target, clear our message buffer. */
|
||||
if (reply_target == os::InvalidNativeHandle) {
|
||||
svc::ipc::MessageBuffer(svc::ipc::GetMessageBuffer()).SetNull();
|
||||
}
|
||||
|
||||
/* Try to reply/receive. */
|
||||
const Result result = [&] ALWAYS_INLINE_LAMBDA () -> Result {
|
||||
os::MultiWaitHolderType *signaled_holder = nullptr;
|
||||
ON_SCOPE_EXIT { AMS_ABORT_UNLESS(signaled_holder == nullptr); };
|
||||
return m_object_manager->ReplyAndReceive(std::addressof(signaled_holder), out_object, reply_target, std::addressof(m_multi_wait));
|
||||
}();
|
||||
|
||||
/* Handle the result. */
|
||||
if (R_FAILED(result)) {
|
||||
/* Close the object. */
|
||||
this->CloseSession(*out_object);
|
||||
|
||||
/* We don't have anything to process. */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddSession(os::NativeHandle session_handle, tipc::ServiceObjectBase *service_object) {
|
||||
/* Create an object holder for the session. */
|
||||
tipc::ObjectHolder object;
|
||||
|
||||
/* Setup the object. */
|
||||
object.InitializeAsSession(session_handle, true, service_object);
|
||||
|
||||
/* Register the object. */
|
||||
m_object_manager->AddObject(object);
|
||||
}
|
||||
|
||||
void CloseSession(ObjectHolder &object) {
|
||||
/* Get the object's handle. */
|
||||
const auto handle = object.GetHandle();
|
||||
|
||||
/* Close the object with our manager. */
|
||||
m_object_manager->CloseObject(handle);
|
||||
|
||||
/* Close the handle itself. */
|
||||
R_ABORT_UNLESS(svc::CloseHandle(handle));
|
||||
}
|
||||
};
|
||||
|
||||
class PortManagerImpl final : public PortManagerBase {
|
||||
private:
|
||||
tipc::ObjectManager<1 + MaxSessions> m_object_manager_impl;
|
||||
public:
|
||||
constexpr PortManagerImpl() : PortManagerBase(), m_object_manager_impl() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void Initialize() {
|
||||
/* Initialize our base. */
|
||||
this->InitializeBase(std::addressof(m_object_manager_impl));
|
||||
|
||||
/* Initialize our object manager. */
|
||||
m_object_manager_impl.Initialize(std::addressof(this->m_multi_wait));
|
||||
}
|
||||
};
|
||||
|
||||
using PortManager = PortManagerImpl;
|
||||
private:
|
||||
PortManager m_port_manager;
|
||||
PortInfo::Allocator m_port_allocator;
|
||||
public:
|
||||
constexpr ServerManagerImpl() : m_port_manager(), m_port_allocator() { /* ... */ }
|
||||
|
||||
void Initialize() {
|
||||
/* Initialize our port manager. */
|
||||
m_port_manager.Initialize();
|
||||
}
|
||||
|
||||
void RegisterPort(os::NativeHandle port_handle) {
|
||||
m_port_manager.RegisterPort(port_handle);
|
||||
}
|
||||
|
||||
void RegisterPort(sm::ServiceName service_name, size_t max_sessions) {
|
||||
/* Register service. */
|
||||
os::NativeHandle port_handle;
|
||||
R_ABORT_UNLESS(sm::RegisterService(std::addressof(port_handle), service_name, max_sessions, false));
|
||||
|
||||
/* Register the port handle. */
|
||||
this->RegisterPort(port_handle);
|
||||
}
|
||||
|
||||
void LoopAuto() {
|
||||
/* Process for the only port. */
|
||||
this->LoopProcess(m_port_manager);
|
||||
}
|
||||
|
||||
tipc::ServiceObjectBase *AllocateObject() {
|
||||
/* Allocate the object. */
|
||||
auto * const new_object = m_port_allocator.Allocate();
|
||||
AMS_ABORT_UNLESS(new_object != nullptr);
|
||||
|
||||
/* If we should, set the object's deleter. */
|
||||
if constexpr (IsServiceObjectDeleter<typename PortInfo::Allocator>) {
|
||||
new_object->SetDeleter(std::addressof(m_port_allocator));
|
||||
}
|
||||
|
||||
return new_object;
|
||||
}
|
||||
|
||||
Result AddSession(os::NativeHandle *out, tipc::ServiceObjectBase *object) {
|
||||
/* Create a handle for the session. */
|
||||
svc::Handle session_handle;
|
||||
R_TRY(svc::CreateSession(std::addressof(session_handle), static_cast<svc::Handle *>(out), false, 0));
|
||||
|
||||
/* Add the session to our manager. */
|
||||
m_port_manager.AddSession(session_handle, object);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
private:
|
||||
void LoopProcess(PortManagerBase &port_manager) {
|
||||
/* Process requests forever. */
|
||||
os::NativeHandle reply_target = os::InvalidNativeHandle;
|
||||
while (true) {
|
||||
/* Reply to our pending request, and wait to receive a new one. */
|
||||
tipc::ObjectHolder signaled_object{};
|
||||
while (!port_manager.ReplyAndReceive(std::addressof(signaled_object), reply_target)) {
|
||||
reply_target = os::InvalidNativeHandle;
|
||||
}
|
||||
|
||||
/* A session was signaled, accessible via signaled_object. */
|
||||
switch (signaled_object.GetType()) {
|
||||
case ObjectHolder::ObjectType_Port:
|
||||
{
|
||||
/* Try to accept a new session */
|
||||
svc::Handle session_handle;
|
||||
if (R_SUCCEEDED(svc::AcceptSession(std::addressof(session_handle), signaled_object.GetHandle()))) {
|
||||
port_manager.AddSession(session_handle, this->AllocateObject());
|
||||
}
|
||||
|
||||
/* We have nothing to reply to. */
|
||||
reply_target = os::InvalidNativeHandle;
|
||||
}
|
||||
break;
|
||||
case ObjectHolder::ObjectType_Session:
|
||||
{
|
||||
/* Process the request */
|
||||
reply_target = port_manager.ProcessRequest(signaled_object);
|
||||
}
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<size_t ThreadStackSize, typename... PortInfos>
|
||||
using ServerManagerImpl = impl::ServerManagerImpl<ThreadStackSize, (PortInfos::CanDeferInvokeRequest || ...), sizeof...(PortInfos), PortInfos...>;
|
||||
|
||||
|
||||
template<typename... PortInfos>
|
||||
using ServerManager = ServerManagerImpl<os::MemoryPageSize, PortInfos...>;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ams::pgl::srv {
|
|||
};
|
||||
|
||||
constexpr sm::ServiceName ShellServiceName = sm::ServiceName::Encode("pgl");
|
||||
constexpr size_t ShellMaxSessions = 8; /* Official maximum is 8. */
|
||||
constexpr size_t ShellMaxSessions = 8; /* Official maximum is 6. */
|
||||
|
||||
using CmifServerManager = ams::sf::hipc::ServerManager<PortIndex_Count>;
|
||||
|
||||
|
@ -113,7 +113,7 @@ namespace ams::pgl::srv {
|
|||
globals.server_manager.Initialize();
|
||||
|
||||
/* Register the pgl service. */
|
||||
globals.server_manager.RegisterPort<PortIndex_Shell>(ShellServiceName, ShellMaxSessions);
|
||||
globals.server_manager.RegisterPort(ShellServiceName, ShellMaxSessions);
|
||||
} else {
|
||||
/* Get the globals. */
|
||||
auto &globals = GetGlobalsForCmif();
|
||||
|
@ -192,16 +192,4 @@ namespace ams::pgl::srv {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
||||
ams::tipc::ServiceObjectBase *AllocateShellEventObserverForTipc() {
|
||||
auto &allocator = GetGlobalsForTipc().observer_allocator;
|
||||
|
||||
auto *object = allocator.Allocate();
|
||||
if (object != nullptr) {
|
||||
object->SetDeleter(std::addressof(allocator));
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue