From 6583744532bf72b785000c8e10bab3027c7ac65f Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Thu, 20 Oct 2022 22:12:02 -0700 Subject: [PATCH] [libj6] Add thread wrapper class This new class makes it easier for user programs to spawn threads. This change also includes support for .hh files in modules, to differentiate headers that are C++-only in system libraries. --- scripts/bonnibel/source.py | 4 +-- src/libraries/j6/j6.module | 2 ++ src/libraries/j6/j6/thread.hh | 46 ++++++++++++++++++++++++++++++++ src/libraries/j6/thread.cpp | 50 +++++++++++++++++++++++++++++++++++ src/user/drv.uart/main.cpp | 14 +++------- 5 files changed, 103 insertions(+), 13 deletions(-) create mode 100644 src/libraries/j6/j6/thread.hh create mode 100644 src/libraries/j6/thread.cpp diff --git a/scripts/bonnibel/source.py b/scripts/bonnibel/source.py index aa09673..8fbda67 100644 --- a/scripts/bonnibel/source.py +++ b/scripts/bonnibel/source.py @@ -49,7 +49,7 @@ class ParseSource(Source): @property def gather(self): _, suffix = splitext(self.output) - return suffix in (".h", ".inc") + return suffix in (".h", ".hh", ".inc") @property def next(self): @@ -113,7 +113,7 @@ def make_source(root, path): return CompileSource(path, root) elif suffix in (".cog",): return ParseSource(path, root) - elif suffix in (".h", ".inc"): + elif suffix in (".h", ".hh", ".inc"): return HeaderSource(path, root) else: raise RuntimeError(f"{path} has no Source type") diff --git a/src/libraries/j6/j6.module b/src/libraries/j6/j6.module index ba3c5e4..a6ff0b7 100644 --- a/src/libraries/j6/j6.module +++ b/src/libraries/j6/j6.module @@ -8,6 +8,7 @@ j6 = module("j6", "protocol_ids.cpp", "syscalls.s.cog", "sysconf.cpp.cog", + "thread.cpp", ], public_headers = [ "j6/cap_flags.h.cog", @@ -18,6 +19,7 @@ j6 = module("j6", "j6/protocols/service_locator.h", "j6/syscalls.h.cog", "j6/sysconf.h.cog", + "j6/thread.hh", "j6/types.h", "j6/tables/log_areas.inc", diff --git a/src/libraries/j6/j6/thread.hh b/src/libraries/j6/j6/thread.hh new file mode 100644 index 0000000..dd63e51 --- /dev/null +++ b/src/libraries/j6/j6/thread.hh @@ -0,0 +1,46 @@ +#pragma once +/// \file thread.h +/// High level threading interface + +// The kernel depends on libj6 for some shared code, +// but should not include the user-specific code. +#ifndef __j6kernel + +#include +#include +#include + +namespace j6 { + +class thread +{ +public: + using proc = 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); + + /// Start executing the thread. + /// \returns j6_status_ok if the thread was successfully started. + j6_status_t start(); + + /// Wait for the thread to stop executing. + void join(); + + thread() = delete; + thread(const thread&) = delete; + +private: + j6_status_t m_status; + j6_handle_t m_stack; + j6_handle_t m_thread; + uintptr_t m_stack_top; + proc m_proc; +}; + +} // namespace j6 + +#endif // __j6kernel diff --git a/src/libraries/j6/thread.cpp b/src/libraries/j6/thread.cpp new file mode 100644 index 0000000..0fd9cc3 --- /dev/null +++ b/src/libraries/j6/thread.cpp @@ -0,0 +1,50 @@ +// The kernel depends on libj6 for some shared code, +// but should not include the user-specific code. +#ifndef __j6kernel + +#include +#include +#include +#include +#include + +extern j6_handle_t __handle_self; + +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() +{ + if (m_status != j6_status_ok) + return m_status; + + if (m_thread != j6_handle_invalid) + return j6_err_invalid_arg; + + m_status = j6_thread_create(&m_thread, __handle_self, + m_stack_top, reinterpret_cast(m_proc)); + + return m_status; +} + +} + +#endif // __j6kernel diff --git a/src/user/drv.uart/main.cpp b/src/user/drv.uart/main.cpp index 70dbd4c..ae2c846 100644 --- a/src/user/drv.uart/main.cpp +++ b/src/user/drv.uart/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,6 @@ uint8_t com2_out[out_buf_size]; serial_port *g_com1; serial_port *g_com2; -constexpr size_t stack_size = 0x10000; constexpr uintptr_t stack_top = 0xf80000000; int @@ -119,16 +119,8 @@ main(int argc, const char **argv) g_com1 = &com1; g_com2 = &com2; - j6_handle_t child_stack_vma = j6_handle_invalid; - result = j6_vma_create_map(&child_stack_vma, stack_size, stack_top-stack_size, j6_vm_flag_write); - if (result != j6_status_ok) - return result; - - uint64_t *sp = reinterpret_cast(stack_top - 0x10); - sp[0] = sp[1] = 0; - - j6_handle_t child = j6_handle_invalid; - result = j6_thread_create(&child, __handle_self, stack_top - 0x10, reinterpret_cast(&pump_proc)); + j6::thread pump_thread {pump_proc, stack_top}; + result = pump_thread.start(); if (result != j6_status_ok) return result;