summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/GCAdapter.cpp
diff options
context:
space:
mode:
authormathieui <mathieui@mathieui.net>2016-04-30 13:29:11 +0200
committermathieui <mathieui@mathieui.net>2016-05-18 20:44:01 +0200
commit54b4efff6b14a2dc0be6d6a284be8b27750ceecb (patch)
treef573eb2f0ef88017e1cca187da4257c6f2978302 /Source/Core/InputCommon/GCAdapter.cpp
parente62972757205e23abab798323a2729212e0766ba (diff)
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)
Diffstat (limited to 'Source/Core/InputCommon/GCAdapter.cpp')
-rw-r--r--Source/Core/InputCommon/GCAdapter.cpp25
1 files changed, 22 insertions, 3 deletions
diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp
index eceed1ed0b..4728a9f49f 100644
--- a/Source/Core/InputCommon/GCAdapter.cpp
+++ b/Source/Core/InputCommon/GCAdapter.cpp
@@ -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);