Putting guest thread to sleep inside handler
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
|
#include "core/hle/kernel/event.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/hle_ipc.h"
|
#include "core/hle/kernel/hle_ipc.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
@@ -25,6 +26,39 @@ void SessionRequestHandler::ClientDisconnected(SharedPtr<ServerSession> server_s
|
|||||||
boost::range::remove_erase(connected_sessions, server_session);
|
boost::range::remove_erase(connected_sessions, server_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> 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> thread, SharedPtr<WaitObject> 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<u32, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> 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<Kernel::ServerSession> server_session)
|
HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
|
||||||
: server_session(std::move(server_session)) {
|
: server_session(std::move(server_session)) {
|
||||||
cmd_buf[0] = 0;
|
cmd_buf[0] = 0;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
#include <boost/container/small_vector.hpp>
|
#include <boost/container/small_vector.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/swap.h"
|
#include "common/swap.h"
|
||||||
@@ -24,6 +25,8 @@ class Domain;
|
|||||||
class HandleTable;
|
class HandleTable;
|
||||||
class HLERequestContext;
|
class HLERequestContext;
|
||||||
class Process;
|
class Process;
|
||||||
|
class Thread;
|
||||||
|
class Event;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface implemented by HLE Session handlers.
|
* Interface implemented by HLE Session handlers.
|
||||||
@@ -102,6 +105,23 @@ public:
|
|||||||
return server_session;
|
return server_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using WakeupCallback = std::function<void(SharedPtr<Thread> 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<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
|
||||||
|
u64 timeout, WakeupCallback&& callback);
|
||||||
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
|
void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
|
||||||
|
|
||||||
/// Populates this context with data from the requesting process/thread.
|
/// Populates this context with data from the requesting process/thread.
|
||||||
|
|||||||
@@ -247,7 +247,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
|||||||
bool resume = true;
|
bool resume = true;
|
||||||
|
|
||||||
if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
|
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
|
// Remove the thread from each of its waiting objects' waitlists
|
||||||
for (auto& object : thread->wait_objects)
|
for (auto& object : thread->wait_objects)
|
||||||
|
|||||||
@@ -150,9 +150,15 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
|
|||||||
}
|
}
|
||||||
|
|
||||||
u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());
|
u32* cmd_buf = (u32*)Memory::GetPointer(Kernel::GetCurrentThread()->GetTLSAddress());
|
||||||
context.WriteToOutgoingCommandBuffer(cmd_buf, *Kernel::g_current_process,
|
auto thread = Kernel::GetCurrentThread();
|
||||||
Kernel::g_handle_table);
|
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;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user