summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon
diff options
context:
space:
mode:
authorDentomologist <dentomologist@gmail.com>2026-04-25 11:16:10 -0700
committerDentomologist <dentomologist@gmail.com>2026-04-25 11:16:10 -0700
commitac78e52cf9d6f140362af961faf7ea33a08e0e5f (patch)
tree965f1f50b4cb3e64cbfea870a563255918fee290 /Source/Core/InputCommon
parent0363de56fc13edb43cd50467a52b1c10207db702 (diff)
GCAdapter: Fix data races
Make `s_is_adapter_wanted` and the elements of `s_config_rumble_enabled` atomic. The CPU thread reads `s_is_adapter_wanted` and `s_config_rumble_enabled` in `Output`, while the host thread writes to them in `RefreshConfig`. The simplest way to trigger this race is to close the `Settings` window while playing a game with the adapter active.
Diffstat (limited to 'Source/Core/InputCommon')
-rw-r--r--Source/Core/InputCommon/GCAdapter.cpp27
1 files changed, 16 insertions, 11 deletions
diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp
index 8438146c34..e11d95d68f 100644
--- a/Source/Core/InputCommon/GCAdapter.cpp
+++ b/Source/Core/InputCommon/GCAdapter.cpp
@@ -166,8 +166,8 @@ static u64 s_last_init = 0;
static std::optional<Config::ConfigChangedCallbackID> s_config_callback_id = std::nullopt;
-static bool s_is_adapter_wanted = false;
-static std::array<bool, SerialInterface::MAX_SI_CHANNELS> s_config_rumble_enabled{};
+static std::atomic_bool s_is_adapter_wanted = false;
+static std::array<std::atomic_bool, SerialInterface::MAX_SI_CHANNELS> s_config_rumble_enabled{};
static std::atomic<double> s_adapter_poll_rate{};
@@ -462,7 +462,7 @@ static void ScanThreadFunc()
while (s_adapter_detect_thread_running.IsSet())
{
- if (!s_detected && s_is_adapter_wanted &&
+ if (!s_detected && s_is_adapter_wanted.load(std::memory_order_relaxed) &&
env->CallStaticBooleanMethod(s_adapter_class, is_usb_device_available_func))
{
std::lock_guard lk(s_init_mutex);
@@ -506,16 +506,19 @@ static void StopScanThread()
static void RefreshConfig()
{
- s_is_adapter_wanted = false;
+ bool is_adapter_wanted = false;
for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; ++i)
{
- s_is_adapter_wanted |= Config::Get(Config::GetInfoForSIDevice(i)) ==
- SerialInterface::SIDevices::SIDEVICE_WIIU_ADAPTER;
- s_config_rumble_enabled[i] = Config::Get(Config::GetInfoForAdapterRumble(i));
+ is_adapter_wanted |= Config::Get(Config::GetInfoForSIDevice(i)) ==
+ SerialInterface::SIDevices::SIDEVICE_WIIU_ADAPTER;
+ s_config_rumble_enabled[i].store(Config::Get(Config::GetInfoForAdapterRumble(i)),
+ std::memory_order_relaxed);
}
- if (s_is_adapter_wanted)
+ s_is_adapter_wanted.store(is_adapter_wanted, std::memory_order_relaxed);
+
+ if (is_adapter_wanted)
StartScanThread();
else
StopScanThread();
@@ -830,7 +833,7 @@ static void Reset()
GCPadStatus Input(int chan)
{
- if (!s_is_adapter_wanted)
+ if (!s_is_adapter_wanted.load(std::memory_order_relaxed))
return {};
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
@@ -991,7 +994,8 @@ void ResetRumble()
// being called while the libusb state is being reset
static void ResetRumbleLockNeeded()
{
- if (!s_is_adapter_wanted || s_handle == nullptr || s_status != AdapterStatus::Detected)
+ if (s_handle == nullptr || s_status != AdapterStatus::Detected ||
+ !s_is_adapter_wanted.load(std::memory_order_relaxed))
{
return;
}
@@ -1018,7 +1022,8 @@ static void ResetRumbleLockNeeded()
void Output(int chan, u8 rumble_command)
{
- if (!s_is_adapter_wanted || !s_config_rumble_enabled[chan])
+ if (!s_is_adapter_wanted.load(std::memory_order_relaxed) ||
+ !s_config_rumble_enabled[chan].load(std::memory_order_relaxed))
return;
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION