mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 08:09:26 +01:00
GCAdapter: improve thread safety
make sure Reset() can’t be run concurrently with AddGCAdapter() or ResetRumble() (which is called on other threads) which can cause crashes (issue #9462)
This commit is contained in:
parent
e629727572
commit
54b4efff6b
@ -22,6 +22,7 @@ namespace GCAdapter
|
||||
{
|
||||
static bool CheckDeviceAccess(libusb_device* device);
|
||||
static void AddGCAdapter(libusb_device* device);
|
||||
static void ResetRumbleLockNeeded();
|
||||
|
||||
static bool s_detected = false;
|
||||
static libusb_device_handle* s_handle = nullptr;
|
||||
@ -37,6 +38,7 @@ static std::atomic<int> s_controller_payload_size = {0};
|
||||
static std::thread s_adapter_thread;
|
||||
static Common::Flag s_adapter_thread_running;
|
||||
|
||||
static std::mutex s_init_mutex;
|
||||
static std::thread s_adapter_detect_thread;
|
||||
static Common::Flag s_adapter_detect_thread_running;
|
||||
|
||||
@ -77,7 +79,10 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl
|
||||
if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
|
||||
{
|
||||
if (s_handle == nullptr && CheckDeviceAccess(dev))
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_init_mutex);
|
||||
AddGCAdapter(dev);
|
||||
}
|
||||
}
|
||||
else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
|
||||
{
|
||||
@ -115,6 +120,7 @@ static void ScanThreadFunc()
|
||||
{
|
||||
if (s_handle == nullptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_init_mutex);
|
||||
Setup();
|
||||
if (s_detected && s_detect_callback != nullptr)
|
||||
s_detect_callback();
|
||||
@ -306,7 +312,7 @@ static void AddGCAdapter(libusb_device* device)
|
||||
s_detected = true;
|
||||
if (s_detect_callback != nullptr)
|
||||
s_detect_callback();
|
||||
ResetRumble();
|
||||
ResetRumbleLockNeeded();
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
@ -329,6 +335,9 @@ void Shutdown()
|
||||
|
||||
void Reset()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(s_init_mutex, std::defer_lock);
|
||||
if (!lock.try_lock())
|
||||
return;
|
||||
if (!s_detected)
|
||||
return;
|
||||
|
||||
@ -439,10 +448,20 @@ bool UseAdapter()
|
||||
|
||||
void ResetRumble()
|
||||
{
|
||||
if (!UseAdapter())
|
||||
std::unique_lock<std::mutex> lock(s_init_mutex, std::defer_lock);
|
||||
if (!lock.try_lock())
|
||||
return;
|
||||
if (s_handle == nullptr || !s_detected)
|
||||
ResetRumbleLockNeeded();
|
||||
}
|
||||
|
||||
// Needs to be called when s_init_mutex is locked in order to avoid
|
||||
// being called while the libusb state is being reset
|
||||
static void ResetRumbleLockNeeded()
|
||||
{
|
||||
if (!UseAdapter() || (s_handle == nullptr || !s_detected))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::fill(std::begin(s_controller_rumble), std::end(s_controller_rumble), 0);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user