[hid_core/frontend] use shared lock for accesses on emulated controller (reduces contention in FBSD) (#2553)

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2553
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2025-09-24 19:30:21 +02:00 committed by crueter
parent 45263ee7aa
commit bf4dce8d0b
Signed by: crueter
GPG key ID: 425ACD2D4830EBC6
2 changed files with 50 additions and 48 deletions

View file

@ -577,7 +577,7 @@ void EmulatedController::UnloadInput() {
} }
void EmulatedController::EnableConfiguration() { void EmulatedController::EnableConfiguration() {
std::scoped_lock lock{connect_mutex, npad_mutex}; std::unique_lock lock1{connect_mutex}, lock2{npad_mutex};
is_configuring = true; is_configuring = true;
tmp_is_connected = is_connected; tmp_is_connected = is_connected;
tmp_npad_type = npad_type; tmp_npad_type = npad_type;
@ -614,19 +614,19 @@ void EmulatedController::DisableConfiguration() {
} }
void EmulatedController::EnableSystemButtons() { void EmulatedController::EnableSystemButtons() {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
system_buttons_enabled = true; system_buttons_enabled = true;
} }
void EmulatedController::DisableSystemButtons() { void EmulatedController::DisableSystemButtons() {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
system_buttons_enabled = false; system_buttons_enabled = false;
controller.home_button_state.raw = 0; controller.home_button_state.raw = 0;
controller.capture_button_state.raw = 0; controller.capture_button_state.raw = 0;
} }
void EmulatedController::ResetSystemButtons() { void EmulatedController::ResetSystemButtons() {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
controller.home_button_state.home.Assign(false); controller.home_button_state.home.Assign(false);
controller.capture_button_state.capture.Assign(false); controller.capture_button_state.capture.Assign(false);
} }
@ -937,7 +937,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
auto trigger_guard = SCOPE_GUARD { auto trigger_guard = SCOPE_GUARD {
TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); TriggerOnChange(ControllerTriggerType::Stick, !is_configuring);
}; };
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
const auto stick_value = TransformToStick(callback); const auto stick_value = TransformToStick(callback);
// Only read stick values that have the same uuid or are over the threshold to avoid flapping // Only read stick values that have the same uuid or are over the threshold to avoid flapping
@ -994,7 +994,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
auto trigger_guard = SCOPE_GUARD { auto trigger_guard = SCOPE_GUARD {
TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring);
}; };
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
const auto trigger_value = TransformToTrigger(callback); const auto trigger_value = TransformToTrigger(callback);
// Only read trigger values that have the same uuid or are pressed once // Only read trigger values that have the same uuid or are pressed once
@ -1042,7 +1042,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
SCOPE_EXIT { SCOPE_EXIT {
TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); TriggerOnChange(ControllerTriggerType::Motion, !is_configuring);
}; };
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
auto& raw_status = controller.motion_values[index].raw_status; auto& raw_status = controller.motion_values[index].raw_status;
auto& emulated = controller.motion_values[index].emulated; auto& emulated = controller.motion_values[index].emulated;
@ -1078,7 +1078,7 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback
auto trigger_guard = SCOPE_GUARD { auto trigger_guard = SCOPE_GUARD {
TriggerOnChange(ControllerTriggerType::Color, !is_configuring); TriggerOnChange(ControllerTriggerType::Color, !is_configuring);
}; };
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
controller.color_values[index] = TransformToColor(callback); controller.color_values[index] = TransformToColor(callback);
if (is_configuring) { if (is_configuring) {
@ -1129,7 +1129,7 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
SCOPE_EXIT { SCOPE_EXIT {
TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); TriggerOnChange(ControllerTriggerType::Battery, !is_configuring);
}; };
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
controller.battery_values[index] = TransformToBattery(callback); controller.battery_values[index] = TransformToBattery(callback);
if (is_configuring) { if (is_configuring) {
@ -1194,7 +1194,7 @@ void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback
SCOPE_EXIT { SCOPE_EXIT {
TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring);
}; };
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
controller.camera_values = TransformToCamera(callback); controller.camera_values = TransformToCamera(callback);
if (is_configuring) { if (is_configuring) {
@ -1211,7 +1211,7 @@ void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& call
SCOPE_EXIT { SCOPE_EXIT {
TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); TriggerOnChange(ControllerTriggerType::RingController, !is_configuring);
}; };
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
const auto force_value = TransformToStick(callback); const auto force_value = TransformToStick(callback);
controller.ring_analog_value = force_value.x; controller.ring_analog_value = force_value.x;
@ -1227,7 +1227,7 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
SCOPE_EXIT { SCOPE_EXIT {
TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring);
}; };
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
controller.nfc_values = TransformToNfc(callback); controller.nfc_values = TransformToNfc(callback);
if (is_configuring) { if (is_configuring) {
@ -1662,7 +1662,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
} }
bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
switch (type) { switch (type) {
case NpadStyleIndex::Fullkey: case NpadStyleIndex::Fullkey:
@ -1678,7 +1678,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
} }
bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
switch (type) { switch (type) {
case NpadStyleIndex::Fullkey: case NpadStyleIndex::Fullkey:
@ -1718,7 +1718,7 @@ void EmulatedController::Connect(bool use_temporary_value) {
auto trigger_guard = SCOPE_GUARD { auto trigger_guard = SCOPE_GUARD {
TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); TriggerOnChange(ControllerTriggerType::Connected, !is_configuring);
}; };
std::scoped_lock lock{connect_mutex, mutex}; std::unique_lock lock1{connect_mutex}, lock2{mutex};
if (is_configuring) { if (is_configuring) {
tmp_is_connected = true; tmp_is_connected = true;
return; return;
@ -1735,7 +1735,7 @@ void EmulatedController::Disconnect() {
auto trigger_guard = SCOPE_GUARD { auto trigger_guard = SCOPE_GUARD {
TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring);
}; };
std::scoped_lock lock{connect_mutex, mutex}; std::unique_lock lock1{connect_mutex}, lock2{mutex};
if (is_configuring) { if (is_configuring) {
tmp_is_connected = false; tmp_is_connected = false;
return; return;
@ -1749,23 +1749,21 @@ void EmulatedController::Disconnect() {
} }
bool EmulatedController::IsConnected(bool get_temporary_value) const { bool EmulatedController::IsConnected(bool get_temporary_value) const {
std::scoped_lock lock{connect_mutex}; std::shared_lock lock{connect_mutex};
if (get_temporary_value && is_configuring) { if (get_temporary_value && is_configuring)
return tmp_is_connected; return tmp_is_connected;
}
return is_connected; return is_connected;
} }
NpadIdType EmulatedController::GetNpadIdType() const { NpadIdType EmulatedController::GetNpadIdType() const {
std::scoped_lock lock{mutex}; std::shared_lock lock{mutex};
return npad_id_type; return npad_id_type;
} }
NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const {
std::scoped_lock lock{npad_mutex}; std::shared_lock lock{npad_mutex};
if (get_temporary_value && is_configuring) { if (get_temporary_value && is_configuring)
return tmp_npad_type; return tmp_npad_type;
}
return npad_type; return npad_type;
} }
@ -1773,7 +1771,7 @@ void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
auto trigger_guard = SCOPE_GUARD { auto trigger_guard = SCOPE_GUARD {
TriggerOnChange(ControllerTriggerType::Type, !is_configuring); TriggerOnChange(ControllerTriggerType::Type, !is_configuring);
}; };
std::scoped_lock lock{mutex, npad_mutex}; std::unique_lock lock1{mutex}, lock2{npad_mutex};
if (is_configuring) { if (is_configuring) {
if (tmp_npad_type == npad_type_) { if (tmp_npad_type == npad_type_) {
@ -1819,37 +1817,37 @@ LedPattern EmulatedController::GetLedPattern() const {
} }
ButtonValues EmulatedController::GetButtonsValues() const { ButtonValues EmulatedController::GetButtonsValues() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.button_values; return controller.button_values;
} }
SticksValues EmulatedController::GetSticksValues() const { SticksValues EmulatedController::GetSticksValues() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.stick_values; return controller.stick_values;
} }
TriggerValues EmulatedController::GetTriggersValues() const { TriggerValues EmulatedController::GetTriggersValues() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.trigger_values; return controller.trigger_values;
} }
ControllerMotionValues EmulatedController::GetMotionValues() const { ControllerMotionValues EmulatedController::GetMotionValues() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.motion_values; return controller.motion_values;
} }
ColorValues EmulatedController::GetColorsValues() const { ColorValues EmulatedController::GetColorsValues() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.color_values; return controller.color_values;
} }
BatteryValues EmulatedController::GetBatteryValues() const { BatteryValues EmulatedController::GetBatteryValues() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.battery_values; return controller.battery_values;
} }
CameraValues EmulatedController::GetCameraValues() const { CameraValues EmulatedController::GetCameraValues() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.camera_values; return controller.camera_values;
} }
@ -1858,7 +1856,7 @@ RingAnalogValue EmulatedController::GetRingSensorValues() const {
} }
HomeButtonState EmulatedController::GetHomeButtons() const { HomeButtonState EmulatedController::GetHomeButtons() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
if (is_configuring) { if (is_configuring) {
return {}; return {};
} }
@ -1866,7 +1864,7 @@ HomeButtonState EmulatedController::GetHomeButtons() const {
} }
CaptureButtonState EmulatedController::GetCaptureButtons() const { CaptureButtonState EmulatedController::GetCaptureButtons() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
if (is_configuring) { if (is_configuring) {
return {}; return {};
} }
@ -1874,7 +1872,7 @@ CaptureButtonState EmulatedController::GetCaptureButtons() const {
} }
NpadButtonState EmulatedController::GetNpadButtons() const { NpadButtonState EmulatedController::GetNpadButtons() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
if (is_configuring) { if (is_configuring) {
return {}; return {};
} }
@ -1882,7 +1880,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
} }
DebugPadButton EmulatedController::GetDebugPadButtons() const { DebugPadButton EmulatedController::GetDebugPadButtons() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
if (is_configuring) { if (is_configuring) {
return {}; return {};
} }
@ -1890,7 +1888,7 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const {
} }
AnalogSticks EmulatedController::GetSticks() const { AnalogSticks EmulatedController::GetSticks() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
if (is_configuring) { if (is_configuring) {
return {}; return {};
@ -1900,7 +1898,7 @@ AnalogSticks EmulatedController::GetSticks() const {
} }
NpadGcTriggerState EmulatedController::GetTriggers() const { NpadGcTriggerState EmulatedController::GetTriggers() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
if (is_configuring) { if (is_configuring) {
return {}; return {};
} }
@ -1913,17 +1911,17 @@ MotionState EmulatedController::GetMotions() const {
} }
ControllerColors EmulatedController::GetColors() const { ControllerColors EmulatedController::GetColors() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.colors_state; return controller.colors_state;
} }
BatteryLevelState EmulatedController::GetBattery() const { BatteryLevelState EmulatedController::GetBattery() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.battery_state; return controller.battery_state;
} }
const CameraState& EmulatedController::GetCamera() const { const CameraState& EmulatedController::GetCamera() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.camera_state; return controller.camera_state;
} }
@ -1932,7 +1930,7 @@ RingSensorForce EmulatedController::GetRingSensorForce() const {
} }
const NfcState& EmulatedController::GetNfc() const { const NfcState& EmulatedController::GetNfc() const {
std::scoped_lock lock{mutex}; std::unique_lock lock{mutex};
return controller.nfc_state; return controller.nfc_state;
} }
@ -1946,7 +1944,7 @@ NpadColor EmulatedController::GetNpadColor(u32 color) {
} }
void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
std::scoped_lock lock{callback_mutex}; std::unique_lock lock{callback_mutex};
for (const auto& poller_pair : callback_list) { for (const auto& poller_pair : callback_list) {
const ControllerUpdateCallback& poller = poller_pair.second; const ControllerUpdateCallback& poller = poller_pair.second;
if (!is_npad_service_update && poller.is_npad_service) { if (!is_npad_service_update && poller.is_npad_service) {
@ -1959,13 +1957,13 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa
} }
int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {
std::scoped_lock lock{callback_mutex}; std::unique_lock lock{callback_mutex};
callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
return last_callback_key++; return last_callback_key++;
} }
void EmulatedController::DeleteCallback(int key) { void EmulatedController::DeleteCallback(int key) {
std::scoped_lock lock{callback_mutex}; std::unique_lock lock{callback_mutex};
const auto& iterator = callback_list.find(key); const auto& iterator = callback_list.find(key);
if (iterator == callback_list.end()) { if (iterator == callback_list.end()) {
LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -7,6 +10,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <shared_mutex>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
@ -626,10 +630,10 @@ private:
StickDevices virtual_stick_devices; StickDevices virtual_stick_devices;
ControllerMotionDevices virtual_motion_devices; ControllerMotionDevices virtual_motion_devices;
mutable std::mutex mutex; mutable std::shared_mutex mutex;
mutable std::mutex callback_mutex; mutable std::shared_mutex callback_mutex;
mutable std::mutex npad_mutex; mutable std::shared_mutex npad_mutex;
mutable std::mutex connect_mutex; mutable std::shared_mutex connect_mutex;
std::unordered_map<int, ControllerUpdateCallback> callback_list; std::unordered_map<int, ControllerUpdateCallback> callback_list;
int last_callback_key = 0; int last_callback_key = 0;