1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-10 12:41:47 +00:00

Proper USB background thread exit.

This commit is contained in:
Pablo Curiel 2020-07-12 12:37:03 -04:00
parent 400cab42a0
commit 8baa5800a1

View file

@ -101,9 +101,9 @@ static bool g_usbDeviceInterfaceInitialized = false;
static Event *g_usbStateChangeEvent = NULL;
static thrd_t g_usbDetectionThread;
static UEvent g_usbTimeoutEvent = {0};
static bool g_usbDetectionThreadCreated = false, g_usbHostAvailable = false, g_usbSessionStarted = false;
static atomic_bool g_usbDetectionThreadExit = false;
static UEvent g_usbDetectionThreadExitEvent = {0}, g_usbTimeoutEvent = {0};
static bool g_usbHostAvailable = false, g_usbSessionStarted = false, g_usbDetectionThreadExitFlag = false;
static atomic_bool g_usbDetectionThreadCreated = false;
static u8 *g_usbTransferBuffer = NULL;
static u64 g_usbTransferRemainingSize = 0;
@ -167,11 +167,15 @@ bool usbInitialize(void)
goto exit;
}
/* Create usermode exit event. */
ueventCreate(&g_usbDetectionThreadExitEvent, true);
/* Create usermode USB timeout event. */
ueventCreate(&g_usbTimeoutEvent, true);
/* Create USB detection thread. */
if (!(g_usbDetectionThreadCreated = usbCreateDetectionThread())) goto exit;
atomic_store(&g_usbDetectionThreadCreated, usbCreateDetectionThread());
if (!atomic_load(&g_usbDetectionThreadCreated)) goto exit;
ret = true;
@ -183,15 +187,14 @@ exit:
void usbExit(void)
{
/* Destroy USB detection thread. */
if (g_usbDetectionThreadCreated && !atomic_load(&g_usbDetectionThreadExit))
/* Destroy USB detection thread before attempting to lock. */
if (atomic_load(&g_usbDetectionThreadCreated))
{
atomic_store(&g_usbDetectionThreadExit, true);
usbDestroyDetectionThread();
g_usbDetectionThreadCreated = false;
atomic_store(&g_usbDetectionThreadExit, false);
atomic_store(&g_usbDetectionThreadCreated, false);
}
/* Now we can safely lock. */
rwlockWriteLock(&g_usbDeviceLock);
/* Clear USB state change kernel event. */
@ -346,6 +349,9 @@ static bool usbCreateDetectionThread(void)
static void usbDestroyDetectionThread(void)
{
/* Signal the exit event to terminate the USB detection thread */
ueventSignal(&g_usbDetectionThreadExitEvent);
/* Wait for the USB detection thread to exit. */
thrd_join(g_usbDetectionThread, NULL);
}
@ -359,28 +365,39 @@ static int usbDetectionThreadFunc(void *arg)
Waiter usb_change_event_waiter = waiterForEvent(g_usbStateChangeEvent);
Waiter usb_timeout_event_waiter = waiterForUEvent(&g_usbTimeoutEvent);
Waiter exit_event_waiter = waiterForUEvent(&g_usbDetectionThreadExitEvent);
while(true)
{
/* Check if the thread exit flag has been enabled. */
if (atomic_load(&g_usbDetectionThreadExit)) break;
/* Wait until an event is triggered (100 ms). */
rc = waitMulti(&idx, (u64)100000000, usb_change_event_waiter, usb_timeout_event_waiter);
/* Wait until an event is triggered. */
rc = waitMulti(&idx, -1, usb_change_event_waiter, usb_timeout_event_waiter, exit_event_waiter);
if (R_FAILED(rc)) continue;
rwlockWriteLock(&g_usbDeviceLock);
rwlockWriteLock(&(g_usbDeviceInterface.lock));
/* Exit event triggered. */
if (idx == 2) break;
/* Retrieve current USB connection status. */
/* Only proceed if we're dealing with a status change. */
g_usbHostAvailable = usbIsHostAvailable();
g_usbSessionStarted = false;
g_usbTransferRemainingSize = 0;
/* Start a USB session if we're connected to a host device and if the status change event was triggered. */
/* This will essentially hang this thread and all other threads that call USB-related functions until a session is established. */
if (g_usbHostAvailable) g_usbSessionStarted = usbStartSession();
/* Start an USB session if we're connected to a host device. */
/* This will essentially hang this thread and all other threads that call USB-related functions until: */
/* a) A session is established. */
/* b) The console is disconnected. */
/* c) The thread exit event is triggered. */
if (g_usbHostAvailable)
{
/* Wait until a session is established. */
g_usbSessionStarted = usbStartSession();
/* Check if the exit event was triggered while waiting for a session to be established. */
if (!g_usbSessionStarted && g_usbDetectionThreadExitFlag) break;
}
rwlockWriteUnlock(&(g_usbDeviceInterface.lock));
rwlockWriteUnlock(&g_usbDeviceLock);
@ -388,9 +405,12 @@ static int usbDetectionThreadFunc(void *arg)
/* Close USB session if needed. */
if (g_usbHostAvailable && g_usbSessionStarted) usbEndSession();
g_usbHostAvailable = g_usbSessionStarted = false;
g_usbHostAvailable = g_usbSessionStarted = g_usbDetectionThreadExitFlag = false;
g_usbTransferRemainingSize = 0;
rwlockWriteUnlock(&(g_usbDeviceInterface.lock));
rwlockWriteUnlock(&g_usbDeviceLock);
return 0;
}
@ -1014,20 +1034,16 @@ static bool usbTransferData(void *buf, u64 size, UsbDsEndpoint *endpoint)
rc = eventWait(&(endpoint->CompletionEvent), USB_TRANSFER_TIMEOUT * (u64)1000000000);
} else {
/* If we're starting an USB transfer session, wait indefinitely inside a loop to let the user start the companion app. */
while(true)
int idx = 0;
Waiter completion_event_waiter = waiterForEvent(&(endpoint->CompletionEvent));
Waiter exit_event_waiter = waiterForUEvent(&g_usbDetectionThreadExitEvent);
rc = waitMulti(&idx, -1, completion_event_waiter, exit_event_waiter);
if (R_SUCCEEDED(rc) && idx == 1)
{
/* Check if the thread exit flag has been enabled. */
if (atomic_load(&g_usbDetectionThreadExit))
{
rc = MAKERESULT(Module_Kernel, KernelError_TimedOut);
thread_exit = true;
break;
}
/* Wait for the endpoint completion event (100 ms). */
/* Break from this loop if the wait function succeeded, or if we got an result code different than TimedOut. */
rc = eventWait(&(endpoint->CompletionEvent), (u64)100000000);
if (R_SUCCEEDED(rc) || R_VALUE(rc) != KERNELRESULT(TimedOut)) break;
/* Exit event triggered. */
rc = MAKERESULT(Module_Kernel, KernelError_TimedOut);
g_usbDetectionThreadExitFlag = thread_exit = true;
}
}