Merge pull request #3805 from mathieui/gcadapter-unplug-crash

GCAdapter: improve thread safety
This commit is contained in:
Markus Wick 2016-05-19 22:58:06 +02:00
commit bb6604df76
4 changed files with 31 additions and 11 deletions

View File

@ -23,6 +23,9 @@ namespace GCAdapter
{ {
static bool CheckDeviceAccess(libusb_device* device); static bool CheckDeviceAccess(libusb_device* device);
static void AddGCAdapter(libusb_device* device); static void AddGCAdapter(libusb_device* device);
static void ResetRumbleLockNeeded();
static void Reset();
static void Setup();
static bool s_detected = false; static bool s_detected = false;
static libusb_device_handle* s_handle = nullptr; 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 std::thread s_adapter_thread;
static Common::Flag s_adapter_thread_running; static Common::Flag s_adapter_thread_running;
static std::mutex s_init_mutex;
static std::thread s_adapter_detect_thread; static std::thread s_adapter_detect_thread;
static Common::Flag s_adapter_detect_thread_running; 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 (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
{ {
if (s_handle == nullptr && CheckDeviceAccess(dev)) if (s_handle == nullptr && CheckDeviceAccess(dev))
{
std::lock_guard<std::mutex> lk(s_init_mutex);
AddGCAdapter(dev); AddGCAdapter(dev);
}
} }
else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
{ {
@ -116,6 +123,7 @@ static void ScanThreadFunc()
{ {
if (s_handle == nullptr) if (s_handle == nullptr)
{ {
std::lock_guard<std::mutex> lk(s_init_mutex);
Setup(); Setup();
if (s_detected && s_detect_callback != nullptr) if (s_detected && s_detect_callback != nullptr)
s_detect_callback(); s_detect_callback();
@ -178,7 +186,7 @@ void StopScanThread()
} }
} }
void Setup() static void Setup()
{ {
libusb_device** list; libusb_device** list;
ssize_t cnt = libusb_get_device_list(s_libusb_context, &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; s_detected = true;
if (s_detect_callback != nullptr) if (s_detect_callback != nullptr)
s_detect_callback(); s_detect_callback();
ResetRumble(); ResetRumbleLockNeeded();
} }
void Shutdown() void Shutdown()
@ -328,8 +336,11 @@ void Shutdown()
s_libusb_driver_not_supported = false; 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) if (!s_detected)
return; return;
@ -443,10 +454,20 @@ bool UseAdapter()
void ResetRumble() void ResetRumble()
{ {
if (!UseAdapter()) std::unique_lock<std::mutex> lock(s_init_mutex, std::defer_lock);
if (!lock.try_lock())
return; 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; return;
}
std::fill(std::begin(s_controller_rumble), std::end(s_controller_rumble), 0); std::fill(std::begin(s_controller_rumble), std::end(s_controller_rumble), 0);

View File

@ -19,9 +19,7 @@ enum ControllerTypes
CONTROLLER_WIRELESS = 2 CONTROLLER_WIRELESS = 2
}; };
void Init(); void Init();
void Reset();
void ResetRumble(); void ResetRumble();
void Setup();
void Shutdown(); void Shutdown();
void SetAdapterCallback(std::function<void(void)> func); void SetAdapterCallback(std::function<void(void)> func);
void StartScanThread(); void StartScanThread();

View File

@ -24,6 +24,9 @@ extern JavaVM* g_java_vm;
namespace GCAdapter namespace GCAdapter
{ {
static void Setup();
static void Reset();
// Java classes // Java classes
static jclass s_adapter_class; static jclass s_adapter_class;
@ -207,7 +210,7 @@ void Init()
StartScanThread(); StartScanThread();
} }
void Setup() static void Setup()
{ {
s_fd = 0; s_fd = 0;
s_detected = true; s_detected = true;
@ -220,7 +223,7 @@ void Setup()
s_read_adapter_thread = std::thread(Read); s_read_adapter_thread = std::thread(Read);
} }
void Reset() static void Reset()
{ {
if (!s_detected) if (!s_detected)
return; return;

View File

@ -9,9 +9,7 @@ namespace GCAdapter
{ {
void Init() {} void Init() {}
void Reset() {}
void ResetRumble() {} void ResetRumble() {}
void Setup() {}
void Shutdown() {} void Shutdown() {}
void SetAdapterCallback(std::function<void(void)> func) {} void SetAdapterCallback(std::function<void(void)> func) {}
void StartScanThread() {} void StartScanThread() {}