From 3cfd0cf86b318c1d6ad39a62a81d5ce3cf93ed87 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Wed, 9 Aug 2023 21:07:09 -0700 Subject: [PATCH] [libj6] Make j6::thread a template for lambdas Instead of a C-style function pointer taking `void *userdata`, let j6::thread take a lambda as its thread procedure. --- src/libraries/j6/include/j6/thread.hh | 55 ++++++++++++++++++----- src/libraries/j6/j6.module | 1 - src/libraries/j6/thread.cpp | 65 --------------------------- src/user/testapp/main.cpp | 4 +- 4 files changed, 47 insertions(+), 78 deletions(-) delete mode 100644 src/libraries/j6/thread.cpp diff --git a/src/libraries/j6/include/j6/thread.hh b/src/libraries/j6/include/j6/thread.hh index 9cbf7f9..615090b 100644 --- a/src/libraries/j6/include/j6/thread.hh +++ b/src/libraries/j6/include/j6/thread.hh @@ -8,40 +8,75 @@ #include #include +#include +#include #include +#include namespace j6 { +template class thread { public: - using proc = void (*)(void *); - /// Constructor. Create a thread and its stack space, but /// do not start executing the thread. - /// \arg p The function where the thread will begin execution - /// \arg stack_top The address where the top of this thread's stack should be mapped - thread(proc p, uintptr_t stack_top); + /// \arg p The function where the thread will begin execution + /// \arg stack_top The address where the top of this thread's stack should be mapped + /// \arg stack_size Size of the stack, in bytes (default 64KiB) + thread(Proc p, uintptr_t stack_top, size_t stack_size = 0x10000) : + m_stack {j6_handle_invalid}, + m_thread {j6_handle_invalid}, + m_stack_top {stack_top}, + m_proc {p} + { + uintptr_t stack_base = stack_top - stack_size; + m_status = j6_vma_create_map(&m_stack, stack_size, stack_base, j6_vm_flag_write); + if (m_status != j6_status_ok) + return; + + static constexpr size_t zeros_size = 0x10; + m_stack_top -= zeros_size; // Sentinel + memset(reinterpret_cast(m_stack_top), 0, zeros_size); + } /// Start executing the thread. - /// \arg user Optional pointer to user data to pass to the thread proc /// \returns j6_status_ok if the thread was successfully started. - j6_status_t start(void *user = nullptr); + j6_status_t start() + { + if (m_status != j6_status_ok) + return m_status; + + if (m_thread != j6_handle_invalid) + return j6_err_invalid_arg; + + uint64_t arg0 = reinterpret_cast(this); + + m_status = j6_thread_create(&m_thread, 0, + m_stack_top, reinterpret_cast(init_proc), + arg0, 0); + + return m_status; + } /// Wait for the thread to stop executing. - void join(); + void join() { j6_thread_join(m_thread); } thread() = delete; thread(const thread&) = delete; private: - static void init_proc(thread *t, void *user); + static void init_proc(thread *t) + { + t->m_proc(); + j6_thread_exit(); + } j6_status_t m_status; j6_handle_t m_stack; j6_handle_t m_thread; uintptr_t m_stack_top; - proc m_proc; + Proc m_proc; }; } // namespace j6 diff --git a/src/libraries/j6/j6.module b/src/libraries/j6/j6.module index 026082a..7be0e93 100644 --- a/src/libraries/j6/j6.module +++ b/src/libraries/j6/j6.module @@ -15,7 +15,6 @@ j6 = module("j6", "syscalls.s.cog", "sysconf.cpp.cog", "syslog.cpp", - "thread.cpp", ], public_headers = [ "j6/cap_flags.h.cog", diff --git a/src/libraries/j6/thread.cpp b/src/libraries/j6/thread.cpp deleted file mode 100644 index dc7c25c..0000000 --- a/src/libraries/j6/thread.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// The kernel depends on libj6 for some shared code, -// but should not include the user-specific code. -#ifndef __j6kernel - -#include -#include -#include -#include -#include - -namespace j6 { - -static constexpr size_t stack_size = 0x10000; -static constexpr size_t zeros_size = 0x10; - -thread::thread(thread::proc p, uintptr_t stack_top) : - m_stack {j6_handle_invalid}, - m_thread {j6_handle_invalid}, - m_stack_top {stack_top}, - m_proc {p} -{ - uintptr_t stack_base = stack_top - stack_size; - m_status = j6_vma_create_map(&m_stack, stack_size, stack_base, j6_vm_flag_write); - if (m_status != j6_status_ok) - return; - - m_stack_top -= zeros_size; - memset(reinterpret_cast(m_stack_top), 0, zeros_size); -} - -j6_status_t -thread::start(void *user) -{ - if (m_status != j6_status_ok) - return m_status; - - if (m_thread != j6_handle_invalid) - return j6_err_invalid_arg; - - uint64_t arg0 = reinterpret_cast(this); - uint64_t arg1 = reinterpret_cast(user); - - m_status = j6_thread_create(&m_thread, 0, - m_stack_top, reinterpret_cast(init_proc), - arg0, arg1); - - return m_status; -} - -void -thread::join() -{ - j6_thread_join(m_thread); -} - -void -thread::init_proc(thread *t, void *user) -{ - t->m_proc(user); - j6_thread_exit(); -} - -} // namespace j6 - -#endif // __j6kernel diff --git a/src/user/testapp/main.cpp b/src/user/testapp/main.cpp index 42203ff..e80f1bf 100644 --- a/src/user/testapp/main.cpp +++ b/src/user/testapp/main.cpp @@ -111,8 +111,8 @@ main(int argc, const char **argv) j6_log("main thread created channel"); - j6::thread child_thread {thread_proc, stack_top}; - j6_status_t result = child_thread.start(chan); + j6::thread child_thread {[=](){ thread_proc(chan); }, stack_top}; + j6_status_t result = child_thread.start(); if (result != j6_status_ok) return result;