mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-26 04:02:11 +00:00
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.
This commit is contained in:
parent
1e50cec315
commit
a19d3f2338
9 changed files with 148 additions and 63 deletions
4
Makefile
4
Makefile
|
@ -31,8 +31,8 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||
# - <libnx folder>/default_icon.jpg
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
VERSION_MAJOR := 1
|
||||
VERSION_MINOR := 2
|
||||
VERSION_MAJOR := 2
|
||||
VERSION_MINOR := 0
|
||||
VERSION_MICRO := 0
|
||||
|
||||
APP_TITLE := nxdumptool-rewrite
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
15
source/usb.c
15
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <threads.h>
|
||||
#include <stdatomic.h>
|
||||
#include <switch.h>
|
||||
|
||||
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue