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:
parent
400cab42a0
commit
8baa5800a1
1 changed files with 47 additions and 31 deletions
78
source/usb.c
78
source/usb.c
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue