Add WIP thread wrapper API
This commit is contained in:
parent
05b8ce5b5d
commit
b1e97f2ca4
@ -16,6 +16,7 @@ extern "C" {
|
||||
#include <3ds/srv.h>
|
||||
#include <3ds/os.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/thread.h>
|
||||
#include <3ds/gfx.h>
|
||||
#include <3ds/console.h>
|
||||
#include <3ds/env.h>
|
||||
|
@ -579,7 +579,7 @@ Result svcSetThreadIdealProcessor(Handle thread, s32 processorid);
|
||||
* @brief Returns the ID of the processor the current thread is running on.
|
||||
* @sa svcCreateThread
|
||||
*/
|
||||
s32 svcGetProcessorID();
|
||||
s32 svcGetProcessorID(void);
|
||||
|
||||
/**
|
||||
* @brief Gets the ID of a thread.
|
||||
@ -755,7 +755,7 @@ Result svcClearTimer(Handle timer);
|
||||
* @brief Gets the current system tick.
|
||||
* @return The current system tick.
|
||||
*/
|
||||
u64 svcGetSystemTick();
|
||||
u64 svcGetSystemTick(void);
|
||||
///@}
|
||||
|
||||
///@name System
|
||||
|
20
libctru/include/3ds/thread.h
Normal file
20
libctru/include/3ds/thread.h
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @file thread.h
|
||||
* @brief Provides functions to use threads.
|
||||
*/
|
||||
#pragma once
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/svc.h>
|
||||
|
||||
typedef struct Thread_tag* Thread;
|
||||
|
||||
Thread threadCreate(ThreadFunc entrypoint, void* arg, size_t stack_size, int prio, int affinity, bool detached);
|
||||
Handle threadGetHandle(Thread thread);
|
||||
int threadGetExitCode(Thread thread);
|
||||
void threadFree(Thread thread);
|
||||
Result threadJoin(Thread thread, u64 timeout_ns);
|
||||
|
||||
Thread threadGetCurrent(void);
|
||||
void threadExit(int rc) __attribute__((noreturn));
|
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
#include <sys/reent.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <sys/reent.h>
|
||||
#include <3ds/thread.h>
|
||||
|
||||
#define THREADVARS_MAGIC 0x21545624 // !TV$
|
||||
#define FS_OVERRIDE_MAGIC 0x21465324 // !FS$
|
||||
@ -13,6 +14,9 @@ typedef struct
|
||||
// Magic value used to check if the struct is initialized
|
||||
u32 magic;
|
||||
|
||||
// Pointer to the current thread (if exists)
|
||||
Thread thread_ptr;
|
||||
|
||||
// Pointer to this thread's newlib state
|
||||
struct _reent* reent;
|
||||
|
||||
|
@ -45,4 +45,5 @@ void __system_initSyscalls(void)
|
||||
ThreadVars* tv = getThreadVars();
|
||||
tv->magic = THREADVARS_MAGIC;
|
||||
tv->reent = _impure_ptr;
|
||||
tv->thread_ptr = NULL;
|
||||
}
|
||||
|
112
libctru/source/thread.c
Normal file
112
libctru/source/thread.c
Normal file
@ -0,0 +1,112 @@
|
||||
#include "internal.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct Thread_tag
|
||||
{
|
||||
Handle handle;
|
||||
ThreadFunc ep;
|
||||
void* arg;
|
||||
int rc;
|
||||
bool detached, finished;
|
||||
struct _reent reent;
|
||||
void* stacktop;
|
||||
};
|
||||
|
||||
static void __panic(void)
|
||||
{
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static void _thread_begin(void* arg)
|
||||
{
|
||||
Thread t = (Thread)arg;
|
||||
ThreadVars* tv = getThreadVars();
|
||||
tv->magic = THREADVARS_MAGIC;
|
||||
tv->reent = &t->reent;
|
||||
tv->thread_ptr = t;
|
||||
t->ep(t->arg);
|
||||
threadExit(0);
|
||||
}
|
||||
|
||||
Thread threadCreate(ThreadFunc entrypoint, void* arg, size_t stack_size, int prio, int affinity, bool detached)
|
||||
{
|
||||
size_t stackoffset = (sizeof(struct Thread_tag)+7)&~7;
|
||||
size_t allocsize = stackoffset + ((stack_size+7)&~7);
|
||||
if (allocsize < stackoffset) return NULL; // guard against overflow
|
||||
if ((allocsize-stackoffset) < stack_size) return NULL; // guard against overflow
|
||||
Thread t = (Thread)malloc(allocsize);
|
||||
if (!t) return NULL;
|
||||
|
||||
t->ep = entrypoint;
|
||||
t->arg = arg;
|
||||
t->detached = detached;
|
||||
t->finished = false;
|
||||
t->stacktop = (u8*)t + allocsize;
|
||||
|
||||
// Set up child thread's reent struct, inheriting standard file handles
|
||||
_REENT_INIT_PTR(&t->reent);
|
||||
struct _reent* cur = getThreadVars()->reent;
|
||||
t->reent._stdin = cur->_stdin;
|
||||
t->reent._stdout = cur->_stdout;
|
||||
t->reent._stderr = cur->_stderr;
|
||||
|
||||
Result rc;
|
||||
rc = svcCreateThread(&t->handle, _thread_begin, (u32)t, (u32*)t->stacktop, prio, affinity);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Handle threadGetHandle(Thread thread)
|
||||
{
|
||||
if (!thread || thread->finished) return ~0UL;
|
||||
return thread->handle;
|
||||
}
|
||||
|
||||
int threadGetExitCode(Thread thread)
|
||||
{
|
||||
if (!thread || !thread->finished) return 0;
|
||||
return thread->rc;
|
||||
}
|
||||
|
||||
void threadFree(Thread thread)
|
||||
{
|
||||
if (!thread || !thread->finished) return;
|
||||
svcCloseHandle(thread->handle);
|
||||
free(thread);
|
||||
}
|
||||
|
||||
Result threadJoin(Thread thread, u64 timeout_ns)
|
||||
{
|
||||
if (!thread || thread->finished) return 0;
|
||||
return svcWaitSynchronization(thread->handle, timeout_ns);
|
||||
}
|
||||
|
||||
Thread threadGetCurrent(void)
|
||||
{
|
||||
ThreadVars* tv = getThreadVars();
|
||||
if (tv->magic != THREADVARS_MAGIC)
|
||||
__panic();
|
||||
return tv->thread_ptr;
|
||||
}
|
||||
|
||||
void threadExit(int rc)
|
||||
{
|
||||
Thread t = threadGetCurrent();
|
||||
if (!t)
|
||||
__panic();
|
||||
|
||||
t->finished = true;
|
||||
if (t->detached)
|
||||
threadFree(t);
|
||||
else
|
||||
t->rc = rc;
|
||||
|
||||
svcExitThread();
|
||||
}
|
Loading…
Reference in New Issue
Block a user