From 7db6594358c0e76c6dff9094517ca863bccca756 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Tue, 14 Feb 2023 02:27:47 +0300 Subject: [PATCH] rsx/overlays: Use lf_queue for a lock-free stack implementation --- Utilities/lockless.h | 8 +++ rpcs3/Emu/RSX/Overlays/overlay_manager.cpp | 66 +++++++--------------- rpcs3/Emu/RSX/Overlays/overlay_manager.h | 6 +- rpcs3/Emu/RSX/Overlays/overlays.h | 4 ++ 4 files changed, 34 insertions(+), 50 deletions(-) diff --git a/Utilities/lockless.h b/Utilities/lockless.h index a563ceed3e..41b24fe739 100644 --- a/Utilities/lockless.h +++ b/Utilities/lockless.h @@ -359,6 +359,14 @@ public: return result; } + // Withdraw the list in reverse order (LIFO/FILO) + lf_queue_slice pop_all_reversed() + { + lf_queue_slice result; + result.m_head = m_head.exchange(nullptr); + return result; + } + // Apply func(data) to each element, return the total length template usz apply(F func) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_manager.cpp b/rpcs3/Emu/RSX/Overlays/overlay_manager.cpp index 63929cda8f..f5201ce24a 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_manager.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_manager.cpp @@ -7,6 +7,15 @@ namespace rsx { namespace overlays { + display_manager::display_manager(int) + { + m_input_thread = std::make_shared>(); + (*m_input_thread)([this]() + { + input_thread_loop(); + }); + } + display_manager::~display_manager() { if (m_input_thread) @@ -135,22 +144,9 @@ namespace rsx m_type_ids_to_remove.clear(); } - void display_manager::on_overlay_activated(const std::shared_ptr& item) + void display_manager::on_overlay_activated(const std::shared_ptr& /*item*/) { - if (auto iface = std::dynamic_pointer_cast(item)) - { - // Kick input thread if not enabled. Expect the interface to attach shortly - std::lock_guard lock(m_input_thread_lock); - - if (!m_input_thread) - { - m_input_thread = std::make_shared>(); - (*m_input_thread)([this]() - { - input_thread_loop(); - }); - } - } + // TODO: Internal management, callbacks, etc } void display_manager::attach_thread_input( @@ -161,8 +157,7 @@ namespace rsx { if (auto iface = std::dynamic_pointer_cast(get(uid))) { - std::lock_guard lock(m_input_thread_lock); - m_input_token_stack.emplace_front( + m_input_token_stack.push( std::move(iface), on_input_loop_enter, on_input_loop_exit, @@ -172,46 +167,27 @@ namespace rsx void display_manager::on_overlay_removed(const std::shared_ptr& item) { - if (!dynamic_cast(item.get())) + auto iface = std::dynamic_pointer_cast(item); + if (!iface) { // Not instance of UI, ignore return; } - std::lock_guard lock(m_input_thread_lock); - for (auto& entry : m_input_token_stack) - { - if (entry.target->uid == item->uid) - { - // Release - entry.target = {}; - break; - } - } - - // The top must never be an empty ref. Pop all empties. - while (!m_input_token_stack.empty() && !m_input_token_stack.front().target) - { - m_input_token_stack.pop_front(); - } + iface->detach_input(); } void display_manager::input_thread_loop() { while (!m_input_thread_abort) { - input_thread_context_t input_context; + for (auto&& input_context : m_input_token_stack.pop_all_reversed()) { - reader_lock lock(m_input_thread_lock); - if (!m_input_token_stack.empty()) + if (input_context.target->is_detached()) { - input_context = m_input_token_stack.front(); - m_input_token_stack.pop_front(); + continue; } - } - if (input_context.target) - { if (input_context.input_loop_prologue) { input_context.input_loop_prologue(); @@ -236,10 +212,8 @@ namespace rsx rsx_log.error("Input loop exited with error code=%d", result); } } - else - { - thread_ctrl::wait_for(1000); - } + + m_input_token_stack.wait(); } } } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_manager.h b/rpcs3/Emu/RSX/Overlays/overlay_manager.h index e93b1cc8f1..720eb7665a 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_manager.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_manager.h @@ -39,8 +39,7 @@ namespace rsx public: // Disable default construction to make it conditionally available in g_fxo - explicit display_manager(int) noexcept - {} + explicit display_manager(int) noexcept; ~display_manager(); @@ -176,8 +175,7 @@ namespace rsx std::function input_loop_override = nullptr; }; - std::deque m_input_token_stack; - shared_mutex m_input_thread_lock; + lf_queue m_input_token_stack; atomic_t m_input_thread_abort = false; std::shared_ptr> m_input_thread; diff --git a/rpcs3/Emu/RSX/Overlays/overlays.h b/rpcs3/Emu/RSX/Overlays/overlays.h index 79e60c5893..4b2c5810c6 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.h +++ b/rpcs3/Emu/RSX/Overlays/overlays.h @@ -112,6 +112,7 @@ namespace rsx atomic_t m_interactive = false; bool m_start_pad_interception = true; atomic_t m_stop_pad_interception = false; + atomic_t m_input_thread_detached = false; atomic_t thread_bits = 0; bool m_keyboard_input_enabled = false; // Allow keyboard input bool m_keyboard_pad_handler_active = true; // Initialized as true to prevent keyboard input until proven otherwise. @@ -146,6 +147,9 @@ namespace rsx public: s32 return_code = 0; // CELL_OK + bool is_detached() const { return m_input_thread_detached; } + void detach_input() { m_input_thread_detached.store(true); } + void update() override {} compiled_resource get_compiled() override = 0;