diff options
| author | 2021-05-15 23:49:03 -0700 | |
|---|---|---|
| committer | 2021-05-20 21:41:49 -0700 | |
| commit | 7361eac10ff8991f16165190792a948a02b9b756 (patch) | |
| tree | 9fdd0bd629afb6a6d20602c341e74511de2cc135 | |
| parent | Revert "WORKAROUND: temp. disable session resource limits while we work out i... (diff) | |
| download | yuzu-7361eac10ff8991f16165190792a948a02b9b756.tar.gz yuzu-7361eac10ff8991f16165190792a948a02b9b756.tar.xz yuzu-7361eac10ff8991f16165190792a948a02b9b756.zip | |
hle: kernel: Implement CloneCurrentObject and improve session management.
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/ipc_helpers.h | 23 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 82 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_client_port.h | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_port.cpp | 7 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_port.h | 16 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 35 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.h | 36 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_session.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/service.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/sm/controller.cpp | 39 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/service/sm/sm.h | 2 |
13 files changed, 184 insertions, 99 deletions
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index c0d0860fd..963f3db30 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h | |||
| @@ -86,10 +86,8 @@ public: | |||
| 86 | 86 | ||
| 87 | // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory | 87 | // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory |
| 88 | // padding. | 88 | // padding. |
| 89 | u32 raw_data_size = ctx.IsTipc() | 89 | u32 raw_data_size = ctx.write_size = |
| 90 | ? normal_params_size - 1 | 90 | ctx.IsTipc() ? normal_params_size - 1 : normal_params_size; |
| 91 | : sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; | ||
| 92 | |||
| 93 | u32 num_handles_to_move{}; | 91 | u32 num_handles_to_move{}; |
| 94 | u32 num_domain_objects{}; | 92 | u32 num_domain_objects{}; |
| 95 | const bool always_move_handles{ | 93 | const bool always_move_handles{ |
| @@ -101,16 +99,20 @@ public: | |||
| 101 | } | 99 | } |
| 102 | 100 | ||
| 103 | if (ctx.Session()->IsDomain()) { | 101 | if (ctx.Session()->IsDomain()) { |
| 104 | raw_data_size += static_cast<u32>(sizeof(DomainMessageHeader) / 4 + num_domain_objects); | 102 | raw_data_size += |
| 103 | static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects); | ||
| 104 | ctx.write_size += num_domain_objects; | ||
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | if (ctx.IsTipc()) { | 107 | if (ctx.IsTipc()) { |
| 108 | header.type.Assign(ctx.GetCommandType()); | 108 | header.type.Assign(ctx.GetCommandType()); |
| 109 | } else { | ||
| 110 | raw_data_size += static_cast<u32>(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 + | ||
| 111 | normal_params_size); | ||
| 109 | } | 112 | } |
| 110 | 113 | ||
| 111 | ctx.data_size = static_cast<u32>(raw_data_size); | 114 | header.data_size.Assign(raw_data_size); |
| 112 | header.data_size.Assign(static_cast<u32>(raw_data_size)); | 115 | if (num_handles_to_copy || num_handles_to_move) { |
| 113 | if (num_handles_to_copy != 0 || num_handles_to_move != 0) { | ||
| 114 | header.enable_handle_descriptor.Assign(1); | 116 | header.enable_handle_descriptor.Assign(1); |
| 115 | } | 117 | } |
| 116 | PushRaw(header); | 118 | PushRaw(header); |
| @@ -143,7 +145,8 @@ public: | |||
| 143 | data_payload_index = index; | 145 | data_payload_index = index; |
| 144 | 146 | ||
| 145 | ctx.data_payload_offset = index; | 147 | ctx.data_payload_offset = index; |
| 146 | ctx.domain_offset = index + raw_data_size / 4; | 148 | ctx.write_size += index; |
| 149 | ctx.domain_offset = static_cast<u32>(index + raw_data_size / sizeof(u32)); | ||
| 147 | } | 150 | } |
| 148 | 151 | ||
| 149 | template <class T> | 152 | template <class T> |
| @@ -404,7 +407,7 @@ public: | |||
| 404 | std::shared_ptr<T> PopIpcInterface() { | 407 | std::shared_ptr<T> PopIpcInterface() { |
| 405 | ASSERT(context->Session()->IsDomain()); | 408 | ASSERT(context->Session()->IsDomain()); |
| 406 | ASSERT(context->GetDomainMessageHeader().input_object_count > 0); | 409 | ASSERT(context->GetDomainMessageHeader().input_object_count > 0); |
| 407 | return context->GetDomainRequestHandler<T>(Pop<u32>() - 1); | 410 | return context->GetDomainHandler<T>(Pop<u32>() - 1); |
| 408 | } | 411 | } |
| 409 | }; | 412 | }; |
| 410 | 413 | ||
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 24700f7a5..689f58cf6 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -35,11 +35,11 @@ SessionRequestHandler::SessionRequestHandler() = default; | |||
| 35 | SessionRequestHandler::~SessionRequestHandler() = default; | 35 | SessionRequestHandler::~SessionRequestHandler() = default; |
| 36 | 36 | ||
| 37 | void SessionRequestHandler::ClientConnected(KServerSession* session) { | 37 | void SessionRequestHandler::ClientConnected(KServerSession* session) { |
| 38 | session->SetHleHandler(shared_from_this()); | 38 | session->SetSessionHandler(shared_from_this()); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void SessionRequestHandler::ClientDisconnected(KServerSession* session) { | 41 | void SessionRequestHandler::ClientDisconnected(KServerSession* session) { |
| 42 | session->SetHleHandler(nullptr); | 42 | session->SetSessionHandler(nullptr); |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, | 45 | HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, |
| @@ -186,18 +186,6 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t | |||
| 186 | auto& owner_process = *requesting_thread.GetOwnerProcess(); | 186 | auto& owner_process = *requesting_thread.GetOwnerProcess(); |
| 187 | auto& handle_table = owner_process.GetHandleTable(); | 187 | auto& handle_table = owner_process.GetHandleTable(); |
| 188 | 188 | ||
| 189 | // The data_size already includes the payload header, the padding and the domain header. | ||
| 190 | std::size_t size{}; | ||
| 191 | |||
| 192 | if (IsTipc()) { | ||
| 193 | size = cmd_buf.size(); | ||
| 194 | } else { | ||
| 195 | size = data_payload_offset + data_size - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; | ||
| 196 | if (Session()->IsDomain()) { | ||
| 197 | size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | for (auto& object : copy_objects) { | 189 | for (auto& object : copy_objects) { |
| 202 | Handle handle{}; | 190 | Handle handle{}; |
| 203 | if (object) { | 191 | if (object) { |
| @@ -222,7 +210,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t | |||
| 222 | if (Session()->IsDomain()) { | 210 | if (Session()->IsDomain()) { |
| 223 | current_offset = domain_offset - static_cast<u32>(domain_objects.size()); | 211 | current_offset = domain_offset - static_cast<u32>(domain_objects.size()); |
| 224 | for (const auto& object : domain_objects) { | 212 | for (const auto& object : domain_objects) { |
| 225 | server_session->AppendDomainRequestHandler(object); | 213 | server_session->AppendDomainHandler(object); |
| 226 | cmd_buf[current_offset++] = | 214 | cmd_buf[current_offset++] = |
| 227 | static_cast<u32_le>(server_session->NumDomainRequestHandlers()); | 215 | static_cast<u32_le>(server_session->NumDomainRequestHandlers()); |
| 228 | } | 216 | } |
| @@ -230,7 +218,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t | |||
| 230 | 218 | ||
| 231 | // Copy the translated command buffer back into the thread's command buffer area. | 219 | // Copy the translated command buffer back into the thread's command buffer area. |
| 232 | memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), | 220 | memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), |
| 233 | size * sizeof(u32)); | 221 | write_size * sizeof(u32)); |
| 234 | 222 | ||
| 235 | return RESULT_SUCCESS; | 223 | return RESULT_SUCCESS; |
| 236 | } | 224 | } |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index e1b128281..51cd1a898 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | #include <type_traits> | 12 | #include <type_traits> |
| 13 | #include <vector> | 13 | #include <vector> |
| 14 | #include <boost/container/small_vector.hpp> | 14 | #include <boost/container/small_vector.hpp> |
| 15 | |||
| 16 | #include "common/assert.h" | ||
| 15 | #include "common/common_types.h" | 17 | #include "common/common_types.h" |
| 16 | #include "common/concepts.h" | 18 | #include "common/concepts.h" |
| 17 | #include "common/swap.h" | 19 | #include "common/swap.h" |
| @@ -84,6 +86,69 @@ public: | |||
| 84 | void ClientDisconnected(KServerSession* session); | 86 | void ClientDisconnected(KServerSession* session); |
| 85 | }; | 87 | }; |
| 86 | 88 | ||
| 89 | using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; | ||
| 90 | |||
| 91 | /** | ||
| 92 | * Manages the underlying HLE requests for a session, and whether (or not) the session should be | ||
| 93 | * treated as a domain. This is managed separately from server sessions, as this state is shared | ||
| 94 | * when objects are cloned. | ||
| 95 | */ | ||
| 96 | class SessionRequestManager final { | ||
| 97 | public: | ||
| 98 | SessionRequestManager() = default; | ||
| 99 | |||
| 100 | bool IsDomain() const { | ||
| 101 | return is_domain; | ||
| 102 | } | ||
| 103 | |||
| 104 | void ConvertToDomain() { | ||
| 105 | domain_handlers = {session_handler}; | ||
| 106 | is_domain = true; | ||
| 107 | } | ||
| 108 | |||
| 109 | std::size_t DomainHandlerCount() const { | ||
| 110 | return domain_handlers.size(); | ||
| 111 | } | ||
| 112 | |||
| 113 | bool HasSessionHandler() const { | ||
| 114 | return session_handler != nullptr; | ||
| 115 | } | ||
| 116 | |||
| 117 | SessionRequestHandler& SessionHandler() { | ||
| 118 | return *session_handler; | ||
| 119 | } | ||
| 120 | |||
| 121 | const SessionRequestHandler& SessionHandler() const { | ||
| 122 | return *session_handler; | ||
| 123 | } | ||
| 124 | |||
| 125 | void CloseDomainHandler(std::size_t index) { | ||
| 126 | if (index < DomainHandlerCount()) { | ||
| 127 | domain_handlers[index] = nullptr; | ||
| 128 | } else { | ||
| 129 | UNREACHABLE_MSG("Unexpected handler index {}", index); | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | SessionRequestHandlerPtr DomainHandler(std::size_t index) const { | ||
| 134 | ASSERT_MSG(index < DomainHandlerCount(), "Unexpected handler index {}", index); | ||
| 135 | return domain_handlers.at(index); | ||
| 136 | } | ||
| 137 | |||
| 138 | void AppendDomainHandler(SessionRequestHandlerPtr&& handler) { | ||
| 139 | domain_handlers.emplace_back(std::move(handler)); | ||
| 140 | } | ||
| 141 | |||
| 142 | void SetSessionHandler(SessionRequestHandlerPtr&& handler) { | ||
| 143 | session_handler = std::move(handler); | ||
| 144 | } | ||
| 145 | |||
| 146 | private: | ||
| 147 | bool is_domain{}; | ||
| 148 | SessionRequestHandlerPtr session_handler; | ||
| 149 | std::vector<SessionRequestHandlerPtr> domain_handlers; | ||
| 150 | }; | ||
| 151 | |||
| 87 | /** | 152 | /** |
| 88 | * Class containing information about an in-flight IPC request being handled by an HLE service | 153 | * Class containing information about an in-flight IPC request being handled by an HLE service |
| 89 | * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and | 154 | * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and |
| @@ -239,18 +304,17 @@ public: | |||
| 239 | copy_objects.emplace_back(object); | 304 | copy_objects.emplace_back(object); |
| 240 | } | 305 | } |
| 241 | 306 | ||
| 242 | void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) { | 307 | void AddDomainObject(SessionRequestHandlerPtr object) { |
| 243 | domain_objects.emplace_back(std::move(object)); | 308 | domain_objects.emplace_back(std::move(object)); |
| 244 | } | 309 | } |
| 245 | 310 | ||
| 246 | template <typename T> | 311 | template <typename T> |
| 247 | std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const { | 312 | std::shared_ptr<T> GetDomainHandler(std::size_t index) const { |
| 248 | return std::static_pointer_cast<T>(domain_request_handlers.at(index)); | 313 | return std::static_pointer_cast<T>(manager->DomainHandler(index)); |
| 249 | } | 314 | } |
| 250 | 315 | ||
| 251 | void SetDomainRequestHandlers( | 316 | void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) { |
| 252 | const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) { | 317 | manager = std::move(manager_); |
| 253 | domain_request_handlers = handlers; | ||
| 254 | } | 318 | } |
| 255 | 319 | ||
| 256 | /// Clears the list of objects so that no lingering objects are written accidentally to the | 320 | /// Clears the list of objects so that no lingering objects are written accidentally to the |
| @@ -297,7 +361,7 @@ private: | |||
| 297 | boost::container::small_vector<Handle, 8> copy_handles; | 361 | boost::container::small_vector<Handle, 8> copy_handles; |
| 298 | boost::container::small_vector<KAutoObject*, 8> move_objects; | 362 | boost::container::small_vector<KAutoObject*, 8> move_objects; |
| 299 | boost::container::small_vector<KAutoObject*, 8> copy_objects; | 363 | boost::container::small_vector<KAutoObject*, 8> copy_objects; |
| 300 | boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; | 364 | boost::container::small_vector<SessionRequestHandlerPtr, 8> domain_objects; |
| 301 | 365 | ||
| 302 | std::optional<IPC::CommandHeader> command_header; | 366 | std::optional<IPC::CommandHeader> command_header; |
| 303 | std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; | 367 | std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; |
| @@ -311,12 +375,12 @@ private: | |||
| 311 | 375 | ||
| 312 | u32_le command{}; | 376 | u32_le command{}; |
| 313 | u64 pid{}; | 377 | u64 pid{}; |
| 378 | u32 write_size{}; | ||
| 314 | u32 data_payload_offset{}; | 379 | u32 data_payload_offset{}; |
| 315 | u32 handles_offset{}; | 380 | u32 handles_offset{}; |
| 316 | u32 domain_offset{}; | 381 | u32 domain_offset{}; |
| 317 | u32 data_size{}; | ||
| 318 | 382 | ||
| 319 | std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; | 383 | std::shared_ptr<SessionRequestManager> manager; |
| 320 | bool is_thread_waiting{}; | 384 | bool is_thread_waiting{}; |
| 321 | 385 | ||
| 322 | KernelCore& kernel; | 386 | KernelCore& kernel; |
diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index d00ce3ddd..8501156e8 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h | |||
| @@ -31,6 +31,9 @@ public: | |||
| 31 | const KPort* GetParent() const { | 31 | const KPort* GetParent() const { |
| 32 | return parent; | 32 | return parent; |
| 33 | } | 33 | } |
| 34 | KPort* GetParent() { | ||
| 35 | return parent; | ||
| 36 | } | ||
| 34 | 37 | ||
| 35 | s32 GetNumSessions() const { | 38 | s32 GetNumSessions() const { |
| 36 | return num_sessions; | 39 | return num_sessions; |
diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index feb2bb11f..723a1b571 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp | |||
| @@ -56,11 +56,8 @@ ResultCode KPort::EnqueueSession(KServerSession* session) { | |||
| 56 | 56 | ||
| 57 | R_UNLESS(state == State::Normal, ResultPortClosed); | 57 | R_UNLESS(state == State::Normal, ResultPortClosed); |
| 58 | 58 | ||
| 59 | if (server.HasHLEHandler()) { | 59 | server.GetSessionRequestHandler()->ClientConnected(session); |
| 60 | server.GetHLEHandler()->ClientConnected(session); | 60 | server.EnqueueSession(session); |
| 61 | } else { | ||
| 62 | server.EnqueueSession(session); | ||
| 63 | } | ||
| 64 | 61 | ||
| 65 | return RESULT_SUCCESS; | 62 | return RESULT_SUCCESS; |
| 66 | } | 63 | } |
diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index e76792253..d1a757ec3 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h | |||
| @@ -32,26 +32,24 @@ public: | |||
| 32 | explicit KServerPort(KernelCore& kernel_); | 32 | explicit KServerPort(KernelCore& kernel_); |
| 33 | virtual ~KServerPort() override; | 33 | virtual ~KServerPort() override; |
| 34 | 34 | ||
| 35 | using HLEHandler = std::shared_ptr<SessionRequestHandler>; | ||
| 36 | |||
| 37 | void Initialize(KPort* parent_, std::string&& name_); | 35 | void Initialize(KPort* parent_, std::string&& name_); |
| 38 | 36 | ||
| 39 | /// Whether or not this server port has an HLE handler available. | 37 | /// Whether or not this server port has an HLE handler available. |
| 40 | bool HasHLEHandler() const { | 38 | bool HasSessionRequestHandler() const { |
| 41 | return hle_handler != nullptr; | 39 | return session_handler != nullptr; |
| 42 | } | 40 | } |
| 43 | 41 | ||
| 44 | /// Gets the HLE handler for this port. | 42 | /// Gets the HLE handler for this port. |
| 45 | HLEHandler GetHLEHandler() const { | 43 | SessionRequestHandlerPtr GetSessionRequestHandler() const { |
| 46 | return hle_handler; | 44 | return session_handler; |
| 47 | } | 45 | } |
| 48 | 46 | ||
| 49 | /** | 47 | /** |
| 50 | * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port | 48 | * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port |
| 51 | * will inherit a reference to this handler. | 49 | * will inherit a reference to this handler. |
| 52 | */ | 50 | */ |
| 53 | void SetHleHandler(HLEHandler hle_handler_) { | 51 | void SetSessionHandler(SessionRequestHandlerPtr&& handler) { |
| 54 | hle_handler = std::move(hle_handler_); | 52 | session_handler = std::move(handler); |
| 55 | } | 53 | } |
| 56 | 54 | ||
| 57 | void EnqueueSession(KServerSession* pending_session); | 55 | void EnqueueSession(KServerSession* pending_session); |
| @@ -73,7 +71,7 @@ private: | |||
| 73 | 71 | ||
| 74 | private: | 72 | private: |
| 75 | SessionList session_list; | 73 | SessionList session_list; |
| 76 | HLEHandler hle_handler; | 74 | SessionRequestHandlerPtr session_handler; |
| 77 | KPort* parent{}; | 75 | KPort* parent{}; |
| 78 | }; | 76 | }; |
| 79 | 77 | ||
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 8850d9af5..457fdfd60 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -23,7 +23,8 @@ | |||
| 23 | 23 | ||
| 24 | namespace Kernel { | 24 | namespace Kernel { |
| 25 | 25 | ||
| 26 | KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} | 26 | KServerSession::KServerSession(KernelCore& kernel_) |
| 27 | : KSynchronizationObject{kernel_}, manager{std::make_shared<SessionRequestManager>()} {} | ||
| 27 | 28 | ||
| 28 | KServerSession::~KServerSession() { | 29 | KServerSession::~KServerSession() { |
| 29 | kernel.ReleaseServiceThread(service_thread); | 30 | kernel.ReleaseServiceThread(service_thread); |
| @@ -43,14 +44,8 @@ void KServerSession::Destroy() { | |||
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | void KServerSession::OnClientClosed() { | 46 | void KServerSession::OnClientClosed() { |
| 46 | // We keep a shared pointer to the hle handler to keep it alive throughout | 47 | if (manager->HasSessionHandler()) { |
| 47 | // the call to ClientDisconnected, as ClientDisconnected invalidates the | 48 | manager->SessionHandler().ClientDisconnected(this); |
| 48 | // hle_handler member itself during the course of the function executing. | ||
| 49 | std::shared_ptr<SessionRequestHandler> handler = hle_handler; | ||
| 50 | if (handler) { | ||
| 51 | // Note that after this returns, this server session's hle_handler is | ||
| 52 | // invalidated (set to null). | ||
| 53 | handler->ClientDisconnected(this); | ||
| 54 | } | 49 | } |
| 55 | } | 50 | } |
| 56 | 51 | ||
| @@ -66,12 +61,12 @@ bool KServerSession::IsSignaled() const { | |||
| 66 | return false; | 61 | return false; |
| 67 | } | 62 | } |
| 68 | 63 | ||
| 69 | void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { | 64 | void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { |
| 70 | domain_request_handlers.push_back(std::move(handler)); | 65 | manager->AppendDomainHandler(std::move(handler)); |
| 71 | } | 66 | } |
| 72 | 67 | ||
| 73 | std::size_t KServerSession::NumDomainRequestHandlers() const { | 68 | std::size_t KServerSession::NumDomainRequestHandlers() const { |
| 74 | return domain_request_handlers.size(); | 69 | return manager->DomainHandlerCount(); |
| 75 | } | 70 | } |
| 76 | 71 | ||
| 77 | ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { | 72 | ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { |
| @@ -80,14 +75,14 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co | |||
| 80 | } | 75 | } |
| 81 | 76 | ||
| 82 | // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs | 77 | // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs |
| 83 | context.SetDomainRequestHandlers(domain_request_handlers); | 78 | context.SetSessionRequestManager(manager); |
| 84 | 79 | ||
| 85 | // If there is a DomainMessageHeader, then this is CommandType "Request" | 80 | // If there is a DomainMessageHeader, then this is CommandType "Request" |
| 86 | const auto& domain_message_header = context.GetDomainMessageHeader(); | 81 | const auto& domain_message_header = context.GetDomainMessageHeader(); |
| 87 | const u32 object_id{domain_message_header.object_id}; | 82 | const u32 object_id{domain_message_header.object_id}; |
| 88 | switch (domain_message_header.command) { | 83 | switch (domain_message_header.command) { |
| 89 | case IPC::DomainMessageHeader::CommandType::SendMessage: | 84 | case IPC::DomainMessageHeader::CommandType::SendMessage: |
| 90 | if (object_id > domain_request_handlers.size()) { | 85 | if (object_id > manager->DomainHandlerCount()) { |
| 91 | LOG_CRITICAL(IPC, | 86 | LOG_CRITICAL(IPC, |
| 92 | "object_id {} is too big! This probably means a recent service call " | 87 | "object_id {} is too big! This probably means a recent service call " |
| 93 | "to {} needed to return a new interface!", | 88 | "to {} needed to return a new interface!", |
| @@ -95,12 +90,12 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co | |||
| 95 | UNREACHABLE(); | 90 | UNREACHABLE(); |
| 96 | return RESULT_SUCCESS; // Ignore error if asserts are off | 91 | return RESULT_SUCCESS; // Ignore error if asserts are off |
| 97 | } | 92 | } |
| 98 | return domain_request_handlers[object_id - 1]->HandleSyncRequest(*this, context); | 93 | return manager->DomainHandler(object_id - 1)->HandleSyncRequest(*this, context); |
| 99 | 94 | ||
| 100 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { | 95 | case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { |
| 101 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); | 96 | LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); |
| 102 | 97 | ||
| 103 | domain_request_handlers[object_id - 1] = nullptr; | 98 | manager->CloseDomainHandler(object_id - 1); |
| 104 | 99 | ||
| 105 | IPC::ResponseBuilder rb{context, 2}; | 100 | IPC::ResponseBuilder rb{context, 2}; |
| 106 | rb.Push(RESULT_SUCCESS); | 101 | rb.Push(RESULT_SUCCESS); |
| @@ -133,14 +128,14 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 133 | if (IsDomain() && context.HasDomainMessageHeader()) { | 128 | if (IsDomain() && context.HasDomainMessageHeader()) { |
| 134 | result = HandleDomainSyncRequest(context); | 129 | result = HandleDomainSyncRequest(context); |
| 135 | // If there is no domain header, the regular session handler is used | 130 | // If there is no domain header, the regular session handler is used |
| 136 | } else if (hle_handler != nullptr) { | 131 | } else if (manager->HasSessionHandler()) { |
| 137 | // If this ServerSession has an associated HLE handler, forward the request to it. | 132 | // If this ServerSession has an associated HLE handler, forward the request to it. |
| 138 | result = hle_handler->HandleSyncRequest(*this, context); | 133 | result = manager->SessionHandler().HandleSyncRequest(*this, context); |
| 139 | } | 134 | } |
| 140 | 135 | ||
| 141 | if (convert_to_domain) { | 136 | if (convert_to_domain) { |
| 142 | ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); | 137 | ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance."); |
| 143 | domain_request_handlers = {hle_handler}; | 138 | manager->ConvertToDomain(); |
| 144 | convert_to_domain = false; | 139 | convert_to_domain = false; |
| 145 | } | 140 | } |
| 146 | 141 | ||
diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 597d76d38..dd4de2904 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <boost/intrusive/list.hpp> | 12 | #include <boost/intrusive/list.hpp> |
| 13 | 13 | ||
| 14 | #include "common/threadsafe_queue.h" | 14 | #include "common/threadsafe_queue.h" |
| 15 | #include "core/hle/kernel/hle_ipc.h" | ||
| 15 | #include "core/hle/kernel/k_synchronization_object.h" | 16 | #include "core/hle/kernel/k_synchronization_object.h" |
| 16 | #include "core/hle/kernel/service_thread.h" | 17 | #include "core/hle/kernel/service_thread.h" |
| 17 | #include "core/hle/result.h" | 18 | #include "core/hle/result.h" |
| @@ -64,8 +65,8 @@ public: | |||
| 64 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not | 65 | * instead of the regular IPC machinery. (The regular IPC machinery is currently not |
| 65 | * implemented.) | 66 | * implemented.) |
| 66 | */ | 67 | */ |
| 67 | void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) { | 68 | void SetSessionHandler(SessionRequestHandlerPtr handler) { |
| 68 | hle_handler = std::move(hle_handler_); | 69 | manager->SetSessionHandler(std::move(handler)); |
| 69 | } | 70 | } |
| 70 | 71 | ||
| 71 | /** | 72 | /** |
| @@ -82,7 +83,7 @@ public: | |||
| 82 | 83 | ||
| 83 | /// Adds a new domain request handler to the collection of request handlers within | 84 | /// Adds a new domain request handler to the collection of request handlers within |
| 84 | /// this ServerSession instance. | 85 | /// this ServerSession instance. |
| 85 | void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); | 86 | void AppendDomainHandler(SessionRequestHandlerPtr handler); |
| 86 | 87 | ||
| 87 | /// Retrieves the total number of domain request handlers that have been | 88 | /// Retrieves the total number of domain request handlers that have been |
| 88 | /// appended to this ServerSession instance. | 89 | /// appended to this ServerSession instance. |
| @@ -90,12 +91,7 @@ public: | |||
| 90 | 91 | ||
| 91 | /// Returns true if the session has been converted to a domain, otherwise False | 92 | /// Returns true if the session has been converted to a domain, otherwise False |
| 92 | bool IsDomain() const { | 93 | bool IsDomain() const { |
| 93 | return !IsSession(); | 94 | return manager->IsDomain(); |
| 94 | } | ||
| 95 | |||
| 96 | /// Returns true if this session has not been converted to a domain, otherwise false. | ||
| 97 | bool IsSession() const { | ||
| 98 | return domain_request_handlers.empty(); | ||
| 99 | } | 95 | } |
| 100 | 96 | ||
| 101 | /// Converts the session to a domain at the end of the current command | 97 | /// Converts the session to a domain at the end of the current command |
| @@ -103,6 +99,21 @@ public: | |||
| 103 | convert_to_domain = true; | 99 | convert_to_domain = true; |
| 104 | } | 100 | } |
| 105 | 101 | ||
| 102 | /// Gets the session request manager, which forwards requests to the underlying service | ||
| 103 | std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() { | ||
| 104 | return manager; | ||
| 105 | } | ||
| 106 | |||
| 107 | /// Gets the session request manager, which forwards requests to the underlying service | ||
| 108 | const std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() const { | ||
| 109 | return manager; | ||
| 110 | } | ||
| 111 | |||
| 112 | /// Sets the session request manager, which forwards requests to the underlying service | ||
| 113 | void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) { | ||
| 114 | manager = std::move(manager_); | ||
| 115 | } | ||
| 116 | |||
| 106 | private: | 117 | private: |
| 107 | /// Queues a sync request from the emulated application. | 118 | /// Queues a sync request from the emulated application. |
| 108 | ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); | 119 | ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); |
| @@ -114,11 +125,8 @@ private: | |||
| 114 | /// object handle. | 125 | /// object handle. |
| 115 | ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); | 126 | ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); |
| 116 | 127 | ||
| 117 | /// This session's HLE request handler (applicable when not a domain) | 128 | /// This session's HLE request handlers |
| 118 | std::shared_ptr<SessionRequestHandler> hle_handler; | 129 | std::shared_ptr<SessionRequestManager> manager; |
| 119 | |||
| 120 | /// This is the list of domain request handlers (after conversion to a domain) | ||
| 121 | std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; | ||
| 122 | 130 | ||
| 123 | /// When set to True, converts the session to a domain at the end of the command | 131 | /// When set to True, converts the session to a domain at the end of the command |
| 124 | bool convert_to_domain{}; | 132 | bool convert_to_domain{}; |
diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index 16901e19c..a981fd1f6 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h | |||
| @@ -66,6 +66,10 @@ public: | |||
| 66 | return port; | 66 | return port; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | KClientPort* GetParent() { | ||
| 70 | return port; | ||
| 71 | } | ||
| 72 | |||
| 69 | private: | 73 | private: |
| 70 | enum class State : u8 { | 74 | enum class State : u8 { |
| 71 | Invalid = 0, | 75 | Invalid = 0, |
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 2c9b2ce6d..fa61a5c7b 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -107,7 +107,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) | |||
| 107 | ASSERT(!port_installed); | 107 | ASSERT(!port_installed); |
| 108 | 108 | ||
| 109 | auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); | 109 | auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); |
| 110 | port->SetHleHandler(shared_from_this()); | 110 | port->SetSessionHandler(shared_from_this()); |
| 111 | port_installed = true; | 111 | port_installed = true; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| @@ -118,7 +118,7 @@ Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel | |||
| 118 | 118 | ||
| 119 | auto* port = Kernel::KPort::Create(kernel); | 119 | auto* port = Kernel::KPort::Create(kernel); |
| 120 | port->Initialize(max_sessions, false, service_name); | 120 | port->Initialize(max_sessions, false, service_name); |
| 121 | port->GetServerPort().SetHleHandler(shared_from_this()); | 121 | port->GetServerPort().SetSessionHandler(shared_from_this()); |
| 122 | 122 | ||
| 123 | port_installed = true; | 123 | port_installed = true; |
| 124 | 124 | ||
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index de530cbfb..147f12147 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -4,8 +4,13 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "common/logging/log.h" | 6 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | ||
| 7 | #include "core/hle/ipc_helpers.h" | 8 | #include "core/hle/ipc_helpers.h" |
| 9 | #include "core/hle/kernel/k_client_port.h" | ||
| 8 | #include "core/hle/kernel/k_client_session.h" | 10 | #include "core/hle/kernel/k_client_session.h" |
| 11 | #include "core/hle/kernel/k_port.h" | ||
| 12 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 13 | #include "core/hle/kernel/k_server_port.h" | ||
| 9 | #include "core/hle/kernel/k_server_session.h" | 14 | #include "core/hle/kernel/k_server_session.h" |
| 10 | #include "core/hle/kernel/k_session.h" | 15 | #include "core/hle/kernel/k_session.h" |
| 11 | #include "core/hle/service/sm/controller.h" | 16 | #include "core/hle/service/sm/controller.h" |
| @@ -13,7 +18,7 @@ | |||
| 13 | namespace Service::SM { | 18 | namespace Service::SM { |
| 14 | 19 | ||
| 15 | void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { | 20 | void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { |
| 16 | ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); | 21 | ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain"); |
| 17 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); | 22 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); |
| 18 | ctx.Session()->ConvertToDomain(); | 23 | ctx.Session()->ConvertToDomain(); |
| 19 | 24 | ||
| @@ -29,16 +34,36 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { | |||
| 29 | 34 | ||
| 30 | LOG_DEBUG(Service, "called"); | 35 | LOG_DEBUG(Service, "called"); |
| 31 | 36 | ||
| 32 | auto session = ctx.Session()->GetParent(); | 37 | auto& kernel = system.Kernel(); |
| 38 | auto* session = ctx.Session()->GetParent(); | ||
| 39 | auto* port = session->GetParent()->GetParent(); | ||
| 33 | 40 | ||
| 34 | // Open a reference to the session to simulate a new one being created. | 41 | // Reserve a new session from the process resource limit. |
| 35 | session->Open(); | 42 | Kernel::KScopedResourceReservation session_reservation( |
| 36 | session->GetClientSession().Open(); | 43 | kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); |
| 37 | session->GetServerSession().Open(); | 44 | if (!session_reservation.Succeeded()) { |
| 45 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 46 | rb.Push(Kernel::ResultLimitReached); | ||
| 47 | } | ||
| 38 | 48 | ||
| 49 | // Create a new session. | ||
| 50 | auto* clone = Kernel::KSession::Create(kernel); | ||
| 51 | clone->Initialize(&port->GetClientPort(), session->GetName()); | ||
| 52 | |||
| 53 | // Commit the session reservation. | ||
| 54 | session_reservation.Commit(); | ||
| 55 | |||
| 56 | // Enqueue the session with the named port. | ||
| 57 | port->EnqueueSession(&clone->GetServerSession()); | ||
| 58 | |||
| 59 | // Set the session request manager. | ||
| 60 | clone->GetServerSession().SetSessionRequestManager( | ||
| 61 | session->GetServerSession().GetSessionRequestManager()); | ||
| 62 | |||
| 63 | // We succeeded. | ||
| 39 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 64 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
| 40 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 41 | rb.PushMoveObjects(session->GetClientSession()); | 66 | rb.PushMoveObjects(clone->GetClientSession()); |
| 42 | } | 67 | } |
| 43 | 68 | ||
| 44 | void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { | 69 | void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 391db48b1..a9bc7da74 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -150,31 +150,31 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& | |||
| 150 | IPC::RequestParser rp{ctx}; | 150 | IPC::RequestParser rp{ctx}; |
| 151 | std::string name(PopServiceName(rp)); | 151 | std::string name(PopServiceName(rp)); |
| 152 | 152 | ||
| 153 | // Find the named port. | ||
| 153 | auto result = service_manager.GetServicePort(name); | 154 | auto result = service_manager.GetServicePort(name); |
| 154 | if (result.Failed()) { | 155 | if (result.Failed()) { |
| 155 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); | 156 | LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); |
| 156 | return result.Code(); | 157 | return result.Code(); |
| 157 | } | 158 | } |
| 158 | |||
| 159 | auto* port = result.Unwrap(); | 159 | auto* port = result.Unwrap(); |
| 160 | 160 | ||
| 161 | // Reserve a new session from the process resource limit. | ||
| 161 | Kernel::KScopedResourceReservation session_reservation( | 162 | Kernel::KScopedResourceReservation session_reservation( |
| 162 | kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); | 163 | kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); |
| 163 | R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); | 164 | R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); |
| 164 | 165 | ||
| 166 | // Create a new session. | ||
| 165 | auto* session = Kernel::KSession::Create(kernel); | 167 | auto* session = Kernel::KSession::Create(kernel); |
| 166 | session->Initialize(&port->GetClientPort(), std::move(name)); | 168 | session->Initialize(&port->GetClientPort(), std::move(name)); |
| 167 | 169 | ||
| 168 | // Commit the session reservation. | 170 | // Commit the session reservation. |
| 169 | session_reservation.Commit(); | 171 | session_reservation.Commit(); |
| 170 | 172 | ||
| 171 | if (port->GetServerPort().GetHLEHandler()) { | 173 | // Enqueue the session with the named port. |
| 172 | port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); | 174 | port->EnqueueSession(&session->GetServerSession()); |
| 173 | } else { | ||
| 174 | port->EnqueueSession(&session->GetServerSession()); | ||
| 175 | } | ||
| 176 | 175 | ||
| 177 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); | 176 | LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); |
| 177 | |||
| 178 | return MakeResult(&session->GetClientSession()); | 178 | return MakeResult(&session->GetClientSession()); |
| 179 | } | 179 | } |
| 180 | 180 | ||
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 60f0b3f8a..ea37f11d4 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -73,7 +73,7 @@ public: | |||
| 73 | if (port == nullptr) { | 73 | if (port == nullptr) { |
| 74 | return nullptr; | 74 | return nullptr; |
| 75 | } | 75 | } |
| 76 | return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler()); | 76 | return std::static_pointer_cast<T>(port->GetServerPort().GetSessionRequestHandler()); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | void InvokeControlRequest(Kernel::HLERequestContext& context); | 79 | void InvokeControlRequest(Kernel::HLERequestContext& context); |