diff options
author | Liam <byteslice@airmail.cc> | 2022-10-12 00:16:56 +0200 |
---|---|---|
committer | Liam <byteslice@airmail.cc> | 2022-10-12 00:40:40 +0200 |
commit | 61a8696510b3bca120f1f0289a3829e3db14834e (patch) | |
tree | 34239a299b7cd842e46df21626f6b190e9b40d14 /src/core/hle/kernel/k_server_session.cpp | |
parent | Add implementation of svcCreateSession (diff) | |
download | yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.tar yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.tar.gz yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.tar.bz2 yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.tar.lz yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.tar.xz yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.tar.zst yuzu-61a8696510b3bca120f1f0289a3829e3db14834e.zip |
Diffstat (limited to 'src/core/hle/kernel/k_server_session.cpp')
-rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 243 |
1 files changed, 230 insertions, 13 deletions
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 802c646a6..4252c9adb 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -7,6 +7,8 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/scope_exit.h" +#include "core/core.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/hle_ipc.h" @@ -18,13 +20,19 @@ #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" #include "core/hle/kernel/k_thread.h" +#include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/service_thread.h" #include "core/memory.h" namespace Kernel { -KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} +using ThreadQueueImplForKServerSessionRequest = KThreadQueue; + +static constexpr u32 MessageBufferSize = 0x100; + +KServerSession::KServerSession(KernelCore& kernel_) + : KSynchronizationObject{kernel_}, m_lock{kernel_} {} KServerSession::~KServerSession() = default; @@ -33,17 +41,14 @@ void KServerSession::Initialize(KSession* parent_session_, std::string&& name_, // Set member variables. parent = parent_session_; name = std::move(name_); - - if (manager_) { - manager = manager_; - } else { - manager = std::make_shared<SessionRequestManager>(kernel); - } + manager = manager_; } void KServerSession::Destroy() { parent->OnServerClosed(); + this->CleanupRequests(); + parent->Close(); // Release host emulation members. @@ -54,13 +59,13 @@ void KServerSession::Destroy() { } void KServerSession::OnClientClosed() { - if (manager->HasSessionHandler()) { + if (manager && manager->HasSessionHandler()) { manager->SessionHandler().ClientDisconnected(this); } } bool KServerSession::IsSignaled() const { - ASSERT(kernel.GlobalSchedulerContext().IsLocked()); + ASSERT(KScheduler::IsSchedulerLockedByCurrentThread(kernel)); // If the client is closed, we're always signaled. if (parent->IsClientClosed()) { @@ -68,7 +73,7 @@ bool KServerSession::IsSignaled() const { } // Otherwise, we're signaled if we have a request and aren't handling one. - return false; + return !m_thread_request_list.empty() && m_current_thread_request == nullptr; } void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { @@ -173,9 +178,221 @@ Result KServerSession::CompleteSyncRequest(HLERequestContext& context) { return result; } -Result KServerSession::HandleSyncRequest(KThread* thread, Core::Memory::Memory& memory, - Core::Timing::CoreTiming& core_timing) { - return QueueSyncRequest(thread, memory); +Result KServerSession::OnRequest() { + // Create the wait queue. + ThreadQueueImplForKServerSessionRequest wait_queue{kernel}; + + { + // Lock the scheduler. + KScopedSchedulerLock sl{kernel}; + + // Ensure that we can handle new requests. + R_UNLESS(!parent->IsServerClosed(), ResultSessionClosed); + + // Check that we're not terminating. + R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), ResultTerminationRequested); + + if (manager) { + // HLE request. + auto& memory{kernel.System().Memory()}; + this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory); + } else { + // Non-HLE request. + auto* thread{GetCurrentThreadPointer(kernel)}; + + // Get whether we're empty. + const bool was_empty = m_thread_request_list.empty(); + + // Add the thread to the list. + thread->Open(); + m_thread_request_list.push_back(thread); + + // If we were empty, signal. + if (was_empty) { + this->NotifyAvailable(); + } + } + + // This is a synchronous request, so we should wait for our request to complete. + GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); + GetCurrentThread(kernel).BeginWait(&wait_queue); + } + + return GetCurrentThread(kernel).GetWaitResult(); +} + +Result KServerSession::SendReply() { + // Lock the session. + KScopedLightLock lk(m_lock); + + // Get the request. + KThread* client_thread; + { + KScopedSchedulerLock sl{kernel}; + + // Get the current request. + client_thread = m_current_thread_request; + R_UNLESS(client_thread != nullptr, ResultInvalidState); + + // Clear the current request, since we're processing it. + m_current_thread_request = nullptr; + if (!m_thread_request_list.empty()) { + this->NotifyAvailable(); + } + } + + // Close reference to the request once we're done processing it. + SCOPE_EXIT({ client_thread->Close(); }); + + // Extract relevant information from the request. + // const uintptr_t client_message = request->GetAddress(); + // const size_t client_buffer_size = request->GetSize(); + // KThread *client_thread = request->GetThread(); + // KEvent *event = request->GetEvent(); + + // Check whether we're closed. + const bool closed = (client_thread == nullptr || parent->IsClientClosed()); + + Result result = ResultSuccess; + if (!closed) { + // If we're not closed, send the reply. + Core::Memory::Memory& memory{kernel.System().Memory()}; + KThread* server_thread{GetCurrentThreadPointer(kernel)}; + UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); + + auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); + auto* dst_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress()); + std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize); + } else { + result = ResultSessionClosed; + } + + // Select a result for the client. + Result client_result = result; + if (closed && R_SUCCEEDED(result)) { + result = ResultSessionClosed; + client_result = ResultSessionClosed; + } else { + result = ResultSuccess; + } + + // If there's a client thread, update it. + if (client_thread != nullptr) { + // End the client thread's wait. + KScopedSchedulerLock sl{kernel}; + + if (!client_thread->IsTerminationRequested()) { + client_thread->EndWait(client_result); + } + } + + return result; +} + +Result KServerSession::ReceiveRequest() { + // Lock the session. + KScopedLightLock lk(m_lock); + + // Get the request and client thread. + // KSessionRequest *request; + KThread* client_thread; + + { + KScopedSchedulerLock sl{kernel}; + + // Ensure that we can service the request. + R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed); + + // Ensure we aren't already servicing a request. + R_UNLESS(m_current_thread_request == nullptr, ResultNotFound); + + // Ensure we have a request to service. + R_UNLESS(!m_thread_request_list.empty(), ResultNotFound); + + // Pop the first request from the list. + client_thread = m_thread_request_list.front(); + m_thread_request_list.pop_front(); + + // Get the thread for the request. + R_UNLESS(client_thread != nullptr, ResultSessionClosed); + + // Open the client thread. + client_thread->Open(); + } + + // SCOPE_EXIT({ client_thread->Close(); }); + + // Set the request as our current. + m_current_thread_request = client_thread; + + // Receive the message. + Core::Memory::Memory& memory{kernel.System().Memory()}; + KThread* server_thread{GetCurrentThreadPointer(kernel)}; + UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess()); + + auto* src_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress()); + auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress()); + std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize); + + // We succeeded. + return ResultSuccess; +} + +void KServerSession::CleanupRequests() { + KScopedLightLock lk(m_lock); + + // Clean up any pending requests. + while (true) { + // Get the next request. + // KSessionRequest *request = nullptr; + KThread* client_thread = nullptr; + { + KScopedSchedulerLock sl{kernel}; + + if (m_current_thread_request) { + // Choose the current request if we have one. + client_thread = m_current_thread_request; + m_current_thread_request = nullptr; + } else if (!m_thread_request_list.empty()) { + // Pop the request from the front of the list. + client_thread = m_thread_request_list.front(); + m_thread_request_list.pop_front(); + } + } + + // If there's no request, we're done. + if (client_thread == nullptr) { + break; + } + + // Close a reference to the request once it's cleaned up. + SCOPE_EXIT({ client_thread->Close(); }); + + // Extract relevant information from the request. + // const uintptr_t client_message = request->GetAddress(); + // const size_t client_buffer_size = request->GetSize(); + // KThread *client_thread = request->GetThread(); + // KEvent *event = request->GetEvent(); + + // KProcess *server_process = request->GetServerProcess(); + // KProcess *client_process = (client_thread != nullptr) ? + // client_thread->GetOwnerProcess() : nullptr; + // KProcessPageTable *client_page_table = (client_process != nullptr) ? + // &client_process->GetPageTable() : nullptr; + + // Cleanup the mappings. + // Result result = CleanupMap(request, server_process, client_page_table); + + // If there's a client thread, update it. + if (client_thread != nullptr) { + // End the client thread's wait. + KScopedSchedulerLock sl{kernel}; + + if (!client_thread->IsTerminationRequested()) { + client_thread->EndWait(ResultSessionClosed); + } + } + } } } // namespace Kernel |