summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/k_server_session.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/k_server_session.cpp')
-rw-r--r--src/core/hle/kernel/k_server_session.cpp143
1 files changed, 90 insertions, 53 deletions
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 4252c9adb..685a2a6e6 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -29,8 +29,6 @@ namespace Kernel {
using ThreadQueueImplForKServerSessionRequest = KThreadQueue;
-static constexpr u32 MessageBufferSize = 0x100;
-
KServerSession::KServerSession(KernelCore& kernel_)
: KSynchronizationObject{kernel_}, m_lock{kernel_} {}
@@ -73,7 +71,7 @@ bool KServerSession::IsSignaled() const {
}
// 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;
+ return !m_request_list.empty() && m_current_request == nullptr;
}
void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) {
@@ -178,7 +176,7 @@ Result KServerSession::CompleteSyncRequest(HLERequestContext& context) {
return result;
}
-Result KServerSession::OnRequest() {
+Result KServerSession::OnRequest(KSessionRequest* request) {
// Create the wait queue.
ThreadQueueImplForKServerSessionRequest wait_queue{kernel};
@@ -198,14 +196,13 @@ Result KServerSession::OnRequest() {
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();
+ 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 (was_empty) {
@@ -213,6 +210,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.
GetCurrentThread(kernel).SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
GetCurrentThread(kernel).BeginWait(&wait_queue);
@@ -223,32 +223,32 @@ Result KServerSession::OnRequest() {
Result KServerSession::SendReply() {
// Lock the session.
- KScopedLightLock lk(m_lock);
+ KScopedLightLock lk{m_lock};
// Get the request.
- KThread* client_thread;
+ KSessionRequest* request;
{
KScopedSchedulerLock sl{kernel};
// 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.
- m_current_thread_request = nullptr;
- if (!m_thread_request_list.empty()) {
+ m_current_request = nullptr;
+ if (!m_request_list.empty()) {
this->NotifyAvailable();
}
}
// 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.
- // 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.
const bool closed = (client_thread == nullptr || parent->IsClientClosed());
@@ -261,8 +261,8 @@ Result KServerSession::SendReply() {
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);
+ auto* dst_msg_buffer = memory.GetPointer(client_message);
+ std::memcpy(dst_msg_buffer, src_msg_buffer, client_buffer_size);
} else {
result = ResultSessionClosed;
}
@@ -278,11 +278,30 @@ Result KServerSession::SendReply() {
// If there's a client thread, update it.
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 +310,10 @@ Result KServerSession::SendReply() {
Result KServerSession::ReceiveRequest() {
// Lock the session.
- KScopedLightLock lk(m_lock);
+ KScopedLightLock lk{m_lock};
// Get the request and client thread.
- // KSessionRequest *request;
+ KSessionRequest* request;
KThread* client_thread;
{
@@ -304,35 +323,41 @@ Result KServerSession::ReceiveRequest() {
R_UNLESS(!parent->IsClientClosed(), ResultSessionClosed);
// 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.
- R_UNLESS(!m_thread_request_list.empty(), ResultNotFound);
+ R_UNLESS(!m_request_list.empty(), ResultNotFound);
// 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.
+ client_thread = request->GetThread();
R_UNLESS(client_thread != nullptr, ResultSessionClosed);
// Open the client thread.
client_thread->Open();
}
- // SCOPE_EXIT({ client_thread->Close(); });
+ SCOPE_EXIT({ client_thread->Close(); });
// 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.
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* src_msg_buffer = memory.GetPointer(client_message);
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.
return ResultSuccess;
@@ -344,35 +369,34 @@ void KServerSession::CleanupRequests() {
// Clean up any pending requests.
while (true) {
// Get the next request.
- // KSessionRequest *request = nullptr;
- KThread* client_thread = nullptr;
+ KSessionRequest* request = nullptr;
{
KScopedSchedulerLock sl{kernel};
- if (m_current_thread_request) {
+ if (m_current_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()) {
+ request = m_current_request;
+ m_current_request = nullptr;
+ } else if (!m_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();
+ request = &m_request_list.front();
+ m_request_list.pop_front();
}
}
// If there's no request, we're done.
- if (client_thread == nullptr) {
+ if (request == nullptr) {
break;
}
// 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.
// const uintptr_t client_message = request->GetAddress();
// 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 *client_process = (client_thread != nullptr) ?
@@ -385,11 +409,24 @@ void KServerSession::CleanupRequests() {
// 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);
+ 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);
+ }
}
}
}