diff options
| author | Markus Wick <degasus@users.noreply.github.com> | 2016-05-19 22:58:06 +0200 |
|---|---|---|
| committer | Markus Wick <degasus@users.noreply.github.com> | 2016-05-19 22:58:06 +0200 |
| commit | bb6604df767212affdbd1087d305709d9d83dc13 (patch) | |
| tree | 4e2c2ca2621eecdf94b52cfb6d9c5b954760d91e /Source/Core/InputCommon/GCAdapter.cpp | |
| parent | f1f8bf4d80e95bdb4f84c01c15f7bd27f0c9d8fb (diff) | |
| parent | 1bbbe92cd203d39f0aa0da80d5bd41ae641c3e5c (diff) | |
Merge pull request #3805 from mathieui/gcadapter-unplug-crash
GCAdapter: improve thread safety
Diffstat (limited to 'Source/Core/InputCommon/GCAdapter.cpp')
| -rw-r--r-- | Source/Core/InputCommon/GCAdapter.cpp | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index df71a8d846..a5ccb771cc 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -23,6 +23,9 @@ namespace GCAdapter { static bool CheckDeviceAccess(libusb_device* device); static void AddGCAdapter(libusb_device* device); +static void ResetRumbleLockNeeded(); +static void Reset(); +static void Setup(); static bool s_detected = false; static libusb_device_handle* s_handle = nullptr; @@ -38,6 +41,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; @@ -78,7 +82,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) { @@ -116,6 +123,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(); @@ -178,7 +186,7 @@ void StopScanThread() } } -void Setup() +static void Setup() { libusb_device** list; ssize_t cnt = libusb_get_device_list(s_libusb_context, &list); @@ -307,7 +315,7 @@ static void AddGCAdapter(libusb_device* device) s_detected = true; if (s_detect_callback != nullptr) s_detect_callback(); - ResetRumble(); + ResetRumbleLockNeeded(); } void Shutdown() @@ -328,8 +336,11 @@ void Shutdown() s_libusb_driver_not_supported = false; } -void Reset() +static void Reset() { + std::unique_lock<std::mutex> lock(s_init_mutex, std::defer_lock); + if (!lock.try_lock()) + return; if (!s_detected) return; @@ -443,10 +454,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); |
