]> Chaos Git - corbenik/ctrulib.git/commitdiff
Add WIP thread wrapper API
authorfincs <fincs.alt1@gmail.com>
Sat, 21 Nov 2015 17:55:05 +0000 (18:55 +0100)
committerfincs <fincs.alt1@gmail.com>
Mon, 7 Dec 2015 10:43:54 +0000 (11:43 +0100)
libctru/include/3ds.h
libctru/include/3ds/svc.h
libctru/include/3ds/thread.h [new file with mode: 0644]
libctru/source/internal.h
libctru/source/system/syscalls.c
libctru/source/thread.c [new file with mode: 0644]

index a2c8e72a91f6d47e475684be31f9c27fbbeaacf9..6d59617d5a0c96793a9ca5c556b1ac355fd6984a 100644 (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>
index c5ab683a382815bec067ba4a89c538a766e33e6f..8a5af5895eed93c7e76c6dda197097411515036c 100644 (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
diff --git a/libctru/include/3ds/thread.h b/libctru/include/3ds/thread.h
new file mode 100644 (file)
index 0000000..36ede63
--- /dev/null
@@ -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));
index 53a4c9f1bb0a4d938b61c36ea9e54f9e98dbdcac..269c9c34eb0b71a69481b3b9295a0dbaf489d139 100644 (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;
 
index 3cb5734fbd3e69650289985c32449438ce1090ed..a27482b69cedeb0aa82d5f14904b9e9a07811f7e 100644 (file)
@@ -45,4 +45,5 @@ void __system_initSyscalls(void)
        ThreadVars* tv = getThreadVars();
        tv->magic = THREADVARS_MAGIC;
        tv->reent = _impure_ptr;
+       tv->thread_ptr = NULL;
 }
diff --git a/libctru/source/thread.c b/libctru/source/thread.c
new file mode 100644 (file)
index 0000000..382534c
--- /dev/null
@@ -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();
+}