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…
Reference in New Issue