From b42faa8f85c96ecfe9ddd4f9eb47e67ec2d36ee1 Mon Sep 17 00:00:00 2001 From: visha Date: Tue, 13 Feb 2018 22:24:30 +0530 Subject: [PATCH 1/5] Putting guest thread to sleep inside handler --- src/core/hle/kernel/hle_ipc.cpp | 34 ++++++++++++++++++++++++++++++++ src/core/hle/kernel/hle_ipc.h | 20 +++++++++++++++++++ src/core/hle/kernel/thread.cpp | 3 ++- src/core/hle/service/service.cpp | 12 ++++++++--- 4 files changed, 65 insertions(+), 4 deletions(-) diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index db104e8a26..1df75c9f7a 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -7,6 +7,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/kernel.h" @@ -25,6 +26,39 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr server_s boost::range::remove_erase(connected_sessions, server_session); } +SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, + const std::string& reason, u64 timeout, + WakeupCallback&& callback) { + // Put the client thread to sleep until the wait event is signaled or the timeout expires. + thread->wakeup_callback = [ context = *this, callback ]( + ThreadWakeupReason reason, SharedPtr thread, SharedPtr object) mutable { + ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT); + callback(thread, context, reason); + + auto& process = thread->owner_process; + // We must copy the entire command buffer *plus* the entire static buffers area, since + // the translation might need to read from it in order to retrieve the StaticBuffer + // target addresses. + std::array cmd_buff; + Memory::ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(), + cmd_buff.size() * sizeof(u32)); + context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process, Kernel::g_handle_table); + // Copy the translated command buffer back into the thread's command buffer area. + Memory::WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(), + cmd_buff.size() * sizeof(u32)); + }; + + auto event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); + thread->status = THREADSTATUS_WAIT_HLE_EVENT; + thread->wait_objects = {event}; + event->AddWaitingThread(thread); + + if (timeout > 0) + thread->WakeAfterDelay(timeout); + + return event; +} + HLERequestContext::HLERequestContext(SharedPtr server_session) : server_session(std::move(server_session)) { cmd_buf[0] = 0; diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index da8335b35b..45f86b1013 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "common/common_types.h" #include "common/swap.h" @@ -24,6 +25,8 @@ class Domain; class HandleTable; class HLERequestContext; class Process; +class Thread; +class Event; /** * Interface implemented by HLE Session handlers. @@ -102,6 +105,23 @@ public: return server_session; } + using WakeupCallback = std::function thread, HLERequestContext& context, + ThreadWakeupReason reason)>; + + /* + * Puts the specified guest thread to sleep until the returned event is signaled or until the + * specified timeout expires. + * @param thread Thread to be put to sleep. + * @param reason Reason for pausing the thread, to be used for debugging purposes. + * @param timeout Timeout in nanoseconds after which the thread will be awoken and the callback + * invoked with a Timeout reason. + * @param callback Callback to be invoked when the thread is resumed. This callback must write + * the entire command response once again, regardless of the state of it before this function + * was called. + * @returns Event that when signaled will resume the thread and call the callback function. + */ + SharedPtr SleepClientThread(SharedPtr thread, const std::string& reason, + u64 timeout, WakeupCallback&& callback); void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming); /// Populates this context with data from the requesting process/thread. diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 111c496b92..56ef9eca9f 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -247,7 +247,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { bool resume = true; if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || - thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { + thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB + || thread->status == THREADSTATUS_WAIT_HLE_EVENT) { // Remove the thread from each of its waiting objects' waitlists for (auto& object : thread->wait_objects) diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 1dd04a12f4..2d3c77d75d 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -150,9 +150,15 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co } u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress()); - context.WriteToOutgoingCommandBuffer(cmd_buf, *Kernel::g_current_process, - Kernel::g_handle_table); - + auto thread = Kernel::GetCurrentThread(); + ASSERT(thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_WAIT_HLE_EVENT); + // Only write the response immediately if the thread is still running. If the HLE handler put + // the thread to sleep then the writing of the command buffer will be deferred to the wakeup + // callback. + if (thread->status == THREADSTATUS_RUNNING) { + context.WriteToOutgoingCommandBuffer(cmd_buf, *Kernel::g_current_process, + Kernel::g_handle_table); + } return RESULT_SUCCESS; } From 943a895ae25dbd8de2c33c72cf5f0caec2d6fca1 Mon Sep 17 00:00:00 2001 From: Vishal Sharma Date: Wed, 21 Feb 2018 20:40:02 +0530 Subject: [PATCH 2/5] Corrections for travis fail --- src/core/hle/kernel/hle_ipc.cpp | 5 +++-- src/core/hle/kernel/hle_ipc.h | 2 +- src/core/hle/kernel/thread.cpp | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 1df75c9f7a..b878824531 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -30,8 +30,9 @@ SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, const std::string& reason, u64 timeout, WakeupCallback&& callback) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->wakeup_callback = [ context = *this, callback ]( - ThreadWakeupReason reason, SharedPtr thread, SharedPtr object) mutable { + thread->wakeup_callback = [ context = *this, callback ](ThreadWakeupReason reason, + SharedPtr thread, + SharedPtr object) mutable { ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT); callback(thread, context, reason); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 45f86b1013..cdd8c5e1a4 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -6,8 +6,8 @@ #include #include -#include #include +#include #include #include "common/common_types.h" #include "common/swap.h" diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 56ef9eca9f..fdf7c8e46b 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -247,8 +247,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { bool resume = true; if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || - thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB - || thread->status == THREADSTATUS_WAIT_HLE_EVENT) { + thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB || + thread->status == THREADSTATUS_WAIT_HLE_EVENT) { // Remove the thread from each of its waiting objects' waitlists for (auto& object : thread->wait_objects) From 6f35472e41ff894b950e88bbb87ab1c39302bf7a Mon Sep 17 00:00:00 2001 From: Vishal Sharma Date: Wed, 21 Feb 2018 20:47:15 +0530 Subject: [PATCH 3/5] Corrections for travis --- src/core/hle/kernel/hle_ipc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index b878824531..953a7604f8 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -30,7 +30,7 @@ SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, const std::string& reason, u64 timeout, WakeupCallback&& callback) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->wakeup_callback = [ context = *this, callback ](ThreadWakeupReason reason, + thread->wakeup_callback = [context = *this, callback](ThreadWakeupReason reason, SharedPtr thread, SharedPtr object) mutable { ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT); From 3ab0a703b5b260a2a065d11daef1e31df7dfecf1 Mon Sep 17 00:00:00 2001 From: Vishal Sharma Date: Fri, 9 Mar 2018 01:20:38 +0530 Subject: [PATCH 4/5] Completes all the changes for hle handler building successfully --- src/core/hle/ipc.h | 2 ++ src/core/hle/kernel/hle_ipc.cpp | 23 ++++++++++++----------- src/core/hle/kernel/hle_ipc.h | 5 ++--- src/core/hle/kernel/thread.h | 1 + src/yuzu/main.cpp | 3 ++- 5 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 0dcaede678..3a1c080af0 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -14,6 +14,8 @@ namespace IPC { /// Size of the command buffer area, in 32-bit words. constexpr size_t COMMAND_BUFFER_LENGTH = 0x100 / sizeof(u32); +/// Maximum number of static buffers per thread +constexpr size_t MAX_STATIC_BUFFERS = 16; // These errors are commonly returned by invalid IPC translations, so alias them here for // convenience. // TODO(yuriks): These will probably go away once translation is implemented inside the kernel. diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 953a7604f8..be855adc28 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -26,15 +26,23 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr server_s boost::range::remove_erase(connected_sessions, server_session); } +HLERequestContext::HLERequestContext(SharedPtr server_session) + : server_session(std::move(server_session)) { + cmd_buf[0] = 0; +} + +HLERequestContext::~HLERequestContext() = default; + SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, const std::string& reason, u64 timeout, WakeupCallback&& callback) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->wakeup_callback = [context = *this, callback](ThreadWakeupReason reason, + thread->wakeup_callback = [context = this, callback](ThreadWakeupReason reason, SharedPtr thread, - SharedPtr object) mutable { + SharedPtr object, + size_t index) mutable -> bool { ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT); - callback(thread, context, reason); + callback(thread, *context, reason); auto& process = thread->owner_process; // We must copy the entire command buffer *plus* the entire static buffers area, since @@ -43,7 +51,7 @@ SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, std::array cmd_buff; Memory::ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(), cmd_buff.size() * sizeof(u32)); - context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process, Kernel::g_handle_table); + context->WriteToOutgoingCommandBuffer(cmd_buff.data(), *process, Kernel::g_handle_table); // Copy the translated command buffer back into the thread's command buffer area. Memory::WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(), cmd_buff.size() * sizeof(u32)); @@ -60,13 +68,6 @@ SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, return event; } -HLERequestContext::HLERequestContext(SharedPtr server_session) - : server_session(std::move(server_session)) { - cmd_buf[0] = 0; -} - -HLERequestContext::~HLERequestContext() = default; - void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { IPC::RequestParser rp(src_cmdbuf); command_header = std::make_unique(rp.PopRaw()); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index cdd8c5e1a4..c4503cd1da 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -14,7 +14,7 @@ #include "core/hle/ipc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/server_session.h" - +#include "core/hle/kernel/thread.h" namespace Service { class ServiceFrameworkBase; } @@ -101,13 +101,12 @@ public: * Returns the session through which this request was made. This can be used as a map key to * access per-client data on services. */ - const SharedPtr& Session() const { + SharedPtr Session() const { return server_session; } using WakeupCallback = std::function thread, HLERequestContext& context, ThreadWakeupReason reason)>; - /* * Puts the specified guest thread to sleep until the returned event is signaled or until the * specified timeout expires. diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 0a1ada27dc..2c7581f1c7 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -39,6 +39,7 @@ enum ThreadStatus { THREADSTATUS_RUNNING, ///< Currently running THREADSTATUS_READY, ///< Ready to run THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter + THREADSTATUS_WAIT_HLE_EVENT, ///< Waiting for hle event to finish THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false THREADSTATUS_WAIT_SYNCH_ALL, ///< Waiting due to WaitSynchronizationN with wait_all = true diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e5252abdc3..5802b98559 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -187,7 +187,8 @@ void GMainWindow::InitializeHotkeys() { RegisterHotkey("Main Window", "Load File", QKeySequence::Open); RegisterHotkey("Main Window", "Start Emulation"); RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); - RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence::Cancel, Qt::ApplicationShortcut); + RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape), + Qt::ApplicationShortcut); LoadHotkeys(); connect(GetHotkey("Main Window", "Load File", this), &QShortcut::activated, this, From 3e5ffa3e3166c92af5e918aca3174db3d36a90c2 Mon Sep 17 00:00:00 2001 From: Vishal Sharma Date: Fri, 9 Mar 2018 01:30:36 +0530 Subject: [PATCH 5/5] Two params per line for travis --- src/core/hle/kernel/hle_ipc.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index be855adc28..84a3778ebc 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -37,10 +37,9 @@ SharedPtr HLERequestContext::SleepClientThread(SharedPtr thread, const std::string& reason, u64 timeout, WakeupCallback&& callback) { // Put the client thread to sleep until the wait event is signaled or the timeout expires. - thread->wakeup_callback = [context = this, callback](ThreadWakeupReason reason, - SharedPtr thread, - SharedPtr object, - size_t index) mutable -> bool { + thread->wakeup_callback = + [context = this, callback](ThreadWakeupReason reason, SharedPtr thread, + SharedPtr object, size_t index) mutable -> bool { ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT); callback(thread, *context, reason);