|
@@ -22,15 +22,12 @@
|
|
|
#include "core/hle/kernel/k_thread.h"
|
|
#include "core/hle/kernel/k_thread.h"
|
|
|
#include "core/hle/kernel/k_thread_queue.h"
|
|
#include "core/hle/kernel/k_thread_queue.h"
|
|
|
#include "core/hle/kernel/kernel.h"
|
|
#include "core/hle/kernel/kernel.h"
|
|
|
-#include "core/hle/kernel/service_thread.h"
|
|
|
|
|
#include "core/memory.h"
|
|
#include "core/memory.h"
|
|
|
|
|
|
|
|
namespace Kernel {
|
|
namespace Kernel {
|
|
|
|
|
|
|
|
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
|
|
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
|
|
|
|
|
|
|
|
-static constexpr u32 MessageBufferSize = 0x100;
|
|
|
|
|
-
|
|
|
|
|
KServerSession::KServerSession(KernelCore& kernel_)
|
|
KServerSession::KServerSession(KernelCore& kernel_)
|
|
|
: KSynchronizationObject{kernel_}, m_lock{kernel_} {}
|
|
: KSynchronizationObject{kernel_}, m_lock{kernel_} {}
|
|
|
|
|
|
|
@@ -73,59 +70,7 @@ bool KServerSession::IsSignaled() const {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we're signaled if we have a request and aren't handling one.
|
|
// Otherwise, we're signaled if we have a request and aren't handling one.
|
|
|
- return !m_thread_request_list.empty() && m_current_thread_request == nullptr;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) {
|
|
|
|
|
- manager->AppendDomainHandler(std::move(handler));
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-std::size_t KServerSession::NumDomainRequestHandlers() const {
|
|
|
|
|
- return manager->DomainHandlerCount();
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-Result KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
|
|
|
|
|
- if (!context.HasDomainMessageHeader()) {
|
|
|
|
|
- return ResultSuccess;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
|
|
|
|
|
- context.SetSessionRequestManager(manager);
|
|
|
|
|
-
|
|
|
|
|
- // If there is a DomainMessageHeader, then this is CommandType "Request"
|
|
|
|
|
- const auto& domain_message_header = context.GetDomainMessageHeader();
|
|
|
|
|
- const u32 object_id{domain_message_header.object_id};
|
|
|
|
|
- switch (domain_message_header.command) {
|
|
|
|
|
- case IPC::DomainMessageHeader::CommandType::SendMessage:
|
|
|
|
|
- if (object_id > manager->DomainHandlerCount()) {
|
|
|
|
|
- LOG_CRITICAL(IPC,
|
|
|
|
|
- "object_id {} is too big! This probably means a recent service call "
|
|
|
|
|
- "to {} needed to return a new interface!",
|
|
|
|
|
- object_id, name);
|
|
|
|
|
- ASSERT(false);
|
|
|
|
|
- return ResultSuccess; // Ignore error if asserts are off
|
|
|
|
|
- }
|
|
|
|
|
- if (auto strong_ptr = manager->DomainHandler(object_id - 1).lock()) {
|
|
|
|
|
- return strong_ptr->HandleSyncRequest(*this, context);
|
|
|
|
|
- } else {
|
|
|
|
|
- ASSERT(false);
|
|
|
|
|
- return ResultSuccess;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
|
|
|
|
|
- LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id);
|
|
|
|
|
-
|
|
|
|
|
- manager->CloseDomainHandler(object_id - 1);
|
|
|
|
|
-
|
|
|
|
|
- IPC::ResponseBuilder rb{context, 2};
|
|
|
|
|
- rb.Push(ResultSuccess);
|
|
|
|
|
- return ResultSuccess;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- LOG_CRITICAL(IPC, "Unknown domain command={}", domain_message_header.command.Value());
|
|
|
|
|
- ASSERT(false);
|
|
|
|
|
- return ResultSuccess;
|
|
|
|
|
|
|
+ return !m_request_list.empty() && m_current_request == nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
|
|
Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory) {
|
|
@@ -134,43 +79,11 @@ Result KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memory& m
|
|
|
|
|
|
|
|
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
|
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
|
|
|
|
|
|
|
- // Ensure we have a session request handler
|
|
|
|
|
- if (manager->HasSessionRequestHandler(*context)) {
|
|
|
|
|
- if (auto strong_ptr = manager->GetServiceThread().lock()) {
|
|
|
|
|
- strong_ptr->QueueSyncRequest(*parent, std::move(context));
|
|
|
|
|
- } else {
|
|
|
|
|
- ASSERT_MSG(false, "strong_ptr is nullptr!");
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- ASSERT_MSG(false, "handler is invalid!");
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return ResultSuccess;
|
|
|
|
|
|
|
+ return manager->QueueSyncRequest(parent, std::move(context));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
|
Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
|
|
- Result result = ResultSuccess;
|
|
|
|
|
-
|
|
|
|
|
- // If the session has been converted to a domain, handle the domain request
|
|
|
|
|
- if (manager->HasSessionRequestHandler(context)) {
|
|
|
|
|
- if (IsDomain() && context.HasDomainMessageHeader()) {
|
|
|
|
|
- result = HandleDomainSyncRequest(context);
|
|
|
|
|
- // If there is no domain header, the regular session handler is used
|
|
|
|
|
- } else if (manager->HasSessionHandler()) {
|
|
|
|
|
- // If this ServerSession has an associated HLE handler, forward the request to it.
|
|
|
|
|
- result = manager->SessionHandler().HandleSyncRequest(*this, context);
|
|
|
|
|
- }
|
|
|
|
|
- } else {
|
|
|
|
|
- ASSERT_MSG(false, "Session handler is invalid, stubbing response!");
|
|
|
|
|
- IPC::ResponseBuilder rb(context, 2);
|
|
|
|
|
- rb.Push(ResultSuccess);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (convert_to_domain) {
|
|
|
|
|
- ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance.");
|
|
|
|
|
- manager->ConvertToDomain();
|
|
|
|
|
- convert_to_domain = false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ Result result = manager->CompleteSyncRequest(this, context);
|
|
|
|
|
|
|
|
// The calling thread is waiting for this request to complete, so wake it up.
|
|
// The calling thread is waiting for this request to complete, so wake it up.
|
|
|
context.GetThread().EndWait(result);
|
|
context.GetThread().EndWait(result);
|
|
@@ -178,7 +91,7 @@ Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-Result KServerSession::OnRequest() {
|
|
|
|
|
|
|
+Result KServerSession::OnRequest(KSessionRequest* request) {
|
|
|
// Create the wait queue.
|
|
// Create the wait queue.
|
|
|
ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
|
|
ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
|
|
|
|
|
|
|
@@ -198,14 +111,13 @@ Result KServerSession::OnRequest() {
|
|
|
this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
|
|
this->QueueSyncRequest(GetCurrentThreadPointer(kernel), memory);
|
|
|
} else {
|
|
} else {
|
|
|
// Non-HLE request.
|
|
// Non-HLE request.
|
|
|
- auto* thread{GetCurrentThreadPointer(kernel)};
|
|
|
|
|
|
|
|
|
|
// Get whether we're empty.
|
|
// Get whether we're empty.
|
|
|
- const bool was_empty = m_thread_request_list.empty();
|
|
|
|
|
|
|
+ const bool was_empty = m_request_list.empty();
|
|
|
|
|
|
|
|
- // Add the thread to the list.
|
|
|
|
|
- thread->Open();
|
|
|
|
|
- m_thread_request_list.push_back(thread);
|
|
|
|
|
|
|
+ // Add the request to the list.
|
|
|
|
|
+ request->Open();
|
|
|
|
|
+ m_request_list.push_back(*request);
|
|
|
|
|
|
|
|
// If we were empty, signal.
|
|
// If we were empty, signal.
|
|
|
if (was_empty) {
|
|
if (was_empty) {
|
|
@@ -213,6 +125,9 @@ Result KServerSession::OnRequest() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // If we have a request event, this is asynchronous, and we don't need to wait.
|
|
|
|
|
+ R_SUCCEED_IF(request->GetEvent() != nullptr);
|
|
|
|
|
+
|
|
|
// This is a synchronous request, so we should wait for our request to complete.
|
|
// This is a synchronous request, so we should wait for our request to complete.
|
|
|
GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
|
|
GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
|
|
|
GetCurrentThread(kernel).BeginWait(&wait_queue);
|
|
GetCurrentThread(kernel).BeginWait(&wait_queue);
|
|
@@ -223,32 +138,32 @@ Result KServerSession::OnRequest() {
|
|
|
|
|
|
|
|
Result KServerSession::SendReply() {
|
|
Result KServerSession::SendReply() {
|
|
|
// Lock the session.
|
|
// Lock the session.
|
|
|
- KScopedLightLock lk(m_lock);
|
|
|
|
|
|
|
+ KScopedLightLock lk{m_lock};
|
|
|
|
|
|
|
|
// Get the request.
|
|
// Get the request.
|
|
|
- KThread* client_thread;
|
|
|
|
|
|
|
+ KSessionRequest* request;
|
|
|
{
|
|
{
|
|
|
KScopedSchedulerLock sl{kernel};
|
|
KScopedSchedulerLock sl{kernel};
|
|
|
|
|
|
|
|
// Get the current request.
|
|
// Get the current request.
|
|
|
- client_thread = m_current_thread_request;
|
|
|
|
|
- R_UNLESS(client_thread != nullptr, ResultInvalidState);
|
|
|
|
|
|
|
+ request = m_current_request;
|
|
|
|
|
+ R_UNLESS(request != nullptr, ResultInvalidState);
|
|
|
|
|
|
|
|
// Clear the current request, since we're processing it.
|
|
// Clear the current request, since we're processing it.
|
|
|
- m_current_thread_request = nullptr;
|
|
|
|
|
- if (!m_thread_request_list.empty()) {
|
|
|
|
|
|
|
+ m_current_request = nullptr;
|
|
|
|
|
+ if (!m_request_list.empty()) {
|
|
|
this->NotifyAvailable();
|
|
this->NotifyAvailable();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Close reference to the request once we're done processing it.
|
|
// Close reference to the request once we're done processing it.
|
|
|
- SCOPE_EXIT({ client_thread->Close(); });
|
|
|
|
|
|
|
+ SCOPE_EXIT({ request->Close(); });
|
|
|
|
|
|
|
|
// Extract relevant information from the request.
|
|
// 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();
|
|
|
|
|
|
|
+ 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.
|
|
// Check whether we're closed.
|
|
|
const bool closed = (client_thread == nullptr || parent->IsClientClosed());
|
|
const bool closed = (client_thread == nullptr || parent->IsClientClosed());
|
|
@@ -261,8 +176,8 @@ Result KServerSession::SendReply() {
|
|
|
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
|
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
|
|
|
|
|
|
|
auto* src_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
|
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);
|
|
|
|
|
|
|
+ auto* dst_msg_buffer = memory.GetPointer(client_message);
|
|
|
|
|
+ std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
|
|
} else {
|
|
} else {
|
|
|
result = ResultSessionClosed;
|
|
result = ResultSessionClosed;
|
|
|
}
|
|
}
|
|
@@ -278,11 +193,30 @@ Result KServerSession::SendReply() {
|
|
|
|
|
|
|
|
// If there's a client thread, update it.
|
|
// If there's a client thread, update it.
|
|
|
if (client_thread != nullptr) {
|
|
if (client_thread != nullptr) {
|
|
|
- // End the client thread's wait.
|
|
|
|
|
- KScopedSchedulerLock sl{kernel};
|
|
|
|
|
|
|
+ if (event != nullptr) {
|
|
|
|
|
+ // // Get the client process/page table.
|
|
|
|
|
+ // KProcess *client_process = client_thread->GetOwnerProcess();
|
|
|
|
|
+ // KPageTable *client_page_table = &client_process->PageTable();
|
|
|
|
|
+
|
|
|
|
|
+ // // If we need to, reply with an async error.
|
|
|
|
|
+ // if (R_FAILED(client_result)) {
|
|
|
|
|
+ // ReplyAsyncError(client_process, client_message, client_buffer_size,
|
|
|
|
|
+ // client_result);
|
|
|
|
|
+ // }
|
|
|
|
|
+
|
|
|
|
|
+ // // Unlock the client buffer.
|
|
|
|
|
+ // // NOTE: Nintendo does not check the result of this.
|
|
|
|
|
+ // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
|
|
|
|
|
+
|
|
|
|
|
+ // Signal the event.
|
|
|
|
|
+ event->Signal();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // End the client thread's wait.
|
|
|
|
|
+ KScopedSchedulerLock sl{kernel};
|
|
|
|
|
|
|
|
- if (!client_thread->IsTerminationRequested()) {
|
|
|
|
|
- client_thread->EndWait(client_result);
|
|
|
|
|
|
|
+ if (!client_thread->IsTerminationRequested()) {
|
|
|
|
|
+ client_thread->EndWait(client_result);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -291,10 +225,10 @@ Result KServerSession::SendReply() {
|
|
|
|
|
|
|
|
Result KServerSession::ReceiveRequest() {
|
|
Result KServerSession::ReceiveRequest() {
|
|
|
// Lock the session.
|
|
// Lock the session.
|
|
|
- KScopedLightLock lk(m_lock);
|
|
|
|
|
|
|
+ KScopedLightLock lk{m_lock};
|
|
|
|
|
|
|
|
// Get the request and client thread.
|
|
// Get the request and client thread.
|
|
|
- // KSessionRequest *request;
|
|
|
|
|
|
|
+ KSessionRequest* request;
|
|
|
KThread* client_thread;
|
|
KThread* client_thread;
|
|
|
|
|
|
|
|
{
|
|
{
|
|
@@ -304,35 +238,41 @@ Result KServerSession::ReceiveRequest() {
|
|
|
R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
|
|
R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
|
|
|
|
|
|
|
|
// Ensure we aren't already servicing a request.
|
|
// Ensure we aren't already servicing a request.
|
|
|
- R_UNLESS(m_current_thread_request == nullptr, ResultNotFound);
|
|
|
|
|
|
|
+ R_UNLESS(m_current_request == nullptr, ResultNotFound);
|
|
|
|
|
|
|
|
// Ensure we have a request to service.
|
|
// Ensure we have a request to service.
|
|
|
- R_UNLESS(!m_thread_request_list.empty(), ResultNotFound);
|
|
|
|
|
|
|
+ R_UNLESS(!m_request_list.empty(), ResultNotFound);
|
|
|
|
|
|
|
|
// Pop the first request from the list.
|
|
// Pop the first request from the list.
|
|
|
- client_thread = m_thread_request_list.front();
|
|
|
|
|
- m_thread_request_list.pop_front();
|
|
|
|
|
|
|
+ request = &m_request_list.front();
|
|
|
|
|
+ m_request_list.pop_front();
|
|
|
|
|
|
|
|
// Get the thread for the request.
|
|
// Get the thread for the request.
|
|
|
|
|
+ client_thread = request->GetThread();
|
|
|
R_UNLESS(client_thread != nullptr, ResultSessionClosed);
|
|
R_UNLESS(client_thread != nullptr, ResultSessionClosed);
|
|
|
|
|
|
|
|
// Open the client thread.
|
|
// Open the client thread.
|
|
|
client_thread->Open();
|
|
client_thread->Open();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // SCOPE_EXIT({ client_thread->Close(); });
|
|
|
|
|
|
|
+ SCOPE_EXIT({ client_thread->Close(); });
|
|
|
|
|
|
|
|
// Set the request as our current.
|
|
// Set the request as our current.
|
|
|
- m_current_thread_request = client_thread;
|
|
|
|
|
|
|
+ m_current_request = request;
|
|
|
|
|
+
|
|
|
|
|
+ // Get the client address.
|
|
|
|
|
+ uintptr_t client_message = request->GetAddress();
|
|
|
|
|
+ size_t client_buffer_size = request->GetSize();
|
|
|
|
|
+ // bool recv_list_broken = false;
|
|
|
|
|
|
|
|
// Receive the message.
|
|
// Receive the message.
|
|
|
Core::Memory::Memory& memory{kernel.System().Memory()};
|
|
Core::Memory::Memory& memory{kernel.System().Memory()};
|
|
|
KThread* server_thread{GetCurrentThreadPointer(kernel)};
|
|
KThread* server_thread{GetCurrentThreadPointer(kernel)};
|
|
|
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
|
UNIMPLEMENTED_IF(server_thread->GetOwnerProcess() != client_thread->GetOwnerProcess());
|
|
|
|
|
|
|
|
- auto* src_msg_buffer = memory.GetPointer(client_thread->GetTLSAddress());
|
|
|
|
|
|
|
+ auto* src_msg_buffer = memory.GetPointer(client_message);
|
|
|
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
|
auto* dst_msg_buffer = memory.GetPointer(server_thread->GetTLSAddress());
|
|
|
- std::memcpy(dst_msg_buffer, src_msg_buffer, MessageBufferSize);
|
|
|
|
|
|
|
+ std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
|
|
|
|
|
|
|
|
// We succeeded.
|
|
// We succeeded.
|
|
|
return ResultSuccess;
|
|
return ResultSuccess;
|
|
@@ -344,35 +284,34 @@ void KServerSession::CleanupRequests() {
|
|
|
// Clean up any pending requests.
|
|
// Clean up any pending requests.
|
|
|
while (true) {
|
|
while (true) {
|
|
|
// Get the next request.
|
|
// Get the next request.
|
|
|
- // KSessionRequest *request = nullptr;
|
|
|
|
|
- KThread* client_thread = nullptr;
|
|
|
|
|
|
|
+ KSessionRequest* request = nullptr;
|
|
|
{
|
|
{
|
|
|
KScopedSchedulerLock sl{kernel};
|
|
KScopedSchedulerLock sl{kernel};
|
|
|
|
|
|
|
|
- if (m_current_thread_request) {
|
|
|
|
|
|
|
+ if (m_current_request) {
|
|
|
// Choose the current request if we have one.
|
|
// 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()) {
|
|
|
|
|
|
|
+ request = m_current_request;
|
|
|
|
|
+ m_current_request = nullptr;
|
|
|
|
|
+ } else if (!m_request_list.empty()) {
|
|
|
// Pop the request from the front of the list.
|
|
// Pop the request from the front of the list.
|
|
|
- client_thread = m_thread_request_list.front();
|
|
|
|
|
- m_thread_request_list.pop_front();
|
|
|
|
|
|
|
+ request = &m_request_list.front();
|
|
|
|
|
+ m_request_list.pop_front();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// If there's no request, we're done.
|
|
// If there's no request, we're done.
|
|
|
- if (client_thread == nullptr) {
|
|
|
|
|
|
|
+ if (request == nullptr) {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Close a reference to the request once it's cleaned up.
|
|
// Close a reference to the request once it's cleaned up.
|
|
|
- SCOPE_EXIT({ client_thread->Close(); });
|
|
|
|
|
|
|
+ SCOPE_EXIT({ request->Close(); });
|
|
|
|
|
|
|
|
// Extract relevant information from the request.
|
|
// Extract relevant information from the request.
|
|
|
// const uintptr_t client_message = request->GetAddress();
|
|
// const uintptr_t client_message = request->GetAddress();
|
|
|
// const size_t client_buffer_size = request->GetSize();
|
|
// const size_t client_buffer_size = request->GetSize();
|
|
|
- // KThread *client_thread = request->GetThread();
|
|
|
|
|
- // KEvent *event = request->GetEvent();
|
|
|
|
|
|
|
+ KThread* client_thread = request->GetThread();
|
|
|
|
|
+ KEvent* event = request->GetEvent();
|
|
|
|
|
|
|
|
// KProcess *server_process = request->GetServerProcess();
|
|
// KProcess *server_process = request->GetServerProcess();
|
|
|
// KProcess *client_process = (client_thread != nullptr) ?
|
|
// KProcess *client_process = (client_thread != nullptr) ?
|
|
@@ -385,11 +324,24 @@ void KServerSession::CleanupRequests() {
|
|
|
|
|
|
|
|
// If there's a client thread, update it.
|
|
// If there's a client thread, update it.
|
|
|
if (client_thread != nullptr) {
|
|
if (client_thread != nullptr) {
|
|
|
- // End the client thread's wait.
|
|
|
|
|
- KScopedSchedulerLock sl{kernel};
|
|
|
|
|
-
|
|
|
|
|
- if (!client_thread->IsTerminationRequested()) {
|
|
|
|
|
- client_thread->EndWait(ResultSessionClosed);
|
|
|
|
|
|
|
+ if (event != nullptr) {
|
|
|
|
|
+ // // We need to reply async.
|
|
|
|
|
+ // ReplyAsyncError(client_process, client_message, client_buffer_size,
|
|
|
|
|
+ // (R_SUCCEEDED(result) ? ResultSessionClosed : result));
|
|
|
|
|
+
|
|
|
|
|
+ // // Unlock the client buffer.
|
|
|
|
|
+ // NOTE: Nintendo does not check the result of this.
|
|
|
|
|
+ // client_page_table->UnlockForIpcUserBuffer(client_message, client_buffer_size);
|
|
|
|
|
+
|
|
|
|
|
+ // Signal the event.
|
|
|
|
|
+ event->Signal();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // End the client thread's wait.
|
|
|
|
|
+ KScopedSchedulerLock sl{kernel};
|
|
|
|
|
+
|
|
|
|
|
+ if (!client_thread->IsTerminationRequested()) {
|
|
|
|
|
+ client_thread->EndWait(ResultSessionClosed);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|