From e353b9fb3d374740bab24bffebd7f3a81ce062a8 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Mar 2018 19:45:20 -0400 Subject: thread: Add THREADSTATUS_WAIT_HLE_EVENT, remove THREADSTATUS_WAIT_ARB. --- src/core/hle/kernel/thread.cpp | 21 +++------------------ src/core/hle/kernel/thread.h | 2 +- src/core/hle/kernel/wait_object.cpp | 3 ++- 3 files changed, 6 insertions(+), 20 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index a39c53db5..145f50887 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -55,16 +55,6 @@ inline static u32 const NewThreadId() { Thread::Thread() {} Thread::~Thread() {} -/** - * Check if the specified thread is waiting on the specified address to be arbitrated - * @param thread The thread to test - * @param wait_address The address to test against - * @return True if the thread is waiting, false otherwise - */ -static bool CheckWait_AddressArbiter(const Thread* thread, VAddr wait_address) { - return thread->status == THREADSTATUS_WAIT_ARB && wait_address == thread->wait_address; -} - void Thread::Stop() { // Cancel any outstanding wakeup events for this thread CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); @@ -102,12 +92,6 @@ void WaitCurrentThread_Sleep() { thread->status = THREADSTATUS_WAIT_SLEEP; } -void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) { - Thread* thread = GetCurrentThread(); - thread->wait_address = wait_address; - thread->status = THREADSTATUS_WAIT_ARB; -} - void ExitCurrentThread() { Thread* thread = GetCurrentThread(); thread->Stop(); @@ -129,7 +113,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_HLE_EVENT) { // Remove the thread from each of its waiting objects' waitlists for (auto& object : thread->wait_objects) @@ -163,7 +148,7 @@ void Thread::ResumeFromWait() { switch (status) { case THREADSTATUS_WAIT_SYNCH_ALL: case THREADSTATUS_WAIT_SYNCH_ANY: - case THREADSTATUS_WAIT_ARB: + case THREADSTATUS_WAIT_HLE_EVENT: case THREADSTATUS_WAIT_SLEEP: case THREADSTATUS_WAIT_IPC: break; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 4fd2fc2f8..dbf47e269 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -38,7 +38,7 @@ enum ThreadProcessorId : s32 { 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_IPC, ///< Waiting for the reply from an IPC request THREADSTATUS_WAIT_SYNCH_ANY, ///< Waiting due to WaitSynch1 or WaitSynchN with wait_all = false diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index ec147b84c..b08ac72c1 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -39,7 +39,8 @@ SharedPtr WaitObject::GetHighestPriorityReadyThread() { for (const auto& thread : waiting_threads) { // The list of waiting threads must not contain threads that are not waiting to be awakened. ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || - thread->status == THREADSTATUS_WAIT_SYNCH_ALL, + thread->status == THREADSTATUS_WAIT_SYNCH_ALL || + thread->status == THREADSTATUS_WAIT_HLE_EVENT, "Inconsistent thread statuses in waiting_threads"); if (thread->current_priority >= candidate_priority) -- cgit v1.2.3 From 019f1a0cf0505436854ed631da56b97b1d490945 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Mar 2018 20:17:06 -0400 Subject: hle_ipc: Remove GetPointer(..) usage with WriteToOutgoingCommandBuffer. --- src/core/hle/kernel/hle_ipc.cpp | 14 +++++++++++--- src/core/hle/kernel/hle_ipc.h | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index d9faf4b53..f30f8739c 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -159,8 +159,11 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb return RESULT_SUCCESS; } -ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, - HandleTable& dst_table) { +ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { + std::array dst_cmdbuf; + Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); + // The header was already built in the internal command buffer. Attempt to parse it to verify // the integrity and then copy it over to the target command buffer. ParseCommandBuffer(cmd_buf.data(), false); @@ -171,7 +174,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P if (domain_message_header) size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); - std::copy_n(cmd_buf.begin(), size, dst_cmdbuf); + std::copy_n(cmd_buf.begin(), size, dst_cmdbuf.data()); if (command_header->enable_handle_descriptor) { ASSERT_MSG(!move_objects.empty() || !copy_objects.empty(), @@ -213,6 +216,11 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, P dst_cmdbuf[domain_offset++] = static_cast(request_handlers.size()); } } + + // Copy the translated command buffer back into the thread's command buffer area. + Memory::WriteBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), + dst_cmdbuf.size() * sizeof(u32)); + return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index b5631b773..743835f18 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -13,6 +13,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; @@ -108,8 +109,7 @@ public: ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, HandleTable& src_table); /// Writes data from this context back to the requesting process/thread. - ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process, - HandleTable& dst_table); + ResultCode WriteToOutgoingCommandBuffer(Thread& thread); u32_le GetCommand() const { return command; -- cgit v1.2.3 From 2faa83ca13c766d0b510f62462d63b971e3a72e6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Mar 2018 20:18:42 -0400 Subject: hle_ipc: Use shared_ptr instead of unique_ptr to allow copies. --- src/core/hle/kernel/hle_ipc.cpp | 8 ++++---- src/core/hle/kernel/hle_ipc.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index f30f8739c..aae14f09e 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -35,7 +35,7 @@ HLERequestContext::~HLERequestContext() = default; void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { IPC::RequestParser rp(src_cmdbuf); - command_header = std::make_unique(rp.PopRaw()); + command_header = std::make_shared(rp.PopRaw()); if (command_header->type == IPC::CommandType::Close) { // Close does not populate the rest of the IPC header @@ -45,7 +45,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { // If handle descriptor is present, add size of it if (command_header->enable_handle_descriptor) { handle_descriptor_header = - std::make_unique(rp.PopRaw()); + std::make_shared(rp.PopRaw()); if (handle_descriptor_header->send_current_pid) { rp.Skip(2, false); } @@ -88,7 +88,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { // All outgoing domain messages have the domain header, if only incoming has it if (incoming || domain_message_header) { domain_message_header = - std::make_unique(rp.PopRaw()); + std::make_shared(rp.PopRaw()); } else { if (Session()->IsDomain()) LOG_WARNING(IPC, "Domain request has no DomainMessageHeader!"); @@ -96,7 +96,7 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { } data_payload_header = - std::make_unique(rp.PopRaw()); + std::make_shared(rp.PopRaw()); data_payload_offset = rp.GetCurrentOffset(); diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 743835f18..b5cc0d0af 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -139,7 +139,7 @@ public: return buffer_c_desciptors; } - const std::unique_ptr& GetDomainMessageHeader() const { + const std::shared_ptr& GetDomainMessageHeader() const { return domain_message_header; } @@ -212,10 +212,10 @@ private: boost::container::small_vector, 8> copy_objects; boost::container::small_vector, 8> domain_objects; - std::unique_ptr command_header; - std::unique_ptr handle_descriptor_header; - std::unique_ptr data_payload_header; - std::unique_ptr domain_message_header; + std::shared_ptr command_header; + std::shared_ptr handle_descriptor_header; + std::shared_ptr data_payload_header; + std::shared_ptr domain_message_header; std::vector buffer_x_desciptors; std::vector buffer_a_desciptors; std::vector buffer_b_desciptors; -- cgit v1.2.3 From c86af6939c9777d78fbc48b81eb090553762d3d4 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Mar 2018 20:22:46 -0400 Subject: hle_ipc: Add SleepClientThread to block current thread within HLE routines. --- src/core/hle/kernel/hle_ipc.cpp | 27 +++++++++++++++++++++++++++ src/core/hle/kernel/hle_ipc.h | 20 ++++++++++++++++++++ 2 files changed, 47 insertions(+) (limited to 'src/core/hle/kernel') diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index aae14f09e..293756790 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" @@ -26,6 +27,32 @@ 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, size_t index) mutable -> bool { + ASSERT(thread->status == THREADSTATUS_WAIT_HLE_EVENT); + callback(thread, context, reason); + context.WriteToOutgoingCommandBuffer(*thread); + return true; + }; + + 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 b5cc0d0af..8b35da4c9 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include "common/common_types.h" @@ -25,6 +26,7 @@ class Domain; class HandleTable; class HLERequestContext; class Process; +class Event; /** * Interface implemented by HLE Session handlers. @@ -103,6 +105,24 @@ 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. -- cgit v1.2.3