From a19d3f233819f2142ca5d7fbd8fd31f67fd9031f Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Tue, 18 Aug 2020 01:04:13 -0400 Subject: [PATCH] Ditched C threads in favor of libnx threads. Preemptive multithreading is still used, just like libnx's newlib implementation. Also changed the version number because the rewrite deserves it. --- Makefile | 4 +- code_templates/threaded_usb_bktr_dumper.c | 26 ++++---- code_templates/threaded_usb_gc_dumper.c | 30 +++++---- source/gamecard.c | 12 ++-- source/main.c | 30 +++++---- source/title.c | 12 ++-- source/usb.c | 15 ++--- source/utils.c | 78 +++++++++++++++++++++++ source/utils.h | 4 +- 9 files changed, 148 insertions(+), 63 deletions(-) diff --git a/Makefile b/Makefile index 2ccd923..4f78bd5 100644 --- a/Makefile +++ b/Makefile @@ -31,8 +31,8 @@ include $(DEVKITPRO)/libnx/switch_rules # - /default_icon.jpg #--------------------------------------------------------------------------------- -VERSION_MAJOR := 1 -VERSION_MINOR := 2 +VERSION_MAJOR := 2 +VERSION_MINOR := 0 VERSION_MICRO := 0 APP_TITLE := nxdumptool-rewrite diff --git a/code_templates/threaded_usb_bktr_dumper.c b/code_templates/threaded_usb_bktr_dumper.c index e3b5470..acabb8a 100644 --- a/code_templates/threaded_usb_bktr_dumper.c +++ b/code_templates/threaded_usb_bktr_dumper.c @@ -51,20 +51,20 @@ static void consolePrint(const char *text, ...) consoleUpdate(NULL); } -static int read_thread_func(void *arg) +static void read_thread_func(void *arg) { ThreadSharedData *shared_data = (ThreadSharedData*)arg; if (!shared_data || !shared_data->data || !shared_data->total_size) { shared_data->read_error = true; - return -1; + goto end; } u8 *buf = malloc(TEST_BUF_SIZE); if (!buf) { shared_data->read_error = true; - return -2; + goto end; } u64 file_table_offset = 0; @@ -149,16 +149,17 @@ static int read_thread_func(void *arg) free(buf); - return (shared_data->read_error ? -3 : 0); +end: + threadExit(); } -static int write_thread_func(void *arg) +static void write_thread_func(void *arg) { ThreadSharedData *shared_data = (ThreadSharedData*)arg; if (!shared_data || !shared_data->data) { shared_data->write_error = true; - return -1; + goto end; } while(shared_data->data_written < shared_data->total_size) @@ -191,7 +192,8 @@ static int write_thread_func(void *arg) if (shared_data->write_error) break; } - return 0; +end: + threadExit(); } int main(int argc, char *argv[]) @@ -228,7 +230,7 @@ int main(int argc, char *argv[]) BktrContext bktr_ctx = {0}; ThreadSharedData shared_data = {0}; - thrd_t read_thread, write_thread; + Thread read_thread = {0}, write_thread = {0}; app_metadata = titleGetApplicationMetadataEntries(false, &app_count); if (!app_metadata || !app_count) @@ -420,8 +422,8 @@ int main(int argc, char *argv[]) } consolePrint("creating threads\n"); - thrd_create(&read_thread, read_thread_func, &shared_data); - thrd_create(&write_thread, write_thread_func, &shared_data); + utilsCreateThread(&read_thread, read_thread_func, &shared_data, 2); + utilsCreateThread(&write_thread, write_thread_func, &shared_data, 2); u8 prev_time = 0; u64 prev_size = 0; @@ -482,9 +484,9 @@ int main(int argc, char *argv[]) start = (time(NULL) - start); consolePrint("\nwaiting for threads to join\n"); - thrd_join(read_thread, NULL); + utilsJoinThread(&read_thread); consolePrint("read_thread done: %lu\n", time(NULL)); - thrd_join(write_thread, NULL); + utilsJoinThread(&write_thread); consolePrint("write_thread done: %lu\n", time(NULL)); utilsChangeHomeButtonBlockStatus(false); diff --git a/code_templates/threaded_usb_gc_dumper.c b/code_templates/threaded_usb_gc_dumper.c index 0ad3afe..ef00017 100644 --- a/code_templates/threaded_usb_gc_dumper.c +++ b/code_templates/threaded_usb_gc_dumper.c @@ -78,8 +78,8 @@ static void changeCertificateOption(u32 idx); static void changeTrimOption(u32 idx); static void changeCrcOption(u32 idx); -static int read_thread_func(void *arg); -static int write_thread_func(void *arg); +static void read_thread_func(void *arg); +static void write_thread_func(void *arg); /* Global variables. */ @@ -475,7 +475,7 @@ static bool sendGameCardImageViaUsb(void) GameCardKeyArea gc_key_area = {0}; ThreadSharedData shared_data = {0}; - thrd_t read_thread, write_thread; + Thread read_thread = {0}, write_thread = {0}; char *filename = NULL; @@ -530,8 +530,8 @@ static bool sendGameCardImageViaUsb(void) } consolePrint("creating threads\n"); - thrd_create(&read_thread, read_thread_func, &shared_data); - thrd_create(&write_thread, write_thread_func, &shared_data); + utilsCreateThread(&read_thread, read_thread_func, &shared_data, 2); + utilsCreateThread(&write_thread, write_thread_func, &shared_data, 2); u8 prev_time = 0; u64 prev_size = 0; @@ -590,9 +590,9 @@ static bool sendGameCardImageViaUsb(void) start = (time(NULL) - start); consolePrint("\nwaiting for threads to join\n"); - thrd_join(read_thread, NULL); + utilsJoinThread(&read_thread); consolePrint("read_thread done: %lu\n", time(NULL)); - thrd_join(write_thread, NULL); + utilsJoinThread(&write_thread); consolePrint("write_thread done: %lu\n", time(NULL)); if (shared_data.read_error || shared_data.write_error) @@ -651,20 +651,20 @@ static void changeCrcOption(u32 idx) g_calcCrc = (idx > 0); } -static int read_thread_func(void *arg) +static void read_thread_func(void *arg) { ThreadSharedData *shared_data = (ThreadSharedData*)arg; if (!shared_data || !shared_data->data || !shared_data->total_size) { shared_data->read_error = true; - return -1; + goto end; } u8 *buf = malloc(BLOCK_SIZE); if (!buf) { shared_data->read_error = true; - return -2; + goto end; } for(u64 offset = 0, blksize = BLOCK_SIZE; offset < shared_data->total_size; offset += blksize) @@ -718,16 +718,17 @@ static int read_thread_func(void *arg) free(buf); - return (shared_data->read_error ? -3 : 0); +end: + threadExit(); } -static int write_thread_func(void *arg) +static void write_thread_func(void *arg) { ThreadSharedData *shared_data = (ThreadSharedData*)arg; if (!shared_data || !shared_data->data) { shared_data->write_error = true; - return -1; + goto end; } while(shared_data->data_written < shared_data->total_size) @@ -758,5 +759,6 @@ static int write_thread_func(void *arg) if (shared_data->write_error) break; } - return (shared_data->write_error ? -2 : 0); +end: + threadExit(); } diff --git a/source/gamecard.c b/source/gamecard.c index 081758a..37077c7 100644 --- a/source/gamecard.c +++ b/source/gamecard.c @@ -92,7 +92,7 @@ static FsEventNotifier g_gameCardEventNotifier = {0}; static Event g_gameCardKernelEvent = {0}; static bool g_openDeviceOperator = false, g_openEventNotifier = false, g_loadKernelEvent = false; -static thrd_t g_gameCardDetectionThread; +static Thread g_gameCardDetectionThread = {0}; static UEvent g_gameCardDetectionThreadExitEvent = {0}, g_gameCardStatusChangeEvent = {0}; static bool g_gameCardDetectionThreadCreated = false, g_gameCardInserted = false, g_gameCardInfoLoaded = false; @@ -129,7 +129,7 @@ static const char *g_gameCardHfsPartitionNames[] = { static bool gamecardCreateDetectionThread(void); static void gamecardDestroyDetectionThread(void); -static int gamecardDetectionThreadFunc(void *arg); +static void gamecardDetectionThreadFunc(void *arg); NX_INLINE bool gamecardIsInserted(void); @@ -516,7 +516,7 @@ end: static bool gamecardCreateDetectionThread(void) { - if (thrd_create(&g_gameCardDetectionThread, gamecardDetectionThreadFunc, NULL) != thrd_success) + if (!utilsCreateThread(&g_gameCardDetectionThread, gamecardDetectionThreadFunc, NULL, 1)) { LOGFILE("Failed to create gamecard detection thread!"); return false; @@ -531,10 +531,10 @@ static void gamecardDestroyDetectionThread(void) ueventSignal(&g_gameCardDetectionThreadExitEvent); /* Wait for the gamecard detection thread to exit. */ - thrd_join(g_gameCardDetectionThread, NULL); + utilsJoinThread(&g_gameCardDetectionThread); } -static int gamecardDetectionThreadFunc(void *arg) +static void gamecardDetectionThreadFunc(void *arg) { (void)arg; @@ -588,7 +588,7 @@ static int gamecardDetectionThreadFunc(void *arg) gamecardFreeInfo(); g_gameCardInserted = false; - return 0; + threadExit(); } NX_INLINE bool gamecardIsInserted(void) diff --git a/source/main.c b/source/main.c index 0ad3afe..ef00017 100644 --- a/source/main.c +++ b/source/main.c @@ -78,8 +78,8 @@ static void changeCertificateOption(u32 idx); static void changeTrimOption(u32 idx); static void changeCrcOption(u32 idx); -static int read_thread_func(void *arg); -static int write_thread_func(void *arg); +static void read_thread_func(void *arg); +static void write_thread_func(void *arg); /* Global variables. */ @@ -475,7 +475,7 @@ static bool sendGameCardImageViaUsb(void) GameCardKeyArea gc_key_area = {0}; ThreadSharedData shared_data = {0}; - thrd_t read_thread, write_thread; + Thread read_thread = {0}, write_thread = {0}; char *filename = NULL; @@ -530,8 +530,8 @@ static bool sendGameCardImageViaUsb(void) } consolePrint("creating threads\n"); - thrd_create(&read_thread, read_thread_func, &shared_data); - thrd_create(&write_thread, write_thread_func, &shared_data); + utilsCreateThread(&read_thread, read_thread_func, &shared_data, 2); + utilsCreateThread(&write_thread, write_thread_func, &shared_data, 2); u8 prev_time = 0; u64 prev_size = 0; @@ -590,9 +590,9 @@ static bool sendGameCardImageViaUsb(void) start = (time(NULL) - start); consolePrint("\nwaiting for threads to join\n"); - thrd_join(read_thread, NULL); + utilsJoinThread(&read_thread); consolePrint("read_thread done: %lu\n", time(NULL)); - thrd_join(write_thread, NULL); + utilsJoinThread(&write_thread); consolePrint("write_thread done: %lu\n", time(NULL)); if (shared_data.read_error || shared_data.write_error) @@ -651,20 +651,20 @@ static void changeCrcOption(u32 idx) g_calcCrc = (idx > 0); } -static int read_thread_func(void *arg) +static void read_thread_func(void *arg) { ThreadSharedData *shared_data = (ThreadSharedData*)arg; if (!shared_data || !shared_data->data || !shared_data->total_size) { shared_data->read_error = true; - return -1; + goto end; } u8 *buf = malloc(BLOCK_SIZE); if (!buf) { shared_data->read_error = true; - return -2; + goto end; } for(u64 offset = 0, blksize = BLOCK_SIZE; offset < shared_data->total_size; offset += blksize) @@ -718,16 +718,17 @@ static int read_thread_func(void *arg) free(buf); - return (shared_data->read_error ? -3 : 0); +end: + threadExit(); } -static int write_thread_func(void *arg) +static void write_thread_func(void *arg) { ThreadSharedData *shared_data = (ThreadSharedData*)arg; if (!shared_data || !shared_data->data) { shared_data->write_error = true; - return -1; + goto end; } while(shared_data->data_written < shared_data->total_size) @@ -758,5 +759,6 @@ static int write_thread_func(void *arg) if (shared_data->write_error) break; } - return (shared_data->write_error ? -2 : 0); +end: + threadExit(); } diff --git a/source/title.c b/source/title.c index 74e6bab..080b6a1 100644 --- a/source/title.c +++ b/source/title.c @@ -34,7 +34,7 @@ typedef struct { /* Global variables. */ static Mutex g_titleMutex = 0; -static thrd_t g_titleGameCardInfoThread; +static Thread g_titleGameCardInfoThread = {0}; static UEvent g_titleGameCardInfoThreadExitEvent = {0}, *g_titleGameCardStatusChangeUserEvent = NULL; static bool g_titleInterfaceInit = false, g_titleGameCardInfoThreadCreated = false, g_titleGameCardAvailable = false, g_titleGameCardInfoUpdated = false; @@ -395,7 +395,7 @@ static bool titleGetContentInfosFromTitle(u8 storage_id, const NcmContentMetaKey static bool titleCreateGameCardInfoThread(void); static void titleDestroyGameCardInfoThread(void); -static int titleGameCardInfoThreadFunc(void *arg); +static void titleGameCardInfoThreadFunc(void *arg); static bool titleRefreshGameCardTitleInfo(void); static void titleRemoveGameCardTitleInfoEntries(void); @@ -1510,7 +1510,7 @@ end: static bool titleCreateGameCardInfoThread(void) { - if (thrd_create(&g_titleGameCardInfoThread, titleGameCardInfoThreadFunc, NULL) != thrd_success) + if (!utilsCreateThread(&g_titleGameCardInfoThread, titleGameCardInfoThreadFunc, NULL, 1)) { LOGFILE("Failed to create gamecard title info thread!"); return false; @@ -1525,10 +1525,10 @@ static void titleDestroyGameCardInfoThread(void) ueventSignal(&g_titleGameCardInfoThreadExitEvent); /* Wait for the gamecard title info thread to exit. */ - thrd_join(g_titleGameCardInfoThread, NULL); + utilsJoinThread(&g_titleGameCardInfoThread); } -static int titleGameCardInfoThreadFunc(void *arg) +static void titleGameCardInfoThreadFunc(void *arg) { (void)arg; @@ -1561,7 +1561,7 @@ static int titleGameCardInfoThreadFunc(void *arg) /* Update gamecard flags. */ g_titleGameCardAvailable = g_titleGameCardInfoUpdated = false; - return 0; + threadExit(); } static bool titleRefreshGameCardTitleInfo(void) diff --git a/source/usb.c b/source/usb.c index 529c0c1..d9b823e 100644 --- a/source/usb.c +++ b/source/usb.c @@ -109,7 +109,7 @@ static usbDeviceInterface g_usbDeviceInterface = {0}; static bool g_usbDeviceInterfaceInitialized = false; static Event *g_usbStateChangeEvent = NULL; -static thrd_t g_usbDetectionThread; +static Thread g_usbDetectionThread = {0}; 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; @@ -123,7 +123,7 @@ static u16 g_usbEndpointMaxPacketSize = 0; static bool usbCreateDetectionThread(void); static void usbDestroyDetectionThread(void); -static int usbDetectionThreadFunc(void *arg); +static void usbDetectionThreadFunc(void *arg); static bool usbStartSession(void); static void usbEndSession(void); @@ -407,7 +407,7 @@ end: static bool usbCreateDetectionThread(void) { - if (thrd_create(&g_usbDetectionThread, usbDetectionThreadFunc, NULL) != thrd_success) + if (!utilsCreateThread(&g_usbDetectionThread, usbDetectionThreadFunc, NULL, 1)) { LOGFILE("Failed to create USB detection thread!"); return false; @@ -422,10 +422,10 @@ static void usbDestroyDetectionThread(void) ueventSignal(&g_usbDetectionThreadExitEvent); /* Wait for the USB detection thread to exit. */ - thrd_join(g_usbDetectionThread, NULL); + utilsJoinThread(&g_usbDetectionThread); } -static int usbDetectionThreadFunc(void *arg) +static void usbDetectionThreadFunc(void *arg) { (void)arg; @@ -485,7 +485,7 @@ static int usbDetectionThreadFunc(void *arg) rwlockWriteUnlock(&(g_usbDeviceInterface.lock)); rwlockWriteUnlock(&g_usbDeviceLock); - return 0; + threadExit(); } static bool usbStartSession(void) @@ -545,8 +545,7 @@ static bool usbGetMaxPacketSizeFromHost(void) usbDsEndpoint_Stall(g_usbDeviceInterface.endpoint_in); rwlockWriteUnlock(&(g_usbDeviceInterface.lock_in)); - /* Reset updated variables. */ - g_usbSessionStarted = false; + /* Reset endpoint max packet size. */ g_usbEndpointMaxPacketSize = 0; return false; diff --git a/source/utils.c b/source/utils.c index fe41690..ce4c17f 100644 --- a/source/utils.c +++ b/source/utils.c @@ -204,6 +204,84 @@ void utilsCloseResources(void) mutexUnlock(&g_resourcesMutex); } +bool utilsCreateThread(Thread *out_thread, ThreadFunc func, void *arg, int cpu_id) +{ + /* Core 3 is reserved for HOS, so we can only use cores 0, 1 and 2. */ + /* -2 can be provided to use the default process core. */ + if (!out_thread || !func || (cpu_id < 0 && cpu_id != -2) || cpu_id > 2) + { + LOGFILE("Invalid parameters!"); + return false; + } + + Result rc = 0; + u64 core_mask = 0; + size_t stack_size = 0x20000; /* Same value as libnx's newlib. */ + bool success = false; + + memset(out_thread, 0, sizeof(Thread)); + + /* Get process core mask. */ + rc = svcGetInfo(&core_mask, InfoType_CoreMask, CUR_PROCESS_HANDLE, 0); + if (R_FAILED(rc)) + { + LOGFILE("svcGetInfo failed! (0x%08X).", rc); + goto end; + } + + /* Create thread. */ + /* Enable preemptive multithreading by using priority 0x3B. */ + rc = threadCreate(out_thread, func, arg, NULL, stack_size, 0x3B, cpu_id); + if (R_FAILED(rc)) + { + LOGFILE("threadCreate failed! (0x%08X).", rc); + goto end; + } + + /* Set thread core mask. */ + rc = svcSetThreadCoreMask(out_thread->handle, cpu_id == -2 ? -1 : cpu_id, core_mask); + if (R_FAILED(rc)) + { + LOGFILE("svcSetThreadCoreMask failed! (0x%08X).", rc); + goto end; + } + + /* Start thread. */ + rc = threadStart(out_thread); + if (R_FAILED(rc)) + { + LOGFILE("threadStart failed! (0x%08X).", rc); + goto end; + } + + success = true; + +end: + if (!success && out_thread->handle != INVALID_HANDLE) threadClose(out_thread); + + return success; +} + +void utilsJoinThread(Thread *thread) +{ + if (!thread || thread->handle == INVALID_HANDLE) + { + LOGFILE("Invalid parameters!"); + return; + } + + Result rc = threadWaitForExit(thread); + if (R_FAILED(rc)) + { + LOGFILE("threadWaitForExit failed! (0x%08X).", rc); + return; + } + + threadClose(thread); + + memset(thread, 0, sizeof(Thread)); +} + bool utilsIsDevelopmentUnit(void) { mutexLock(&g_resourcesMutex); diff --git a/source/utils.h b/source/utils.h index 779d19a..33e46e6 100644 --- a/source/utils.h +++ b/source/utils.h @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -76,6 +75,9 @@ typedef enum { bool utilsInitializeResources(void); void utilsCloseResources(void); +bool utilsCreateThread(Thread *out_thread, ThreadFunc func, void *arg, int cpu_id); +void utilsJoinThread(Thread *thread); + bool utilsIsDevelopmentUnit(void); /// hidScanInput() must be called before any of these functions.