Add WIP thread wrapper API

This commit is contained in:
fincs 2015-11-21 18:55:05 +01:00
parent 05b8ce5b5d
commit b1e97f2ca4
6 changed files with 141 additions and 3 deletions

View File

@ -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>

View File

@ -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

View 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));

View File

@ -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;

View File

@ -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
View 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();
}