From 2703080df21cfa71ab90428d5c6a794fcc08b162 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Thu, 20 Oct 2022 21:58:10 -0700 Subject: [PATCH] [kernel] Add thread_join syscall Thread joining is an important primitive that I seem to have totally forgotten to implement previously. --- definitions/objects/thread.def | 3 +++ src/kernel/objects/thread.cpp | 14 ++++++++++++++ src/kernel/objects/thread.h | 12 +++++++++--- src/kernel/syscalls/thread.cpp | 6 ++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/definitions/objects/thread.def b/definitions/objects/thread.def index 757b527..94c2b5e 100644 --- a/definitions/objects/thread.def +++ b/definitions/objects/thread.def @@ -3,6 +3,7 @@ object thread : object { capabilities [ kill + join ] method create [constructor] { @@ -13,6 +14,8 @@ object thread : object { method kill [destructor cap:kill] + method join [cap:join] + method exit [static] method sleep [static] { diff --git a/src/kernel/objects/thread.cpp b/src/kernel/objects/thread.cpp index e24934d..2450b71 100644 --- a/src/kernel/objects/thread.cpp +++ b/src/kernel/objects/thread.cpp @@ -52,6 +52,20 @@ thread::block() return m_wake_value; } +j6_status_t +thread::join() +{ + if (has_state(state::exited)) + return j6_status_ok; + + thread &caller = current(); + if (&caller == this) + return j6_err_invalid_arg; + + m_join_queue.add_thread(&caller); + return caller.block(); +} + void thread::wake(uint64_t value) { diff --git a/src/kernel/objects/thread.h b/src/kernel/objects/thread.h index 9b2abbe..5fb1e12 100644 --- a/src/kernel/objects/thread.h +++ b/src/kernel/objects/thread.h @@ -8,6 +8,7 @@ #include #include "objects/kobject.h" +#include "wait_queue.h" struct cpu_data; struct page_table; @@ -98,6 +99,9 @@ public: /// \returns The value passed to wake() uint64_t block(); + /// Block the calling thread until this thread exits + j6_status_t join(); + /// Wake this thread, giving it a value /// \arg value The value that block() should return void wake(uint64_t value = 0); @@ -123,15 +127,16 @@ public: message_data & get_message_data() { return m_message_data; } inline bool has_state(state s) const { - return static_cast(m_state) & static_cast(s); + return __atomic_load_n(reinterpret_cast(&m_state), __ATOMIC_ACQUIRE) & + static_cast(s); } inline void set_state(state s) { - m_state = static_cast(static_cast(m_state) | static_cast(s)); + __atomic_or_fetch(reinterpret_cast(&m_state), static_cast(s), __ATOMIC_ACQ_REL); } inline void clear_state(state s) { - m_state = static_cast(static_cast(m_state) & ~static_cast(s)); + __atomic_and_fetch(reinterpret_cast(&m_state), ~static_cast(s), __ATOMIC_ACQ_REL); } inline tcb_node * tcb() { return &m_tcb; } @@ -191,6 +196,7 @@ private: uint64_t m_wake_timeout; message_data m_message_data; + wait_queue m_join_queue; j6_handle_t m_self_handle; }; diff --git a/src/kernel/syscalls/thread.cpp b/src/kernel/syscalls/thread.cpp index bb1467a..64e83e4 100644 --- a/src/kernel/syscalls/thread.cpp +++ b/src/kernel/syscalls/thread.cpp @@ -36,6 +36,12 @@ thread_kill(thread *self) return j6_status_ok; } +j6_status_t +thread_join(thread *self) +{ + return self->join(); +} + j6_status_t thread_exit() {