Android/GCAdapter: Don't join current thread

The read thread could call Reset, which in turn tried to join the read
thread, leading to a SIGABRT. This manifested as Dolphin consistently
crashing when disconnecting a GC adapter and having a chance of crashing
a few seconds after connecting a GC adapter.
This commit is contained in:
JosJuice 2024-12-01 12:56:42 +01:00
parent a68ae37df7
commit 74ed5e5532
1 changed files with 26 additions and 8 deletions

View File

@ -66,7 +66,13 @@ static void AddGCAdapter(libusb_device* device);
static void ResetRumbleLockNeeded(); static void ResetRumbleLockNeeded();
#endif #endif
static void Reset(); enum class CalledFromReadThread
{
No,
Yes,
};
static void Reset(CalledFromReadThread called_from_read_thread);
static void Setup(); static void Setup();
static void ProcessInputPayload(const u8* data, std::size_t size); static void ProcessInputPayload(const u8* data, std::size_t size);
static void ReadThreadFunc(); static void ReadThreadFunc();
@ -123,6 +129,7 @@ static std::atomic<int> s_controller_write_payload_size{0};
static std::thread s_read_adapter_thread; static std::thread s_read_adapter_thread;
static Common::Flag s_read_adapter_thread_running; static Common::Flag s_read_adapter_thread_running;
static Common::Flag s_read_adapter_thread_needs_joining;
static std::thread s_write_adapter_thread; static std::thread s_write_adapter_thread;
static Common::Flag s_write_adapter_thread_running; static Common::Flag s_write_adapter_thread_running;
static Common::Event s_write_happened; static Common::Event s_write_happened;
@ -324,7 +331,7 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl
else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
{ {
if (s_handle != nullptr && libusb_get_device(s_handle) == dev) if (s_handle != nullptr && libusb_get_device(s_handle) == dev)
Reset(); Reset(CalledFromReadThread::No);
// Reset a potential error status now that the adapter is unplugged // Reset a potential error status now that the adapter is unplugged
if (s_status == AdapterStatus::Error) if (s_status == AdapterStatus::Error)
@ -516,8 +523,11 @@ static void Setup()
s_detected = true; s_detected = true;
// Make sure the thread isn't in the middle of shutting down while starting a new one // Make sure the thread isn't in the middle of shutting down while starting a new one
if (s_read_adapter_thread_running.TestAndClear()) if (s_read_adapter_thread_needs_joining.TestAndClear() ||
s_read_adapter_thread_running.TestAndClear())
{
s_read_adapter_thread.join(); s_read_adapter_thread.join();
}
s_read_adapter_thread_running.Set(true); s_read_adapter_thread_running.Set(true);
s_read_adapter_thread = std::thread(ReadThreadFunc); s_read_adapter_thread = std::thread(ReadThreadFunc);
@ -682,7 +692,7 @@ void Shutdown()
libusb_hotplug_deregister_callback(*s_libusb_context, s_hotplug_handle); libusb_hotplug_deregister_callback(*s_libusb_context, s_hotplug_handle);
#endif #endif
#endif #endif
Reset(); Reset(CalledFromReadThread::No);
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
s_libusb_context.reset(); s_libusb_context.reset();
@ -696,7 +706,7 @@ void Shutdown()
} }
} }
static void Reset() static void Reset(CalledFromReadThread called_from_read_thread)
{ {
#if GCADAPTER_USE_LIBUSB_IMPLEMENTATION #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION
std::unique_lock lock(s_init_mutex, std::defer_lock); std::unique_lock lock(s_init_mutex, std::defer_lock);
@ -709,8 +719,16 @@ static void Reset()
return; return;
#endif #endif
if (s_read_adapter_thread_running.TestAndClear()) if (called_from_read_thread == CalledFromReadThread::No)
s_read_adapter_thread.join(); {
if (s_read_adapter_thread_running.TestAndClear())
s_read_adapter_thread.join();
}
else
{
s_read_adapter_thread_needs_joining.Set();
s_read_adapter_thread_running.Clear();
}
// The read thread will close the write thread // The read thread will close the write thread
s_port_states.fill({}); s_port_states.fill({});
@ -790,7 +808,7 @@ void ProcessInputPayload(const u8* data, std::size_t size)
ERROR_LOG_FMT(CONTROLLERINTERFACE, "error reading payload (size: {}, type: {:02x})", size, ERROR_LOG_FMT(CONTROLLERINTERFACE, "error reading payload (size: {}, type: {:02x})", size,
data[0]); data[0]);
#if GCADAPTER_USE_ANDROID_IMPLEMENTATION #if GCADAPTER_USE_ANDROID_IMPLEMENTATION
Reset(); Reset(CalledFromReadThread::Yes);
#endif #endif
} }
else else