diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp index 680e85d61c..83d262ebeb 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp @@ -96,8 +96,15 @@ static void TryToFillWiimoteSlot(u32 index) s_wiimote_pool.erase(s_wiimote_pool.begin()); } +void PopulateDevices() +{ + // There is a very small chance of deadlocks if we didn't do it in another thread + s_wiimote_scanner.PopulateDevices(); +} + // Attempts to fill enabled real wiimote slots. // Push/pull wiimotes to/from ControllerInterface as needed. +// Should be called PopulateDevices() to be in line with other implementations. void ProcessWiimotePool() { std::lock_guard lk(g_wiimotes_mutex); @@ -545,7 +552,7 @@ void WiimoteScanner::StopThread() void WiimoteScanner::SetScanMode(WiimoteScanMode scan_mode) { m_scan_mode.store(scan_mode); - m_scan_mode_changed_event.Set(); + m_scan_mode_changed_or_population_event.Set(); } bool WiimoteScanner::IsReady() const @@ -610,6 +617,12 @@ void WiimoteScanner::PoolThreadFunc() } } +void WiimoteScanner::PopulateDevices() +{ + m_populate_devices.Set(); + m_scan_mode_changed_or_population_event.Set(); +} + void WiimoteScanner::ThreadFunc() { std::thread pool_thread(&WiimoteScanner::PoolThreadFunc, this); @@ -634,7 +647,12 @@ void WiimoteScanner::ThreadFunc() while (m_scan_thread_running.IsSet()) { - m_scan_mode_changed_event.WaitFor(std::chrono::milliseconds(500)); + m_scan_mode_changed_or_population_event.WaitFor(std::chrono::milliseconds(500)); + + if (m_populate_devices.TestAndClear()) + { + g_controller_interface.PlatformPopulateDevices([] { ProcessWiimotePool(); }); + } // Does stuff needed to detect disconnects on Windows for (const auto& backend : m_backends) @@ -675,7 +693,7 @@ void WiimoteScanner::ThreadFunc() } AddWiimoteToPool(std::unique_ptr(wiimote)); - ProcessWiimotePool(); + g_controller_interface.PlatformPopulateDevices([] { ProcessWiimotePool(); }); } if (found_board) @@ -956,12 +974,12 @@ void HandleWiimoteSourceChange(unsigned int index) if (auto removed_wiimote = std::move(g_wiimotes[index])) AddWiimoteToPool(std::move(removed_wiimote)); }); - ProcessWiimotePool(); + g_controller_interface.PlatformPopulateDevices([] { ProcessWiimotePool(); }); } void HandleWiimotesInControllerInterfaceSettingChange() { - ProcessWiimotePool(); + g_controller_interface.PlatformPopulateDevices([] { ProcessWiimotePool(); }); } } // namespace WiimoteReal diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h index 44d6a22af4..701371d4bd 100644 --- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h @@ -171,6 +171,7 @@ public: void StartThread(); void StopThread(); void SetScanMode(WiimoteScanMode scan_mode); + void PopulateDevices(); bool IsReady() const; @@ -183,7 +184,8 @@ private: std::thread m_scan_thread; Common::Flag m_scan_thread_running; - Common::Event m_scan_mode_changed_event; + Common::Flag m_populate_devices; + Common::Event m_scan_mode_changed_or_population_event; std::atomic m_scan_mode{WiimoteScanMode::DO_NOT_SCAN}; }; @@ -204,6 +206,7 @@ void InitAdapterClass(); #endif void HandleWiimotesInControllerInterfaceSettingChange(); +void PopulateDevices(); void ProcessWiimotePool(); } // namespace WiimoteReal diff --git a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp index b84e8af571..cb4eae1472 100644 --- a/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp +++ b/Source/Core/InputCommon/ControllerInterface/ControllerInterface.cpp @@ -185,7 +185,7 @@ void ControllerInterface::RefreshDevices(RefreshReason reason) ciface::DualShockUDPClient::PopulateDevices(); #endif - WiimoteReal::ProcessWiimotePool(); + WiimoteReal::PopulateDevices(); m_devices_mutex.unlock(); diff --git a/Source/Core/InputCommon/ControllerInterface/Wiimote/WiimoteController.cpp b/Source/Core/InputCommon/ControllerInterface/Wiimote/WiimoteController.cpp index eaa56ef449..dfd329f5e0 100644 --- a/Source/Core/InputCommon/ControllerInterface/Wiimote/WiimoteController.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Wiimote/WiimoteController.cpp @@ -128,13 +128,17 @@ void ReleaseDevices(std::optional count) // Remove up to "count" remotes (or all of them if nullopt). // Real wiimotes will be added to the pool. - g_controller_interface.RemoveDevice([&](const Core::Device* device) { - if (device->GetSource() != SOURCE_NAME || count == removed_devices) - return false; + // Make sure to force the device removal immediately (as they are shared ptrs and + // they could be kept alive, preventing us from re-creating the device) + g_controller_interface.RemoveDevice( + [&](const Core::Device* device) { + if (device->GetSource() != SOURCE_NAME || count == removed_devices) + return false; - ++removed_devices; - return true; - }); + ++removed_devices; + return true; + }, + true); } Device::Device(std::unique_ptr wiimote) : m_wiimote(std::move(wiimote))