From d44ec53cd3ceda416a3453c6b3223250ee3fc985 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 26 Jun 2024 17:26:12 +0200 Subject: [PATCH] core: tie Platform_thread to Platform_pd This patch tightens the coupling of the 'Platform_thread' objects with their corresponding 'Platform_pd' objects by specifying the 'Platform_pd' as constructor argument, keeping the relationship as a reference (instead of a pointer), and constraining the lifetime of 'Platform_pd' objects to the lifetime of the PD. It thereby clears the way to simplify the thread creation since all PD-related information (like quota budgets) are now known at the construction time of the 'Platform_thread'. The return value of 'Platform_thread::start' has been removed because it is not evaluated by 'Cpu_thread_component'. Related to #5256 --- .../src/core/include/platform_pd.h | 63 ++++----- .../src/core/include/platform_thread.h | 76 +++++------ repos/base-fiasco/src/core/platform.cc | 6 +- repos/base-fiasco/src/core/platform_pd.cc | 116 +++------------- repos/base-fiasco/src/core/platform_thread.cc | 112 ++++++---------- repos/base-fiasco/src/core/thread_start.cc | 4 +- .../src/core/include/platform_thread.h | 13 +- repos/base-foc/src/core/platform_thread.cc | 11 +- repos/base-hw/src/core/pager.cc | 4 +- repos/base-hw/src/core/platform_pd.cc | 10 -- repos/base-hw/src/core/platform_pd.h | 2 + repos/base-hw/src/core/platform_thread.cc | 41 ++---- repos/base-hw/src/core/platform_thread.h | 24 ++-- repos/base-hw/src/core/region_map_support.cc | 2 +- repos/base-hw/src/core/thread_start.cc | 5 +- .../base-linux/src/core/include/platform_pd.h | 2 - .../src/core/include/platform_thread.h | 125 +++++++----------- repos/base-linux/src/core/platform_thread.cc | 82 ++---------- .../base-nova/src/core/include/platform_pd.h | 15 +-- .../src/core/include/platform_thread.h | 28 ++-- repos/base-nova/src/core/platform_pd.cc | 16 +-- repos/base-nova/src/core/platform_thread.cc | 63 ++++----- .../src/core/include/platform_thread.h | 32 ++--- repos/base-okl4/src/core/platform.cc | 4 +- repos/base-okl4/src/core/platform_pd.cc | 4 +- repos/base-okl4/src/core/platform_thread.cc | 41 +++--- repos/base-okl4/src/core/thread_start.cc | 4 +- .../src/core/include/platform_pd.h | 72 ++++------ .../src/core/include/platform_thread.h | 83 ++++++------ repos/base-pistachio/src/core/platform.cc | 8 +- repos/base-pistachio/src/core/platform_pd.cc | 105 ++------------- .../src/core/platform_thread.cc | 90 ++++--------- repos/base-pistachio/src/core/thread_start.cc | 4 +- .../base-sel4/src/core/include/platform_pd.h | 43 +++--- .../src/core/include/platform_thread.h | 20 +-- .../base-sel4/src/core/include/thread_sel4.h | 30 +++-- repos/base-sel4/src/core/platform_pd.cc | 51 +------ repos/base-sel4/src/core/platform_thread.cc | 97 ++++++++++---- repos/base-sel4/src/core/thread_start.cc | 12 +- .../src/include/base/internal/native_utcb.h | 4 +- repos/base/src/core/cpu_session_component.cc | 42 +++--- repos/base/src/core/cpu_thread_component.cc | 5 +- .../src/core/include/cpu_thread_component.h | 28 ++-- .../src/core/include/pd_session_component.h | 29 ++-- repos/base/src/core/pd_session_component.cc | 13 ++ 45 files changed, 628 insertions(+), 1013 deletions(-) diff --git a/repos/base-fiasco/src/core/include/platform_pd.h b/repos/base-fiasco/src/core/include/platform_pd.h index b0dd150f8d..7188824d42 100644 --- a/repos/base-fiasco/src/core/include/platform_pd.h +++ b/repos/base-fiasco/src/core/include/platform_pd.h @@ -21,7 +21,6 @@ #include /* core includes */ -#include #include /* L4/Fiasco includes */ @@ -36,6 +35,13 @@ namespace Core { class Core::Platform_pd : public Address_space { + public: + + struct Thread_id { unsigned value; }; + + enum class Alloc_thread_id_error { EXHAUSTED }; + using Alloc_thread_id_result = Attempt; + private: /* @@ -60,35 +66,11 @@ class Core::Platform_pd : public Address_space Fiasco::l4_taskid_t _l4_task_id { }; /* L4 task ID */ - /********************************************** - ** Threads of this protection domain object ** - **********************************************/ + /*************************************** + ** Threads of this protection domain ** + ***************************************/ - Platform_thread *_threads[THREAD_MAX]; - - /** - * Initialize thread allocator - */ - void _init_threads(); - - /** - * Thread iteration for one task - */ - Platform_thread *_next_thread(); - - /** - * Thread allocation - * - * Again a special case for Core thread0. - */ - int _alloc_thread(int thread_id, Platform_thread &thread); - - /** - * Thread deallocation - * - * No special case for Core thread0 here - we just never call it. - */ - void _free_thread(int thread_id); + Platform_thread *_threads[THREAD_MAX] { }; /****************** @@ -179,18 +161,25 @@ class Core::Platform_pd : public Address_space static void init(); /** - * Bind thread to protection domain - * - * \return true on success + * Allocate PD-local ID for a new 'Platform_thread' */ - bool bind_thread(Platform_thread &thread); + Alloc_thread_id_result alloc_thread_id(Platform_thread &); /** - * Unbind thread from protection domain - * - * Free the thread's slot and update thread object. + * Release PD-local thread ID at destruction of 'Platform_thread' */ - void unbind_thread(Platform_thread &thread); + void free_thread_id(Thread_id); + + /** + * Return L4 thread ID from the PD's task ID and the PD-local thread ID + */ + Fiasco::l4_threadid_t l4_thread_id(Thread_id const id) const + { + Fiasco::l4_threadid_t result = _l4_task_id; + enum { LTHREAD_MASK = (1 << 7) - 1 }; + result.id.lthread = id.value & LTHREAD_MASK; + return result; + } /** * Assign parent interface to protection domain diff --git a/repos/base-fiasco/src/core/include/platform_thread.h b/repos/base-fiasco/src/core/include/platform_thread.h index 3add833406..0d753a7fe0 100644 --- a/repos/base-fiasco/src/core/include/platform_thread.h +++ b/repos/base-fiasco/src/core/include/platform_thread.h @@ -44,85 +44,70 @@ class Core::Platform_thread : Interface Platform_thread(Platform_thread const &); Platform_thread &operator = (Platform_thread const &); - int _thread_id = THREAD_INVALID; /* plain thread number */ + using Name = String<32>; - Fiasco::l4_threadid_t _l4_thread_id; + Name const _name; /* name to be registered at the kernel debugger */ + + Platform_pd &_pd; + + using Id = Platform_pd::Alloc_thread_id_result; + + Id const _id { _pd.alloc_thread_id(*this) }; - typedef String<32> Name; - Name const _name; /* thread name that will be - registered at the kernel - debugger */ - Platform_pd *_platform_pd = nullptr; /* protection domain thread - is bound to */ Pager_object *_pager = nullptr; public: - enum { - THREAD_INVALID = -1, /* invalid thread number */ - }; - /** * Constructor */ - Platform_thread(size_t, const char *name, unsigned priority, - Affinity::Location, addr_t utcb); + Platform_thread(Platform_pd &pd, size_t, const char *name, + unsigned, Affinity::Location, addr_t) + : _name(name), _pd(pd) { } /** * Constructor used for core-internal threads */ - Platform_thread(const char *name); + Platform_thread(Platform_pd &pd, const char *name) + : _name(name), _pd(pd) { } /** * Destructor */ ~Platform_thread(); + /** + * Return false if thread IDs are exhausted + */ + bool valid() const { return _id.ok(); } + /** * Start thread * * \param ip instruction pointer to start at * \param sp stack pointer to use - * - * \retval 0 successful - * \retval -1 thread could not be started */ - int start(void *ip, void *sp); + void start(void *ip, void *sp); /** * Pause this thread */ - void pause(); + void pause() { /* not implemented */ } /** * Enable/disable single stepping */ - void single_step(bool) { } + void single_step(bool) { /* not implemented */ } /** * Resume this thread */ - void resume(); - - /** - * This thread is about to be bound - * - * \param thread_id local thread ID - * \param l4_thread_id final L4 thread ID - * \param pd platform pd, thread is bound to - */ - void bind(int thread_id, Fiasco::l4_threadid_t l4_thread_id, - Platform_pd &pd); - - /** - * Unbind this thread - */ - void unbind(); + void resume() { /* not implemented */ } /** * Override thread state with 's' */ - void state(Thread_state s); + void state(Thread_state) { /* not implemented */ } /** * Read thread state @@ -163,7 +148,7 @@ class Core::Platform_thread : Interface * Return identification of thread when faulting */ unsigned long pager_object_badge() const { - return convert_native_thread_id_to_badge(_l4_thread_id); } + return convert_native_thread_id_to_badge(native_thread_id()); } /** * Set CPU quota of the thread to 'quota' @@ -180,9 +165,16 @@ class Core::Platform_thread : Interface ** Fiasco-specific Accessors ** *******************************/ - int thread_id() const { return _thread_id; } - Fiasco::l4_threadid_t native_thread_id() const { return _l4_thread_id; } - Name name() const { return _name; } + Fiasco::l4_threadid_t native_thread_id() const + { + using namespace Fiasco; + return _id.convert( + [&] (Platform_pd::Thread_id id) { return _pd.l4_thread_id(id); }, + [&] (Platform_pd::Alloc_thread_id_error) { return L4_INVALID_ID; } + ); + } + + Name name() const { return _name; } }; #endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */ diff --git a/repos/base-fiasco/src/core/platform.cc b/repos/base-fiasco/src/core/platform.cc index cacb99151a..155b2475bd 100644 --- a/repos/base-fiasco/src/core/platform.cc +++ b/repos/base-fiasco/src/core/platform.cc @@ -142,14 +142,13 @@ Core::Platform::Sigma0 &Core::Platform::sigma0() Core::Platform::Core_pager::Core_pager(Platform_pd &core_pd) : - Platform_thread("core.pager"), + Platform_thread(core_pd, "core.pager"), Pager_object(Cpu_session_capability(), Thread_capability(), 0, Affinity::Location(), Session_label(), Cpu_session::Name(name())) { Platform_thread::pager(sigma0()); - core_pd.bind_thread(*this); cap(Capability_space::import(native_thread_id(), Rpc_obj_key())); /* pager needs to know core's pd ID */ @@ -432,10 +431,9 @@ Core::Platform::Platform() * interface that allows us to specify the lthread number. */ Platform_thread &core_thread = *new (core_mem_alloc()) - Platform_thread("core.main"); + Platform_thread(*_core_pd, "core.main"); core_thread.pager(sigma0()); - _core_pd->bind_thread(core_thread); /* we never call _core_thread.start(), so set name directly */ fiasco_register_thread_name(core_thread.native_thread_id(), diff --git a/repos/base-fiasco/src/core/platform_pd.cc b/repos/base-fiasco/src/core/platform_pd.cc index 1a2a0d2da6..bcf4aa4c78 100644 --- a/repos/base-fiasco/src/core/platform_pd.cc +++ b/repos/base-fiasco/src/core/platform_pd.cc @@ -37,7 +37,8 @@ static bool _init = false; void Platform_pd::init() { - if (_init) return; + if (_init) + return; unsigned i; Pd_alloc reserved(true, true, 0); @@ -52,10 +53,6 @@ void Platform_pd::init() } -/**************************** - ** Private object members ** - ****************************/ - void Platform_pd::_create_pd(bool syscall) { enum { TASK_ID_MASK = (1 << 11) - 1, @@ -135,96 +132,27 @@ void Platform_pd::_free_pd() } -void Platform_pd::_init_threads() +Platform_pd::Alloc_thread_id_result Platform_pd::alloc_thread_id(Platform_thread &thread) { - unsigned i; - - for (i = 0; i < THREAD_MAX; ++i) - _threads[i] = 0; -} - - -Platform_thread* Platform_pd::_next_thread() -{ - unsigned i; - - /* look for bound thread */ - for (i = 0; i < THREAD_MAX; ++i) - if (_threads[i]) break; - - /* no bound threads */ - if (i == THREAD_MAX) return 0; - - return _threads[i]; -} - - -int Platform_pd::_alloc_thread(int thread_id, Platform_thread &thread) -{ - int i = thread_id; - - /* look for free thread */ - if (thread_id == Platform_thread::THREAD_INVALID) { - for (i = 0; i < THREAD_MAX; ++i) - if (!_threads[i]) break; - - /* no free threads available */ - if (i == THREAD_MAX) return -1; - } else { - if (_threads[i]) return -2; + for (unsigned i = 0; i < THREAD_MAX; i++) { + if (_threads[i] == nullptr) { + _threads[i] = &thread; + return Thread_id { i }; + } } - - _threads[i] = &thread; - - return i; + return Alloc_thread_id_error::EXHAUSTED; } -void Platform_pd::_free_thread(int thread_id) +void Platform_pd::free_thread_id(Thread_id const id) { - if (!_threads[thread_id]) - warning("double-free of thread ", Hex(_pd_id), ".", Hex(thread_id), " detected"); + if (id.value >= THREAD_MAX) + return; - _threads[thread_id] = 0; -} + if (!_threads[id.value]) + warning("double-free of thread ", Hex(_pd_id), ".", Hex(id.value), " detected"); - -/*************************** - ** Public object members ** - ***************************/ - -bool Platform_pd::bind_thread(Platform_thread &thread) -{ - /* thread_id is THREAD_INVALID by default - only core is the special case */ - int thread_id = thread.thread_id(); - l4_threadid_t l4_thread_id; - - int t = _alloc_thread(thread_id, thread); - if (t < 0) - return false; - - thread_id = t; - - enum { LTHREAD_MASK = (1 << 7) - 1 }; - - l4_thread_id = _l4_task_id; - l4_thread_id.id.lthread = thread_id & LTHREAD_MASK; - - /* finally inform thread about binding */ - thread.bind(thread_id, l4_thread_id, *this); - - return true; -} - - -void Platform_pd::unbind_thread(Platform_thread &thread) -{ - int thread_id = thread.thread_id(); - - /* unbind thread before proceeding */ - thread.unbind(); - - _free_thread(thread_id); + _threads[id.value] = nullptr; } @@ -244,15 +172,13 @@ void Platform_pd::flush(addr_t, size_t size, Core_local_addr core_local_base) L4_FP_FLUSH_PAGE); } + Platform_pd::Platform_pd(Allocator &, char const *) { /* check correct init */ if (!_init) panic("init pd facility via Platform_pd::init() before using it!"); - /* init threads */ - _init_threads(); - int ret = _alloc_pd(PD_INVALID); if (ret < 0) { panic("pd alloc failed"); @@ -268,9 +194,6 @@ Platform_pd::Platform_pd(char const *, signed pd_id) if (!_init) panic("init pd facility via Platform_pd::init() before using it!"); - /* init threads */ - _init_threads(); - int ret = _alloc_pd(pd_id); if (ret < 0) { panic("pd alloc failed"); @@ -282,10 +205,11 @@ Platform_pd::Platform_pd(char const *, signed pd_id) Platform_pd::~Platform_pd() { - /* unbind all threads */ - while (Platform_thread *t = _next_thread()) unbind_thread(*t); + bool any_thread_exists = false; + for (Platform_thread *t : _threads) any_thread_exists |= (t != nullptr); + if (any_thread_exists) + error("attempt to destruct platform PD before threads"); _destroy_pd(); _free_pd(); } - diff --git a/repos/base-fiasco/src/core/platform_thread.cc b/repos/base-fiasco/src/core/platform_thread.cc index 83aec3d796..261b6e529b 100644 --- a/repos/base-fiasco/src/core/platform_thread.cc +++ b/repos/base-fiasco/src/core/platform_thread.cc @@ -30,10 +30,13 @@ using namespace Core; using namespace Fiasco; -int Platform_thread::start(void *ip, void *sp) +void Platform_thread::start(void *ip, void *sp) { + if (_id.failed()) + return; + l4_umword_t dummy, old_eflags; - l4_threadid_t thread = _l4_thread_id; + l4_threadid_t thread = native_thread_id(); l4_threadid_t pager = _pager ? Capability_space::ipc_cap_data(_pager->cap()).dst : L4_INVALID_ID; @@ -45,38 +48,47 @@ int Platform_thread::start(void *ip, void *sp) &old_eflags, &dummy, &dummy, 0, l4_utcb_get()); if (old_eflags == ~0UL) - warning("old eflags == ~0 on ex_regs ", + warning("start ", _name, ": old eflags == ~0 on ex_regs ", Hex(thread.id.task), ".", Hex(thread.id.lthread)); fiasco_register_thread_name(thread, _name.string()); - return 0; } -void Platform_thread::pause() +Thread_state Platform_thread::state() { - warning(__func__, " not implemented"); + Thread_state s { }; + + l4_umword_t old_eflags, ip, sp; + l4_threadid_t thread = native_thread_id(); + l4_threadid_t pager = L4_INVALID_ID; + l4_threadid_t preempter = L4_INVALID_ID; + l4_threadid_t cap_handler = L4_INVALID_ID; + + l4_inter_task_ex_regs(thread, ~0UL, ~0UL, + &preempter, &pager, &cap_handler, + &old_eflags, &ip, &sp, + L4_THREAD_EX_REGS_NO_CANCEL, l4_utcb_get()); + if (old_eflags == ~0UL) + warning("state old eflags == ~0 on ex_regs ", + Hex(thread.id.task), ".", Hex(thread.id.lthread)); + + /* fill thread state structure */ + s.cpu.ip = ip; + s.cpu.sp = sp; + s.state = Thread_state::State::VALID; + + return s; } -void Platform_thread::resume() +Platform_thread::~Platform_thread() { - warning(__func__, " not implemented"); -} + if (_id.failed()) + return; - -void Platform_thread::bind(int thread_id, l4_threadid_t l4_thread_id, Platform_pd &pd) -{ - _thread_id = thread_id; - _l4_thread_id = l4_thread_id; - _platform_pd = &pd; -} - - -void Platform_thread::unbind() -{ l4_umword_t dummy, old_eflags; - l4_threadid_t thread = _l4_thread_id; + l4_threadid_t thread = native_thread_id(); l4_threadid_t pager = thread; l4_threadid_t preempter = L4_INVALID_ID; l4_threadid_t cap_handler = L4_INVALID_ID; @@ -93,60 +105,10 @@ void Platform_thread::unbind() &old_eflags, &dummy, &dummy, 0, l4_utcb_get()); if (old_eflags == ~0UL) - warning("old eflags == ~0 on ex_regs ", + warning("unbind old eflags == ~0 on ex_regs ", Hex(thread.id.task), ".", Hex(thread.id.lthread)); - _thread_id = THREAD_INVALID; - _l4_thread_id = L4_INVALID_ID; - _platform_pd = 0; -} - - -void Platform_thread::state(Thread_state) { } - - -Thread_state Platform_thread::state() -{ - Thread_state s { }; - - l4_umword_t old_eflags, ip, sp; - l4_threadid_t thread = _l4_thread_id; - l4_threadid_t pager = L4_INVALID_ID; - l4_threadid_t preempter = L4_INVALID_ID; - l4_threadid_t cap_handler = L4_INVALID_ID; - - l4_inter_task_ex_regs(thread, ~0UL, ~0UL, - &preempter, &pager, &cap_handler, - &old_eflags, &ip, &sp, - L4_THREAD_EX_REGS_NO_CANCEL, l4_utcb_get()); - if (old_eflags == ~0UL) - warning("old eflags == ~0 on ex_regs ", - Hex(thread.id.task), ".", Hex(thread.id.lthread)); - - /* fill thread state structure */ - s.cpu.ip = ip; - s.cpu.sp = sp; - s.state = Thread_state::State::VALID; - - return s; -} - - -Platform_thread::Platform_thread(size_t, const char *name, unsigned, - Affinity::Location, addr_t) -: _l4_thread_id(L4_INVALID_ID), _name(name) { } - - -Platform_thread::Platform_thread(const char *name) -: _l4_thread_id(L4_INVALID_ID), _name(name) { } - - -Platform_thread::~Platform_thread() -{ - /* - * We inform our protection domain about thread destruction, which will end up in - * Thread::unbind() - */ - if (_platform_pd) - _platform_pd->unbind_thread(*this); + _id.with_result( + [&] (Platform_pd::Thread_id id) { _pd.free_thread_id(id); }, + [&] (Platform_pd::Alloc_thread_id_error) { }); } diff --git a/repos/base-fiasco/src/core/thread_start.cc b/repos/base-fiasco/src/core/thread_start.cc index dff6686e75..48871704ac 100644 --- a/repos/base-fiasco/src/core/thread_start.cc +++ b/repos/base-fiasco/src/core/thread_start.cc @@ -38,9 +38,7 @@ Thread::Start_result Thread::start() { /* create and start platform thread */ native_thread().pt = new (platform().core_mem_alloc()) - Platform_thread(_stack->name().string()); - - platform_specific().core_pd().bind_thread(*native_thread().pt); + Platform_thread(platform_specific().core_pd(), _stack->name().string()); native_thread().pt->pager(platform_specific().core_pager()); native_thread().l4id = native_thread().pt->native_thread_id(); diff --git a/repos/base-foc/src/core/include/platform_thread.h b/repos/base-foc/src/core/include/platform_thread.h index 5783179e74..e9580dab31 100644 --- a/repos/base-foc/src/core/include/platform_thread.h +++ b/repos/base-foc/src/core/include/platform_thread.h @@ -60,6 +60,7 @@ class Core::Platform_thread : Interface Platform_pd *_platform_pd; /* protection domain thread is bound to */ Pager_object *_pager_obj; unsigned _prio; + bool _bound_to_pd = false; Affinity::Location _location { }; @@ -74,7 +75,7 @@ class Core::Platform_thread : Interface /** * Constructor for non-core threads */ - Platform_thread(size_t, const char *name, unsigned priority, + Platform_thread(Platform_pd &, size_t, const char *name, unsigned priority, Affinity::Location, addr_t); /** @@ -93,16 +94,18 @@ class Core::Platform_thread : Interface */ ~Platform_thread(); + /** + * Return true if thread creation succeeded + */ + bool valid() const { return _bound_to_pd; } + /** * Start thread * * \param ip instruction pointer to start at * \param sp stack pointer to use - * - * \retval 0 successful - * \retval -1 thread could not be started */ - int start(void *ip, void *sp); + void start(void *ip, void *sp); /** * Pause this thread diff --git a/repos/base-foc/src/core/platform_thread.cc b/repos/base-foc/src/core/platform_thread.cc index 4530633c13..d24ace8782 100644 --- a/repos/base-foc/src/core/platform_thread.cc +++ b/repos/base-foc/src/core/platform_thread.cc @@ -38,7 +38,7 @@ Trace::Execution_time Platform_thread::execution_time() const } -int Platform_thread::start(void *ip, void *sp) +void Platform_thread::start(void *ip, void *sp) { if (!_platform_pd) { @@ -62,7 +62,7 @@ int Platform_thread::start(void *ip, void *sp) if (l4_msgtag_has_error(tag)) { warning("l4_thread_control_commit for ", Hex(_thread.local.data()->kcap()), " failed!"); - return -1; + return; } _state = RUNNING; @@ -72,10 +72,8 @@ int Platform_thread::start(void *ip, void *sp) (l4_addr_t) sp, 0); if (l4_msgtag_has_error(tag)) { warning("l4_thread_ex_regs failed!"); - return -1; + return; } - - return 0; } @@ -280,7 +278,7 @@ void Platform_thread::_finalize_construction() } -Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, +Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned prio, Affinity::Location location, addr_t) : _name(name), @@ -298,6 +296,7 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, _create_thread(); _finalize_construction(); affinity(location); + _bound_to_pd = pd.bind_thread(*this); } diff --git a/repos/base-hw/src/core/pager.cc b/repos/base-hw/src/core/pager.cc index 50b87bc003..4fcd3d651e 100644 --- a/repos/base-hw/src/core/pager.cc +++ b/repos/base-hw/src/core/pager.cc @@ -67,8 +67,8 @@ void Pager_object::unresolved_page_fault_occurred() { } void Pager_object::print(Output &out) const { Platform_thread * const pt = (Platform_thread *)badge(); - if (pt && pt->pd()) - Genode::print(out, "pager_object: pd='", pt->pd()->label(), + if (pt) + Genode::print(out, "pager_object: pd='", pt->pd().label(), "' thread='", pt->label(), "'"); } diff --git a/repos/base-hw/src/core/platform_pd.cc b/repos/base-hw/src/core/platform_pd.cc index 6c7453d67e..b96e1ee8b2 100644 --- a/repos/base-hw/src/core/platform_pd.cc +++ b/repos/base-hw/src/core/platform_pd.cc @@ -154,16 +154,6 @@ void Cap_space::upgrade_slab(Allocator &alloc) ** Platform_pd implementation ** ********************************/ -bool Platform_pd::bind_thread(Platform_thread &t) -{ - /* is this the first and therefore main thread in this PD? */ - bool main_thread = !_thread_associated; - _thread_associated = true; - t.join_pd(this, main_thread, Address_space::weak_ptr()); - return true; -} - - void Platform_pd::assign_parent(Native_capability parent) { if (!_parent.valid() && parent.valid()) diff --git a/repos/base-hw/src/core/platform_pd.h b/repos/base-hw/src/core/platform_pd.h index 003756df46..c40187a4bc 100644 --- a/repos/base-hw/src/core/platform_pd.h +++ b/repos/base-hw/src/core/platform_pd.h @@ -195,6 +195,8 @@ class Core::Platform_pd : public Hw::Address_space, private Cap_space public: + bool has_any_thread = false; + /** * Constructor used for objects other than the Core PD * diff --git a/repos/base-hw/src/core/platform_thread.cc b/repos/base-hw/src/core/platform_thread.cc index 898f0f68d0..7ae23acd04 100644 --- a/repos/base-hw/src/core/platform_thread.cc +++ b/repos/base-hw/src/core/platform_thread.cc @@ -62,7 +62,7 @@ void Platform_thread::quota(size_t const quota) Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb) : _label(label), - _pd(&_kernel_main_get_core_platform_pd()), + _pd(_kernel_main_get_core_platform_pd()), _pager(nullptr), _utcb_core_addr(&utcb), _utcb_pd_addr(&utcb), @@ -86,19 +86,20 @@ Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb) } -Platform_thread::Platform_thread(size_t const quota, +Platform_thread::Platform_thread(Platform_pd &pd, + size_t const quota, Label const &label, unsigned const virt_prio, Affinity::Location const location, addr_t const utcb) : _label(label), - _pd(nullptr), + _pd(pd), _pager(nullptr), _utcb_pd_addr((Native_utcb *)utcb), _priority(_scale_priority(virt_prio)), _quota((unsigned)quota), - _main_thread(false), + _main_thread(!pd.has_any_thread), _location(location), _kobj(_kobj.CALLED_FROM_CORE, _priority, _quota, _label.string()) { @@ -116,22 +117,9 @@ Platform_thread::Platform_thread(size_t const quota, _utcb_core_addr = (Native_utcb *)range.start; }, [&] (Region_map::Attach_error) { error("failed to attach UTCB of new thread within core"); }); -} - -void Platform_thread::join_pd(Platform_pd * pd, bool const main_thread, - Weak_ptr address_space) -{ - /* check if thread is already in another protection domain */ - if (_pd && _pd != pd) { - error("thread already in another protection domain"); - return; - } - - /* join protection domain */ - _pd = pd; - _main_thread = main_thread; - _address_space = address_space; + _address_space = pd.weak_ptr(); + pd.has_any_thread = true; } @@ -144,7 +132,7 @@ void Platform_thread::affinity(Affinity::Location const &) Affinity::Location Platform_thread::affinity() const { return _location; } -int Platform_thread::start(void * const ip, void * const sp) +void Platform_thread::start(void * const ip, void * const sp) { /* attach UTCB in case of a main thread */ if (_main_thread) { @@ -168,7 +156,8 @@ int Platform_thread::start(void * const ip, void * const sp) } return 0; }; - if (core_env().entrypoint().apply(_utcb, lambda)) return -1; + if (core_env().entrypoint().apply(_utcb, lambda)) + return; } /* initialize thread registers */ @@ -176,11 +165,6 @@ int Platform_thread::start(void * const ip, void * const sp) _kobj->regs->sp = reinterpret_cast(sp); /* start executing new thread */ - if (!_pd) { - error("no protection domain associated!"); - return -1; - } - unsigned const cpu = _location.xpos(); Native_utcb &utcb = *Thread::myself()->utcb(); @@ -189,11 +173,10 @@ int Platform_thread::start(void * const ip, void * const sp) utcb.cap_cnt(0); utcb.cap_add(Capability_space::capid(_kobj.cap())); if (_main_thread) { - utcb.cap_add(Capability_space::capid(_pd->parent())); + utcb.cap_add(Capability_space::capid(_pd.parent())); utcb.cap_add(Capability_space::capid(_utcb)); } - Kernel::start_thread(*_kobj, cpu, _pd->kernel_pd(), *_utcb_core_addr); - return 0; + Kernel::start_thread(*_kobj, cpu, _pd.kernel_pd(), *_utcb_core_addr); } diff --git a/repos/base-hw/src/core/platform_thread.h b/repos/base-hw/src/core/platform_thread.h index 6fe7c19187..0ddc28fb1d 100644 --- a/repos/base-hw/src/core/platform_thread.h +++ b/repos/base-hw/src/core/platform_thread.h @@ -56,7 +56,7 @@ class Core::Platform_thread : Noncopyable typedef String<32> Label; Label const _label; - Platform_pd * _pd; + Platform_pd &_pd; Weak_ptr _address_space { }; Pager_object * _pager; Native_utcb * _utcb_core_addr { }; /* UTCB addr in core */ @@ -115,7 +115,7 @@ class Core::Platform_thread : Noncopyable * \param virt_prio unscaled processor-scheduling priority * \param utcb core local pointer to userland stack */ - Platform_thread(size_t const quota, Label const &label, + Platform_thread(Platform_pd &, size_t const quota, Label const &label, unsigned const virt_prio, Affinity::Location, addr_t const utcb); @@ -124,6 +124,11 @@ class Core::Platform_thread : Noncopyable */ ~Platform_thread(); + /** + * Return true if thread creation succeeded + */ + bool valid() const { return true; } + /** * Return information about current exception state * @@ -145,24 +150,13 @@ class Core::Platform_thread : Noncopyable */ Kernel::Thread_fault fault_info() { return _kobj->fault(); } - /** - * Join a protection domain - * - * \param main_thread whether thread is the first in protection domain - * - * This function has no effect when called more twice for a - * given thread. - */ - void join_pd(Platform_pd *const pd, bool const main_thread, - Weak_ptr address_space); - /** * Run this thread * * \param ip initial instruction pointer * \param sp initial stack pointer */ - int start(void * const ip, void * const sp); + void start(void *ip, void *sp); void restart(); @@ -245,7 +239,7 @@ class Core::Platform_thread : Noncopyable Pager_object &pager(); - Platform_pd * pd() const { return _pd; } + Platform_pd &pd() const { return _pd; } Ram_dataspace_capability utcb() const { return _utcb; } }; diff --git a/repos/base-hw/src/core/region_map_support.cc b/repos/base-hw/src/core/region_map_support.cc index deacfa4aeb..4f7f4df79d 100644 --- a/repos/base-hw/src/core/region_map_support.cc +++ b/repos/base-hw/src/core/region_map_support.cc @@ -47,7 +47,7 @@ void Pager_entrypoint::entry() Kernel::Thread::Exception_state::EXCEPTION) { if (!po->submit_exception_signal()) warning("unresolvable exception: " - "pd='", pt->pd()->label(), "', " + "pd='", pt->pd().label(), "', " "thread='", pt->label(), "', " "ip=", Hex(pt->state().cpu.ip)); continue; diff --git a/repos/base-hw/src/core/thread_start.cc b/repos/base-hw/src/core/thread_start.cc index cf46ffe38d..9c811da98f 100644 --- a/repos/base-hw/src/core/thread_start.cc +++ b/repos/base-hw/src/core/thread_start.cc @@ -35,10 +35,7 @@ namespace Hw { extern Untyped_capability _main_thread_cap; } Thread::Start_result Thread::start() { /* start thread with stack pointer at the top of stack */ - if (native_thread().platform_thread->start((void *)&_thread_start, stack_top())) { - error("failed to start thread"); - return Start_result::DENIED; - } + native_thread().platform_thread->start((void *)&_thread_start, stack_top()); if (_thread_cap.failed()) return Start_result::DENIED; diff --git a/repos/base-linux/src/core/include/platform_pd.h b/repos/base-linux/src/core/include/platform_pd.h index fd5c522e10..cb08d07f9e 100644 --- a/repos/base-linux/src/core/include/platform_pd.h +++ b/repos/base-linux/src/core/include/platform_pd.h @@ -32,8 +32,6 @@ struct Core::Platform_pd { Platform_pd(Allocator &, char const *) { } - bool bind_thread(Platform_thread &) { return true; } - void assign_parent(Capability) { } }; diff --git a/repos/base-linux/src/core/include/platform_thread.h b/repos/base-linux/src/core/include/platform_thread.h index 685e8563ee..c9f2f7e78d 100644 --- a/repos/base-linux/src/core/include/platform_thread.h +++ b/repos/base-linux/src/core/include/platform_thread.h @@ -17,13 +17,17 @@ /* Genode includes */ #include #include +#include #include #include /* core includes */ #include -namespace Core { class Platform_thread; } +namespace Core { + class Platform_thread; + class Platform_pd; +} /* @@ -34,32 +38,17 @@ namespace Core { class Platform_thread; } * turn, we find the exception handler's 'Signal_context_capability'. */ -class Core::Platform_thread : public List::Element +class Core::Platform_thread : Noncopyable { + using Location = Affinity::Location; + using Execution_time = Trace::Execution_time; + private: - struct Registry - { - Mutex _mutex { }; - List _list { }; - - void insert(Platform_thread *thread); - void remove(Platform_thread *thread); - - /** - * Trigger exception handler for 'Platform_thread' with matching PID. - */ - void submit_exception(unsigned long pid); - }; - - /** - * Return singleton instance of 'Platform_thread::Registry' - */ - static Registry &_registry(); - unsigned long _tid = -1; unsigned long _pid = -1; - char _name[32] { }; + + String<32> const _name; /* * Dummy pager object that is solely used for storing the @@ -67,84 +56,60 @@ class Core::Platform_thread : public List::Element */ Pager_object _pager { }; + /** + * Singleton instance of platform-thread registry used to deliver + * exceptions. + */ + static Registry &_registry(); + + Registry::Element _elem { _registry(), *this }; + public: /** * Constructor */ - Platform_thread(size_t, const char *name, unsigned priority, - Affinity::Location, addr_t); - - ~Platform_thread(); + Platform_thread(Platform_pd &, size_t, auto const &name, auto...) + : _name(name) { } /** - * Pause this thread + * Return true if thread creation succeeded */ - void pause(); + bool valid() const { return true; } + + const char *name() { return _name.string(); } /** - * Enable/disable single stepping + * Notify Genode::Signal handler about sigchld */ - void single_step(bool) { } - - /** - * Resume this thread - */ - void resume(); - - /** - * Dummy implementation of platform-thread interface - */ - Pager_object &pager() { return _pager; } - void pager(Pager_object &) { } - int start(void *, void *) { return 0; } - - Thread_state state() - { - return { .state = Thread_state::State::UNAVAILABLE, .cpu = { } }; - } - - void state(Thread_state) { } - - const char *name() { return _name; } - - /** - * Set the executing CPU for this thread - * - * SMP is currently not directly supported on Genode/Linux - * (but indirectly by the Linux kernel). - */ - void affinity(Affinity::Location) { } - - /** - * Request the affinity of this thread - */ - Affinity::Location affinity() const { return Affinity::Location(); } + static void submit_exception(unsigned pid); /** * Register process ID and thread ID of thread */ void thread_id(int pid, int tid) { _pid = pid, _tid = tid; } - /** - * Notify Genode::Signal handler about sigchld + /* + * Part of the platform-thread interface that is not used on Linux */ - static void submit_exception(int pid) + + void pause() { }; + void single_step(bool) { } + void resume() { } + Pager_object &pager() { return _pager; } + void pager(Pager_object &) { } + void start(void *, void *) { } + void affinity(Location) { } + Location affinity() const { return { }; } + void quota(size_t) { } + void state(Thread_state) { } + Execution_time execution_time() const { return { 0, 0 }; } + unsigned long pager_object_badge() const { return 0; } + + Thread_state state() { - _registry().submit_exception(pid); + return { .state = Thread_state::State::UNAVAILABLE, .cpu = { } }; } - - /** - * Set CPU quota of the thread to 'quota' - */ - void quota(size_t const) { /* not supported*/ } - - /** - * Return execution time consumed by the thread - */ - Trace::Execution_time execution_time() const { return { 0, 0 }; } - - unsigned long pager_object_badge() const { return 0; } }; #endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */ diff --git a/repos/base-linux/src/core/platform_thread.cc b/repos/base-linux/src/core/platform_thread.cc index d909017eeb..6548587e35 100644 --- a/repos/base-linux/src/core/platform_thread.cc +++ b/repos/base-linux/src/core/platform_thread.cc @@ -22,80 +22,24 @@ using namespace Core; -typedef Token Tid_token; - - -/******************************* - ** Platform_thread::Registry ** - *******************************/ - -void Platform_thread::Registry::insert(Platform_thread *thread) +void Platform_thread::submit_exception(unsigned pid) { - Mutex::Guard guard(_mutex); - _list.insert(thread); -} - - -void Platform_thread::Registry::remove(Platform_thread *thread) -{ - Mutex::Guard guard(_mutex); - _list.remove(thread); -} - - -void Platform_thread::Registry::submit_exception(unsigned long pid) -{ - Mutex::Guard guard(_mutex); - - /* traverse list to find 'Platform_thread' with matching PID */ - for (Platform_thread *curr = _list.first(); curr; curr = curr->next()) { - - if (curr->_tid == pid) { - Signal_context_capability sigh = curr->_pager._sigh; - - if (sigh.valid()) - Signal_transmitter(sigh).submit(); - + bool submitted = false; + _registry().for_each([&] (Platform_thread const &thread) { + if (submitted || thread._tid != pid) return; - } - } + + Signal_context_capability sigh = thread._pager._sigh; + if (sigh.valid()) + Signal_transmitter(sigh).submit(); + + submitted = true; + }); } -Platform_thread::Registry &Platform_thread::_registry() +Registry &Platform_thread::_registry() { - static Platform_thread::Registry registry; + static Registry registry { }; return registry; } - - -/********************* - ** Platform_thread ** - *********************/ - -Platform_thread::Platform_thread(size_t, const char *name, unsigned, - Affinity::Location, addr_t) -{ - copy_cstring(_name, name, min(sizeof(_name), Genode::strlen(name) + 1)); - - _registry().insert(this); -} - - -Platform_thread::~Platform_thread() -{ - _registry().remove(this); -} - - -void Platform_thread::pause() -{ - warning(__func__, "not implemented"); -} - - -void Platform_thread::resume() -{ - warning(__func__, "not implemented"); -} - diff --git a/repos/base-nova/src/core/include/platform_pd.h b/repos/base-nova/src/core/include/platform_pd.h index 846a224770..cb4ee59cc7 100644 --- a/repos/base-nova/src/core/include/platform_pd.h +++ b/repos/base-nova/src/core/include/platform_pd.h @@ -30,7 +30,6 @@ class Core::Platform_pd : public Address_space private: Native_capability _parent { }; - int _thread_cnt; addr_t const _pd_sel; const char * _label; @@ -42,6 +41,8 @@ class Core::Platform_pd : public Address_space public: + bool has_any_threads = false; + /** * Constructors */ @@ -53,18 +54,6 @@ class Core::Platform_pd : public Address_space */ ~Platform_pd(); - /** - * Bind thread to protection domain - */ - bool bind_thread(Platform_thread &thread); - - /** - * Unbind thread from protection domain - * - * Free the thread's slot and update thread object. - */ - void unbind_thread(Platform_thread &thread); - /** * Assign parent interface to protection domain */ diff --git a/repos/base-nova/src/core/include/platform_thread.h b/repos/base-nova/src/core/include/platform_thread.h index 4a977e0dc3..2d0bb4ae41 100644 --- a/repos/base-nova/src/core/include/platform_thread.h +++ b/repos/base-nova/src/core/include/platform_thread.h @@ -39,7 +39,7 @@ class Core::Platform_thread { private: - Platform_pd *_pd; + Platform_pd &_pd; Pager_object *_pager; addr_t _id_base; addr_t _sel_exc_base; @@ -93,7 +93,7 @@ class Core::Platform_thread /** * Constructor */ - Platform_thread(size_t quota, char const *name, + Platform_thread(Platform_pd &, size_t quota, char const *name, unsigned priority, Affinity::Location affinity, addr_t utcb); @@ -103,16 +103,18 @@ class Core::Platform_thread */ ~Platform_thread(); + /** + * Return true if thread creation succeeded + */ + bool valid() const { return true; } + /** * Start thread * - * \param ip instruction pointer to start at - * \param sp stack pointer to use - * - * \retval 0 successful - * \retval -1 thread/vCPU could not be started + * \param ip instruction pointer to start at + * \param sp stack pointer to use */ - int start(void *ip, void *sp); + void start(void *ip, void *sp); /** * Pause this thread @@ -200,16 +202,6 @@ class Core::Platform_thread */ const char *pd_name() const; - /** - * Associate thread with protection domain - */ - void bind_to_pd(Platform_pd *pd, bool main_thread) - { - _pd = pd; - - if (main_thread) _features |= MAIN_THREAD; - } - /** * Set CPU quota of the thread to 'quota' */ diff --git a/repos/base-nova/src/core/platform_pd.cc b/repos/base-nova/src/core/platform_pd.cc index 70ae4d0fa2..8277126acb 100644 --- a/repos/base-nova/src/core/platform_pd.cc +++ b/repos/base-nova/src/core/platform_pd.cc @@ -21,20 +21,6 @@ using namespace Core; -bool Platform_pd::bind_thread(Platform_thread &thread) -{ - thread.bind_to_pd(this, _thread_cnt == 0); - _thread_cnt++; - return true; -} - - -void Platform_pd::unbind_thread(Platform_thread &) -{ - warning(__func__, "not implemented"); -} - - void Platform_pd::assign_parent(Native_capability parent) { if (!_parent.valid() && parent.valid()) @@ -44,7 +30,7 @@ void Platform_pd::assign_parent(Native_capability parent) Platform_pd::Platform_pd(Allocator &, char const *label, signed, bool) : - _thread_cnt(0), _pd_sel(cap_map().insert()), _label(label) + _pd_sel(cap_map().insert()), _label(label) { if (_pd_sel == Native_thread::INVALID_INDEX) { error("platform pd creation failed "); diff --git a/repos/base-nova/src/core/platform_thread.cc b/repos/base-nova/src/core/platform_thread.cc index 6a2a0f6164..65cc71fc56 100644 --- a/repos/base-nova/src/core/platform_thread.cc +++ b/repos/base-nova/src/core/platform_thread.cc @@ -98,21 +98,20 @@ void Platform_thread::prepare_migration() } -int Platform_thread::start(void *ip, void *sp) +void Platform_thread::start(void *ip, void *sp) { using namespace Nova; if (!_pager) { error("pager undefined"); - return -1; + return; } Pager_object &pager = *_pager; - if (!_pd || (main_thread() && !vcpu() && - _pd->parent_pt_sel() == Native_thread::INVALID_INDEX)) { + if (main_thread() && !vcpu() && (_pd.parent_pt_sel() == Native_thread::INVALID_INDEX)) { error("protection domain undefined"); - return -2; + return; } Utcb &utcb = *reinterpret_cast(Thread::myself()->utcb()); @@ -121,7 +120,7 @@ int Platform_thread::start(void *ip, void *sp) if (!_create_and_map_oom_portal(utcb)) { error("setup of out-of-memory notification portal - failed"); - return -8; + return; } if (!main_thread()) { @@ -130,19 +129,19 @@ int Platform_thread::start(void *ip, void *sp) if (_sel_exc_base == Native_thread::INVALID_INDEX) { error("exception base not specified"); - return -3; + return; } uint8_t res = syscall_retry(pager, [&]() { - return create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id, + return create_ec(_sel_ec(), _pd.pd_sel(), kernel_cpu_id, utcb_addr, initial_sp, _sel_exc_base, !worker()); }); if (res != Nova::NOVA_OK) { error("creation of new thread failed ", res); - return -4; + return; } if (!vcpu()) @@ -151,7 +150,7 @@ int Platform_thread::start(void *ip, void *sp) if (res != NOVA_OK) { revoke(Obj_crd(_sel_ec(), 0)); error("creation of new thread/vcpu failed ", res); - return -3; + return; } if (worker()) { @@ -162,13 +161,12 @@ int Platform_thread::start(void *ip, void *sp) pager.initial_eip((addr_t)ip); pager.initial_esp(initial_sp); pager.client_set_ec(_sel_ec()); - - return 0; + return; } if (!vcpu() && _sel_exc_base != Native_thread::INVALID_INDEX) { error("thread already started"); - return -5; + return; } addr_t pd_utcb = 0; @@ -178,7 +176,7 @@ int Platform_thread::start(void *ip, void *sp) pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size(); - addr_t remap_src[] = { _pd->parent_pt_sel() }; + addr_t remap_src[] = { _pd.parent_pt_sel() }; addr_t remap_dst[] = { PT_SEL_PARENT }; /* remap exception portals for first thread */ @@ -186,18 +184,18 @@ int Platform_thread::start(void *ip, void *sp) if (map_local(source_pd, utcb, Obj_crd(remap_src[i], 0), Obj_crd(pager.exc_pt_sel_client() + remap_dst[i], 0))) - return -6; + return; } } /* create first thread in task */ enum { THREAD_GLOBAL = true }; - uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id, + uint8_t res = create_ec(_sel_ec(), _pd.pd_sel(), kernel_cpu_id, pd_utcb, 0, _sel_exc_base, THREAD_GLOBAL); if (res != NOVA_OK) { error("create_ec returned ", res); - return -7; + return; } pager.client_set_ec(_sel_ec()); @@ -213,7 +211,7 @@ int Platform_thread::start(void *ip, void *sp) res = syscall_retry(pager, [&]() { /* let the thread run */ - return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), + return create_sc(_sel_sc(), _pd.pd_sel(), _sel_ec(), Qpd(Qpd::DEFAULT_QUANTUM, _priority)); }); } @@ -227,12 +225,10 @@ int Platform_thread::start(void *ip, void *sp) /* cap_selector free for _sel_ec is done in de-constructor */ revoke(Obj_crd(_sel_ec(), 0)); - return -8; + return; } _features |= SC_CREATED; - - return 0; } @@ -255,14 +251,14 @@ void Platform_thread::resume() return; } - if (!_pd || !_pager) { - error("protection domain undefined - resuming thread failed"); + if (!_pager) { + error("pager undefined - resuming thread failed"); return; } uint8_t res = syscall_retry(*_pager, [&]() { - return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(), + return create_sc(_sel_sc(), _pd.pd_sel(), _sel_ec(), Qpd(Qpd::DEFAULT_QUANTUM, _priority)); }); @@ -298,8 +294,8 @@ void Platform_thread::single_step(bool on) _pager->single_step(on); } -const char * Platform_thread::pd_name() const { - return _pd ? _pd->name() : "unknown"; } + +const char * Platform_thread::pd_name() const { return _pd.name(); } Trace::Execution_time Platform_thread::execution_time() const @@ -326,7 +322,7 @@ Trace::Execution_time Platform_thread::execution_time() const void Platform_thread::pager(Pager_object &pager) { _pager = &pager; - _pager->assign_pd(_pd->pd_sel()); + _pager->assign_pd(_pd.pd_sel()); } @@ -347,16 +343,21 @@ void Platform_thread::thread_type(Cpu_session::Native_cpu::Thread_type thread_ty } -Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, - Affinity::Location affinity, addr_t) +Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, + unsigned prio, Affinity::Location affinity, addr_t) : - _pd(0), _pager(0), _id_base(cap_map().insert(2)), + _pd(pd), _pager(0), _id_base(cap_map().insert(2)), _sel_exc_base(Native_thread::INVALID_INDEX), _location(platform_specific().sanitize(affinity)), _features(0), _priority((uint8_t)(scale_priority(prio, name))), _name(name) -{ } +{ + if (!pd.has_any_threads) + _features |= MAIN_THREAD; + + pd.has_any_threads = true; +} Platform_thread::~Platform_thread() diff --git a/repos/base-okl4/src/core/include/platform_thread.h b/repos/base-okl4/src/core/include/platform_thread.h index e59436ca29..b0a47f8982 100644 --- a/repos/base-okl4/src/core/include/platform_thread.h +++ b/repos/base-okl4/src/core/include/platform_thread.h @@ -47,11 +47,12 @@ class Core::Platform_thread char _name[32]; /* thread name that will be registered at the kernel debugger */ - Platform_pd *_platform_pd; /* protection domain thread - is bound to */ + Platform_pd &_pd; unsigned _priority; /* thread priority */ Pager_object *_pager; + bool _bound_to_pd = false; + public: enum { THREAD_INVALID = -1 }; /* invalid thread number */ @@ -60,7 +61,7 @@ class Core::Platform_thread /** * Constructor */ - Platform_thread(size_t, const char *name, + Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned priority, Affinity::Location, addr_t utcb); @@ -68,25 +69,26 @@ class Core::Platform_thread /** * Constructor used for core-internal threads */ - Platform_thread(char const *name) - : Platform_thread(0, name, 0, Affinity::Location(), 0) { } + Platform_thread(Platform_pd &pd, char const *name) + : Platform_thread(pd, 0, name, 0, Affinity::Location(), 0) { } /** * Destructor */ ~Platform_thread(); + /** + * Return true if thread creation succeeded + */ + bool valid() const { return _bound_to_pd; } + /** * Start thread * - * \param ip instruction pointer to start at - * \param sp stack pointer to use - * \param cpu_no target cpu - * - * \retval 0 successful - * \retval -1 thread could not be started + * \param ip instruction pointer to start at + * \param sp stack pointer to use */ - int start(void *ip, void *sp, unsigned int cpu_no = 0); + void start(void *ip, void *sp); /** * Pause this thread @@ -108,10 +110,8 @@ class Core::Platform_thread * * \param thread_id local thread ID * \param l4_thread_id final L4 thread ID - * \param pd platform pd, thread is bound to */ - void bind(int thread_id, Okl4::L4_ThreadId_t l4_thread_id, - Platform_pd &pd); + void bind(int thread_id, Okl4::L4_ThreadId_t l4_thread_id); /** * Unbind this thread @@ -148,7 +148,7 @@ class Core::Platform_thread /** * Get the 'Platform_pd' object this thread belongs to */ - Platform_pd* pd() { return _platform_pd; } + Platform_pd &pd() { return _pd; } /** * Return identification of thread when faulting diff --git a/repos/base-okl4/src/core/platform.cc b/repos/base-okl4/src/core/platform.cc index 19f2a9ab40..5c109b7fff 100644 --- a/repos/base-okl4/src/core/platform.cc +++ b/repos/base-okl4/src/core/platform.cc @@ -178,12 +178,10 @@ Core::Platform::Platform() * not destroy this task, it should be no problem. */ Platform_thread &core_thread = - *new (&_thread_slab) Platform_thread("core.main"); + *new (&_thread_slab) Platform_thread(*_core_pd, "core.main"); core_thread.set_l4_thread_id(Okl4::L4_rootserver); - _core_pd->bind_thread(core_thread); - /* core log as ROM module */ { unsigned const pages = 1; diff --git a/repos/base-okl4/src/core/platform_pd.cc b/repos/base-okl4/src/core/platform_pd.cc index 2a65959ff2..97072de94f 100644 --- a/repos/base-okl4/src/core/platform_pd.cc +++ b/repos/base-okl4/src/core/platform_pd.cc @@ -179,7 +179,7 @@ bool Platform_pd::bind_thread(Platform_thread &thread) l4_thread_id = make_l4_id(_pd_id, thread_id); /* finally inform thread about binding */ - thread.bind(thread_id, l4_thread_id, *this); + thread.bind(thread_id, l4_thread_id); return true; } @@ -200,7 +200,7 @@ void Platform_pd::space_pager(Platform_thread &thread) using namespace Okl4; L4_Word_t control = L4_SpaceCtrl_space_pager; - L4_SpaceId_t pager_space = L4_SpaceId(thread.pd()->pd_id()); + L4_SpaceId_t pager_space = L4_SpaceId(thread.pd().pd_id()); L4_ClistId_t cap_list = L4_rootclist; L4_Word_t utcb_area_size = L4_GetUtcbSize()*(1 << Thread_id_bits::THREAD); L4_Word_t utcb_location = platform_specific().utcb_base() diff --git a/repos/base-okl4/src/core/platform_thread.cc b/repos/base-okl4/src/core/platform_thread.cc index a266c79c2d..c95ac8b6df 100644 --- a/repos/base-okl4/src/core/platform_thread.cc +++ b/repos/base-okl4/src/core/platform_thread.cc @@ -29,17 +29,16 @@ using namespace Core; using namespace Okl4; -int Platform_thread::start(void *ip, void *sp, unsigned) +void Platform_thread::start(void *ip, void *sp) { - if (!_platform_pd) { + if (!_bound_to_pd) { warning("thread ", _thread_id, " is not bound to a PD"); - return -1; + return; } /* activate local thread by assigning a UTCB address and thread ID */ - int space_no = _platform_pd->pd_id(); - L4_ThreadId_t new_thread_id = _platform_pd->make_l4_id(space_no, - _thread_id); + int space_no = _pd.pd_id(); + L4_ThreadId_t new_thread_id = _pd.make_l4_id(space_no, _thread_id); L4_SpaceId_t space_id = L4_SpaceId(space_no); L4_ThreadId_t scheduler = L4_rootserver; @@ -51,7 +50,7 @@ int Platform_thread::start(void *ip, void *sp, unsigned) L4_Word_t resources = 0; L4_Word_t utcb_size_per_task = L4_GetUtcbSize()*(1 << Thread_id_bits::THREAD); L4_Word_t utcb_location = platform_specific().utcb_base() - + _platform_pd->pd_id()*utcb_size_per_task + + _pd.pd_id()*utcb_size_per_task + _thread_id*L4_GetUtcbSize(); /* * On some ARM architectures, UTCBs are allocated by the kernel. @@ -68,8 +67,8 @@ int Platform_thread::start(void *ip, void *sp, unsigned) * * Note: This is used by OKLinux only */ - if(_platform_pd && _platform_pd->space_pager()) { - pager = _platform_pd->space_pager()->_l4_thread_id; + if(_pd.space_pager()) { + pager = _pd.space_pager()->_l4_thread_id; exception_handler = pager; } @@ -79,7 +78,7 @@ int Platform_thread::start(void *ip, void *sp, unsigned) resources, (void *)utcb_location); if (ret != 1) { error("L4_ThreadControl returned ", ret, ", error=", ret, L4_ErrorCode()); - return -1; + return; } /* make the symbolic thread name known to the kernel debugger */ @@ -102,7 +101,6 @@ int Platform_thread::start(void *ip, void *sp, unsigned) warning("could not set thread prioritry to default"); set_l4_thread_id(new_thread_id); - return 0; } @@ -118,12 +116,10 @@ void Platform_thread::resume() } -void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id, - Platform_pd &pd) +void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id) { _thread_id = thread_id; _l4_thread_id = l4_thread_id; - _platform_pd = &pd; } @@ -134,10 +130,6 @@ void Platform_thread::unbind() if (res != 1) error("deleting thread ", Hex(_l4_thread_id.raw), " failed"); - - _thread_id = THREAD_INVALID; - _l4_thread_id = L4_nilthread; - _platform_pd = nullptr; } @@ -147,13 +139,14 @@ unsigned long Platform_thread::pager_object_badge() const } -Platform_thread::Platform_thread(size_t, const char *name, unsigned prio, - Affinity::Location, addr_t) +Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, + unsigned prio, Affinity::Location, addr_t) : - _l4_thread_id(L4_nilthread), _platform_pd(0), - _priority(prio), _pager(0) + _l4_thread_id(L4_nilthread), _pd(pd), _priority(prio), _pager(0) { copy_cstring(_name, name, sizeof(_name)); + + _bound_to_pd = pd.bind_thread(*this); } @@ -163,6 +156,6 @@ Platform_thread::~Platform_thread() * We inform our protection domain about thread destruction, which will end up in * Thread::unbind() */ - if (_platform_pd) - _platform_pd->unbind_thread(*this); + if (_bound_to_pd) + _pd.unbind_thread(*this); } diff --git a/repos/base-okl4/src/core/thread_start.cc b/repos/base-okl4/src/core/thread_start.cc index 21d7894231..c37fc08f3b 100644 --- a/repos/base-okl4/src/core/thread_start.cc +++ b/repos/base-okl4/src/core/thread_start.cc @@ -38,9 +38,7 @@ Thread::Start_result Thread::start() { /* create and start platform thread */ native_thread().pt = new (Core::platform_specific().thread_slab()) - Core::Platform_thread(_stack->name().string()); - - Core::platform_specific().core_pd().bind_thread(*native_thread().pt); + Core::Platform_thread(Core::platform_specific().core_pd(), _stack->name().string()); native_thread().pt->start((void *)_thread_start, stack_top()); diff --git a/repos/base-pistachio/src/core/include/platform_pd.h b/repos/base-pistachio/src/core/include/platform_pd.h index 9a0df523d3..2f71087418 100644 --- a/repos/base-pistachio/src/core/include/platform_pd.h +++ b/repos/base-pistachio/src/core/include/platform_pd.h @@ -21,7 +21,6 @@ #include /* core includes */ -#include #include namespace Core { @@ -33,6 +32,13 @@ namespace Core { class Core::Platform_pd : public Address_space { + public: + + struct Thread_id { unsigned value; }; + + enum class Alloc_thread_id_error { EXHAUSTED }; + using Alloc_thread_id_result = Attempt; + private: /* @@ -67,9 +73,9 @@ class Core::Platform_pd : public Address_space /** * Manually construct L4 thread ID from its components */ - Pistachio::L4_ThreadId_t make_l4_id(unsigned pd_no, - unsigned thread_no, - unsigned version) + static Pistachio::L4_ThreadId_t make_l4_id(unsigned pd_no, + unsigned thread_no, + unsigned version) { /* * We have to make sure that the 6 lower version bits are @@ -87,31 +93,7 @@ class Core::Platform_pd : public Address_space ** Threads of this protection domain object ** **********************************************/ - Platform_thread *_threads[THREAD_MAX]; - - /** - * Initialize thread allocator - */ - void _init_threads(); - - /** - * Thread iteration for one PD - */ - Platform_thread *_next_thread(); - - /** - * Thread allocation - * - * Again a special case for Core thread0. - */ - int _alloc_thread(int thread_id, Platform_thread &thread); - - /** - * Thread deallocation - * - * No special case for Core thread0 here - we just never call it. - */ - void _free_thread(int thread_id); + Platform_thread *_threads[THREAD_MAX] { }; /****************** @@ -210,25 +192,29 @@ class Core::Platform_pd : public Address_space */ void upgrade_ram_quota(size_t) { } + /** + * Allocate PD-local ID for a new 'Platform_thread' + */ + Alloc_thread_id_result alloc_thread_id(Platform_thread &); + + /** + * Release PD-local thread ID at destruction of 'Platform_thread' + */ + void free_thread_id(Thread_id); + + /** + * Return L4 thread ID from the PD's task ID and the PD-local thread ID + */ + Pistachio::L4_ThreadId_t l4_thread_id(Thread_id const id) const + { + return make_l4_id(_pd_id, id.value, _version); + } + static Pistachio::L4_Word_t _core_utcb_ptr; static void touch_utcb_space(); - /** - * Bind thread to protection domain - * - * This function allocates the physical L4 thread ID. - */ - bool bind_thread(Platform_thread &thread); - int bind_initial_thread(Platform_thread &thread); - /** - * Unbind thread from protection domain - * - * Free the thread's slot and update thread object. - */ - void unbind_thread(Platform_thread &thread); - /** * Assign parent interface to protection domain */ diff --git a/repos/base-pistachio/src/core/include/platform_thread.h b/repos/base-pistachio/src/core/include/platform_thread.h index ced65431bb..f16aa137b0 100644 --- a/repos/base-pistachio/src/core/include/platform_thread.h +++ b/repos/base-pistachio/src/core/include/platform_thread.h @@ -56,86 +56,92 @@ class Core::Platform_thread : Interface Platform_thread(Platform_thread const &); Platform_thread &operator = (Platform_thread const &); - typedef String<32> Name; + using Name = String<32>; - int _thread_id = THREAD_INVALID; - L4_ThreadId_t _l4_thread_id = L4_nilthread; Name const _name; /* thread name at kernel debugger */ - Platform_pd *_platform_pd = nullptr; - unsigned _priority = 0; + Platform_pd &_pd; + unsigned const _priority = 0; Pager_object *_pager = nullptr; - Affinity::Location _location; + Affinity::Location _location { }; + + using Id = Platform_pd::Alloc_thread_id_result; + + Id const _id { _pd.alloc_thread_id(*this) }; + + Pistachio::L4_ThreadId_t _l4_id_from_pd_thread_id() const + { + using namespace Pistachio; + return _id.convert( + [&] (Platform_pd::Thread_id id) { return _pd.l4_thread_id(id); }, + [&] (Platform_pd::Alloc_thread_id_error) { return L4_nilthread; } + ); + } + + Pistachio::L4_ThreadId_t const _l4_id = _l4_id_from_pd_thread_id(); public: - enum { THREAD_INVALID = -1 }; enum { DEFAULT_PRIORITY = 128 }; /** * Constructor */ - Platform_thread(size_t, char const *name, unsigned priority, + Platform_thread(Platform_pd &pd, size_t, char const *name, unsigned priority, Affinity::Location location, addr_t) : - _name(name), _priority(priority), _location(location) + _name(name), _pd(pd), _priority(priority), _location(location) + { } + + /** + * Constructor used for initial roottask thread "core.main" + */ + Platform_thread(Platform_pd &pd, Pistachio::L4_ThreadId_t l4_id) + : + _name("core.main"), _pd(pd), _l4_id(l4_id) { } /** * Constructor used for core-internal threads */ - Platform_thread(char const *name) - : _name(name), _location(Affinity::Location()) { } + Platform_thread(Platform_pd &pd, char const *name) : _name(name), _pd(pd) { } /** * Destructor */ ~Platform_thread(); + /** + * Return true if thread creation suceeded + */ + bool valid() const { return _id.ok(); } + /** * Start thread * * \param ip instruction pointer to start at * \param sp stack pointer to use - * - * \retval 0 successful - * \retval -1 thread could not be started */ - int start(void *ip, void *sp); + void start(void *ip, void *sp); /** * Pause this thread */ - void pause(); + void pause() { /* not implemented */ } /** * Enable/disable single stepping */ - void single_step(bool) { } + void single_step(bool) { /* not implemented */ } /** * Resume this thread */ - void resume(); - - /** - * This thread is about to be bound - * - * \param thread_id local thread ID - * \param l4_thread_id final L4 thread ID - * \param pd platform pd, thread is bound to - */ - void bind(int thread_id, Pistachio::L4_ThreadId_t l4_thread_id, - Platform_pd &pd); - - /** - * Unbind this thread - */ - void unbind(); + void resume() { /* not implemented */ } /** * Override thread state with 's' */ - void state(Thread_state s); + void state(Thread_state) { /* not implemented */ } /** * Read thread state @@ -165,7 +171,7 @@ class Core::Platform_thread : Interface */ unsigned long pager_object_badge() const { - return convert_native_thread_id_to_badge(_l4_thread_id); + return convert_native_thread_id_to_badge(native_thread_id()); } /** @@ -193,12 +199,9 @@ class Core::Platform_thread : Interface ** Pistachio-specific Accessors ** **********************************/ - int thread_id() const { return _thread_id; } - Pistachio::L4_ThreadId_t native_thread_id() const { return _l4_thread_id; } - Name name() const { return _name; } + Pistachio::L4_ThreadId_t native_thread_id() const { return _l4_id; } - /* use only for core... */ - void set_l4_thread_id(Pistachio::L4_ThreadId_t id) { _l4_thread_id = id; } + Name name() const { return _name; } }; #endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */ diff --git a/repos/base-pistachio/src/core/platform.cc b/repos/base-pistachio/src/core/platform.cc index 2786b910ac..7826d8dc8f 100644 --- a/repos/base-pistachio/src/core/platform.cc +++ b/repos/base-pistachio/src/core/platform.cc @@ -214,14 +214,13 @@ Core::Platform::Sigma0 &Core::Platform::sigma0() Core::Platform::Core_pager::Core_pager(Platform_pd &core_pd) : - Platform_thread("core.pager"), + Platform_thread(core_pd, "core.pager"), Pager_object(Cpu_session_capability(), Thread_capability(), 0, Affinity::Location(), Session_label(), Cpu_session::Name(name())) { Platform_thread::pager(sigma0()); - core_pd.bind_thread(*this); cap(Capability_space::import(native_thread_id(), Rpc_obj_key())); /* stack begins at the top end of the '_core_pager_stack' array */ @@ -594,13 +593,10 @@ Core::Platform::Platform() * thread_id of first task. But since we do not destroy this * task, it should be no problem. */ - static Platform_thread core_thread("core.main"); + static Platform_thread core_thread(core_pd(), Pistachio::L4_MyGlobalId()); - core_thread.set_l4_thread_id(Pistachio::L4_MyGlobalId()); core_thread.pager(sigma0()); - core_pd().bind_thread(core_thread); - auto export_page_as_rom_module = [&] (auto rom_name, auto content_fn) { size_t const size = 1 << get_page_size_log2(); diff --git a/repos/base-pistachio/src/core/platform_pd.cc b/repos/base-pistachio/src/core/platform_pd.cc index 4c628c49c2..31d8105df5 100644 --- a/repos/base-pistachio/src/core/platform_pd.cc +++ b/repos/base-pistachio/src/core/platform_pd.cc @@ -14,7 +14,7 @@ /* Genode includes */ #include -#include +#include /* base-internal includes */ #include @@ -116,96 +116,27 @@ void Platform_pd::_free_pd() } -void Platform_pd::_init_threads() +Platform_pd::Alloc_thread_id_result Platform_pd::alloc_thread_id(Platform_thread &thread) { - unsigned i; - - for (i = 0; i < THREAD_MAX; ++i) - _threads[i] = 0; -} - - -Platform_thread* Platform_pd::_next_thread() -{ - unsigned i; - - /* look for bound thread */ - for (i = 0; i < THREAD_MAX; ++i) - if (_threads[i]) break; - - /* no bound threads */ - if (i == THREAD_MAX) return 0; - - return _threads[i]; -} - - -int Platform_pd::_alloc_thread(int thread_id, Platform_thread &thread) -{ - int i = thread_id; - - /* look for free thread */ - if (thread_id == Platform_thread::THREAD_INVALID) { - - /* start from 1 here, because thread 0 is our placeholder thread */ - for (i = 1; i < THREAD_MAX; ++i) - if (!_threads[i]) break; - - /* no free threads available */ - if (i == THREAD_MAX) return -1; - } else { - if (_threads[i]) return -2; + for (unsigned i = 0; i < THREAD_MAX; i++) { + if (_threads[i] == nullptr) { + _threads[i] = &thread; + return Thread_id { i }; + } } - - _threads[i] = &thread; - - return i; + return Alloc_thread_id_error::EXHAUSTED; } -void Platform_pd::_free_thread(int thread_id) +void Platform_pd::free_thread_id(Thread_id const id) { - if (!_threads[thread_id]) - warning("double-free of thread ", Hex(_pd_id), ".", Hex(thread_id), " detected"); + if (id.value >= THREAD_MAX) + return; - _threads[thread_id] = 0; -} + if (!_threads[id.value]) + warning("double-free of thread ", Hex(_pd_id), ".", Hex(id.value), " detected"); - -/*************************** - ** Public object members ** - ***************************/ - -bool Platform_pd::bind_thread(Platform_thread &thread) -{ - using namespace Pistachio; - - /* thread_id is THREAD_INVALID by default - only core is the special case */ - int thread_id = thread.thread_id(); - L4_ThreadId_t l4_thread_id; - - int t = _alloc_thread(thread_id, thread); - if (t < 0) - return false; - - thread_id = t; - l4_thread_id = make_l4_id(_pd_id, thread_id, _version); - - /* finally inform thread about binding */ - thread.bind(thread_id, l4_thread_id, *this); - - return true; -} - - -void Platform_pd::unbind_thread(Platform_thread &thread) -{ - int thread_id = thread.thread_id(); - - /* unbind thread before proceeding */ - thread.unbind(); - - _free_thread(thread_id); + _threads[id.value] = nullptr; } @@ -302,8 +233,6 @@ Platform_pd::Platform_pd(bool) : _l4_task_id(L4_MyGlobalId()) */ Pd_alloc free(false, true, 2); - _init_threads(); - /* init remainder */ for (unsigned i = 0 ; i < PD_MAX; ++i) _pds()[i] = free; @@ -322,8 +251,6 @@ Platform_pd::Platform_pd(Allocator &, char const *, signed pd_id, bool create) if (!create) panic("create must be true."); - _init_threads(); - int const id = _alloc_pd(pd_id); if (id < 0) { error("pd alloc failed"); @@ -338,10 +265,6 @@ Platform_pd::Platform_pd(Allocator &, char const *, signed pd_id, bool create) Platform_pd::~Platform_pd() { - /* unbind all threads */ - while (Platform_thread *t = _next_thread()) - unbind_thread(*t); - _destroy_pd(); _free_pd(); } diff --git a/repos/base-pistachio/src/core/platform_thread.cc b/repos/base-pistachio/src/core/platform_thread.cc index 215da8bb63..e006b80345 100644 --- a/repos/base-pistachio/src/core/platform_thread.cc +++ b/repos/base-pistachio/src/core/platform_thread.cc @@ -34,8 +34,8 @@ void Platform_thread::affinity(Affinity::Location location) return; } - if (_l4_thread_id != L4_nilthread) { - if (L4_Set_ProcessorNo(_l4_thread_id, cpu_no) == 0) + if (native_thread_id() != L4_nilthread) { + if (L4_Set_ProcessorNo(native_thread_id(), cpu_no) == 0) error("could not set processor number"); else _location = location; @@ -49,9 +49,12 @@ Affinity::Location Platform_thread::affinity() const } -int Platform_thread::start(void *ip, void *sp) +void Platform_thread::start(void *ip, void *sp) { - L4_ThreadId_t thread = _l4_thread_id; + if (_id.failed()) + return; + + L4_ThreadId_t thread = native_thread_id(); L4_ThreadId_t pager = _pager ? Capability_space::ipc_cap_data(_pager->cap()).dst : L4_nilthread; @@ -59,29 +62,26 @@ int Platform_thread::start(void *ip, void *sp) /* XXX should always be the root task */ L4_ThreadId_t preempter = L4_Myself(); - if (_thread_id == THREAD_INVALID) { - error("attempt to start a thread with invalid ID"); - return -1; - } + L4_Word_t const utcb_location = _id.convert( + [&] (Platform_pd::Thread_id id) { return _pd._utcb_location(id.value); }, + [&] (Platform_pd::Alloc_thread_id_error) { return 0UL; }); - L4_Word_t utcb_location = _platform_pd->_utcb_location(_thread_id); - - int ret = L4_ThreadControl(thread, _platform_pd->_l4_task_id, + int ret = L4_ThreadControl(thread, _pd._l4_task_id, preempter, L4_Myself(), (void *)utcb_location); if (ret != 1) { error(__func__, ": L4_ThreadControl returned ", Hex(L4_ErrorCode())); - return -2; + return; } /* set real pager */ - ret = L4_ThreadControl(thread, _platform_pd->_l4_task_id, + ret = L4_ThreadControl(thread, _pd._l4_task_id, L4_nilthread, pager, (void *)-1); if (ret != 1) { error(__func__, ": L4_ThreadControl returned ", Hex(L4_ErrorCode())); error("setting pager failed"); - return -3; + return; } /* get the thread running on the right cpu */ @@ -103,51 +103,11 @@ int Platform_thread::start(void *ip, void *sp) if (L4_IpcFailed(tag)) { error("starting thread failed. (IPC error)"); - return -4; + return; } - - return 0; } -void Platform_thread::pause() -{ - warning(__func__, " not implemented"); -} - - -void Platform_thread::resume() -{ - warning(__func__, " not implemented"); -} - - -void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id, - Platform_pd &pd) -{ - _thread_id = thread_id; - _l4_thread_id = l4_thread_id; - _platform_pd = &pd; -} - - -void Platform_thread::unbind() -{ - L4_Word_t res = L4_ThreadControl(_l4_thread_id, L4_nilthread, - L4_nilthread, L4_nilthread, (void *)-1); - - if (res != 1) - error("deleting thread ", Formatted_tid(_l4_thread_id), " failed"); - - _thread_id = THREAD_INVALID; - _l4_thread_id = L4_nilthread; - _platform_pd = 0; -} - - -void Platform_thread::state(Thread_state) { } - - Thread_state Platform_thread::state() { Thread_state s { }; @@ -160,7 +120,7 @@ Thread_state Platform_thread::state() DELIVER = 1 << 9, }; - L4_ExchangeRegisters(_l4_thread_id, + L4_ExchangeRegisters(native_thread_id(), DELIVER, 0, 0, 0, 0, L4_nilthread, &dummy, &sp, &ip, &dummy, &dummy, @@ -174,10 +134,16 @@ Thread_state Platform_thread::state() Platform_thread::~Platform_thread() { - /* - * We inform our protection domain about thread destruction, which will end up in - * Thread::unbind() - */ - if (_platform_pd) - _platform_pd->unbind_thread(*this); + _id.with_result( + [&] (Platform_pd::Thread_id id) { + + L4_Word_t res = L4_ThreadControl(native_thread_id(), L4_nilthread, + L4_nilthread, L4_nilthread, (void *)-1); + if (res != 1) + error("deleting thread ", Formatted_tid(native_thread_id()), " failed"); + + _pd.free_thread_id(id); + }, + [&] (Platform_pd::Alloc_thread_id_error) { } + ); } diff --git a/repos/base-pistachio/src/core/thread_start.cc b/repos/base-pistachio/src/core/thread_start.cc index 41e66819cb..d31662b446 100644 --- a/repos/base-pistachio/src/core/thread_start.cc +++ b/repos/base-pistachio/src/core/thread_start.cc @@ -39,9 +39,7 @@ Thread::Start_result Thread::start() { /* create and start platform thread */ native_thread().pt = new (platform().core_mem_alloc()) - Platform_thread(_stack->name().string()); - - platform_specific().core_pd().bind_thread(*native_thread().pt); + Platform_thread(platform_specific().core_pd(), _stack->name().string()); native_thread().pt->pager(platform_specific().core_pager()); native_thread().l4id = native_thread().pt->native_thread_id(); diff --git a/repos/base-sel4/src/core/include/platform_pd.h b/repos/base-sel4/src/core/include/platform_pd.h index 87332c3d00..338652b257 100644 --- a/repos/base-sel4/src/core/include/platform_pd.h +++ b/repos/base-sel4/src/core/include/platform_pd.h @@ -30,6 +30,16 @@ namespace Core { class Platform_pd; } class Core::Platform_pd : public Address_space { + public: + + /* + * Allocator for core-managed selectors within the PD's CSpace + */ + struct Sel_alloc : Bit_allocator<1 << NUM_CORE_MANAGED_SEL_LOG2> + { + Sel_alloc() { _reserve(0, INITIAL_SEL_END); } + }; + private: unsigned const _id; /* used as index in top-level CNode */ @@ -47,22 +57,9 @@ class Core::Platform_pd : public Address_space Native_capability _parent { }; - /* - * Allocator for core-managed selectors within the PD's CSpace - */ - typedef Bit_allocator<1 << NUM_CORE_MANAGED_SEL_LOG2> Sel_bit_alloc; - - struct Sel_alloc : Sel_bit_alloc - { - Sel_alloc() { _reserve(0, INITIAL_SEL_END); } - }; - Sel_alloc _sel_alloc { }; Mutex _sel_alloc_mutex { }; - Cap_sel alloc_sel(); - void free_sel(Cap_sel sel); - addr_t _init_page_directory() const; void _deinit_page_directory(addr_t) const; @@ -79,16 +76,24 @@ class Core::Platform_pd : public Address_space ~Platform_pd(); /** - * Bind thread to protection domain + * Allocate capability selector */ - bool bind_thread(Platform_thread &); + Cap_sel alloc_sel(); /** - * Unbind thread from protection domain - * - * Free the thread's slot and update thread object. + * Release capability selector */ - void unbind_thread(Platform_thread &); + void free_sel(Cap_sel); + + /** + * Map physical IPC buffer to virtual UTCB address + */ + void map_ipc_buffer(Ipc_buffer_phys, Utcb_virt); + + /** + * Unmap IPC buffer from PD, at 'Platform_thread' destruction time + */ + void unmap_ipc_buffer(Utcb_virt); /** * Assign parent interface to protection domain diff --git a/repos/base-sel4/src/core/include/platform_thread.h b/repos/base-sel4/src/core/include/platform_thread.h index a84ae381ff..447ac953a2 100644 --- a/repos/base-sel4/src/core/include/platform_thread.h +++ b/repos/base-sel4/src/core/include/platform_thread.h @@ -53,7 +53,7 @@ class Core::Platform_thread : public List::Element * The value for the PD's main thread is INITIAL_IPC_BUFFER_VIRT. * For all other threads, the value is somewhere within the stack area. */ - addr_t const _utcb; + Utcb_virt const _utcb; Thread_info _info { }; @@ -72,21 +72,23 @@ class Core::Platform_thread : public List::Element friend class Platform_pd; - Platform_pd *_pd = nullptr; + Platform_pd &_pd; enum { INITIAL_IPC_BUFFER_VIRT = 0x1000 }; Affinity::Location _location; uint16_t _priority; - bool main_thread() const { return _utcb == INITIAL_IPC_BUFFER_VIRT; } + bool _bound_to_pd = false; + + bool main_thread() const { return _utcb.addr == INITIAL_IPC_BUFFER_VIRT; } public: /** * Constructor */ - Platform_thread(size_t, const char *name, unsigned priority, + Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned priority, Affinity::Location, addr_t utcb); /** @@ -94,17 +96,19 @@ class Core::Platform_thread : public List::Element */ ~Platform_thread(); + /** + * Return true if thread creation succeeded + */ + bool valid() const { return _bound_to_pd; } + /** * Start thread * * \param ip instruction pointer to start at * \param sp stack pointer to use * \param cpu_no target cpu - * - * \retval 0 successful - * \retval -1 thread could not be started */ - int start(void *ip, void *sp, unsigned int cpu_no = 0); + void start(void *ip, void *sp, unsigned int cpu_no = 0); /** * Pause this thread diff --git a/repos/base-sel4/src/core/include/thread_sel4.h b/repos/base-sel4/src/core/include/thread_sel4.h index 765c3213d7..1eb9bd8053 100644 --- a/repos/base-sel4/src/core/include/thread_sel4.h +++ b/repos/base-sel4/src/core/include/thread_sel4.h @@ -19,6 +19,7 @@ /* base-internal includes */ #include +#include /* core includes */ #include @@ -36,17 +37,22 @@ namespace Core { void start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, unsigned cpu, addr_t tls_ipcbuffer); void affinity_sel4_thread(Cap_sel const &tcb_sel, unsigned cpu); + + struct Ipc_buffer_phys { addr_t addr; }; + + using Utcb_virt = Native_utcb::Virt; } struct Genode::Thread_info { - Cap_sel tcb_sel { 0 }; - Cap_sel ep_sel { 0 }; + Cap_sel tcb_sel { 0 }; + Cap_sel ep_sel { 0 }; Cap_sel lock_sel { 0 }; Cap_sel vcpu_sel { 0 }; - addr_t ipc_buffer_phys { 0 }; + Core::Ipc_buffer_phys ipc_buffer_phys { 0 }; + addr_t vcpu_state_phys { 0 }; inline void write_thread_info_to_ipc_buffer(Cap_sel pd_ep_sel); @@ -55,7 +61,7 @@ struct Genode::Thread_info inline void init_tcb(Core::Platform &, Range_allocator &, unsigned const prio, unsigned const cpu); - inline void init(addr_t const utcb_virt_addr, unsigned const prio); + inline void init(Core::Utcb_virt const utcb_virt, unsigned const prio); inline void destruct(); bool init_vcpu(Core::Platform &, Cap_sel ept); @@ -84,7 +90,7 @@ void Genode::Thread_info::init_tcb(Core::Platform &platform, } -void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio) +void Genode::Thread_info::init(Core::Utcb_virt const utcb_virt, unsigned const prio) { using namespace Core; @@ -92,8 +98,8 @@ void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio) Range_allocator &phys_alloc = platform.ram_alloc(); /* create IPC buffer of one page */ - ipc_buffer_phys = Untyped_memory::alloc_page(phys_alloc); - Untyped_memory::convert_to_page_frames(ipc_buffer_phys, 1); + ipc_buffer_phys = { Untyped_memory::alloc_page(phys_alloc) }; + Untyped_memory::convert_to_page_frames(ipc_buffer_phys.addr, 1); /* allocate TCB within core's CNode */ init_tcb(platform, phys_alloc, prio, 0); @@ -119,9 +125,9 @@ void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio) /* assign IPC buffer to thread */ { /* determine page frame selector of the allocated IPC buffer */ - Cap_sel ipc_buffer_sel = Untyped_memory::frame_sel(ipc_buffer_phys); + Cap_sel ipc_buffer_sel = Untyped_memory::frame_sel(ipc_buffer_phys.addr); - int const ret = seL4_TCB_SetIPCBuffer(tcb_sel.value(), utcb_virt_addr, + int const ret = seL4_TCB_SetIPCBuffer(tcb_sel.value(), utcb_virt.addr, ipc_buffer_sel.value()); ASSERT(ret == 0); } @@ -150,11 +156,11 @@ void Genode::Thread_info::destruct() platform_specific().core_sel_alloc().free(vcpu_sel); } - if (ipc_buffer_phys) { + if (ipc_buffer_phys.addr) { Core::Platform &platform = platform_specific(); Range_allocator &phys_alloc = platform.ram_alloc(); - Untyped_memory::convert_to_untyped_frames(ipc_buffer_phys, 4096); - Untyped_memory::free_page(phys_alloc, ipc_buffer_phys); + Untyped_memory::convert_to_untyped_frames(ipc_buffer_phys.addr, 4096); + Untyped_memory::free_page(phys_alloc, ipc_buffer_phys.addr); } } diff --git a/repos/base-sel4/src/core/platform_pd.cc b/repos/base-sel4/src/core/platform_pd.cc index b2da145144..deebe71345 100644 --- a/repos/base-sel4/src/core/platform_pd.cc +++ b/repos/base-sel4/src/core/platform_pd.cc @@ -49,40 +49,8 @@ Bit_allocator<1024> &Platform_pd::pd_id_alloc() } -bool Platform_pd::bind_thread(Platform_thread &thread) +void Platform_pd::map_ipc_buffer(Ipc_buffer_phys const from, Utcb_virt const to) { - try { - /* allocate fault handler selector in the PD's CSpace */ - thread._fault_handler_sel = alloc_sel(); - /* allocate endpoint selector in the PD's CSpace */ - thread._ep_sel = alloc_sel(); - thread._vcpu_sel = alloc_sel(); - /* allocate asynchronous selector used for locks in the PD's CSpace */ - thread._lock_sel = thread.main_thread() ? Cap_sel(INITIAL_SEL_LOCK) - : alloc_sel(); - thread._vcpu_notify_sel = alloc_sel(); - } catch (Platform_pd::Sel_bit_alloc::Out_of_indices) { - if (thread._fault_handler_sel.value()) { - free_sel(thread._fault_handler_sel); - thread._fault_handler_sel = Cap_sel(0); - } - if (thread._ep_sel.value()) { - free_sel(thread._ep_sel); - thread._ep_sel = Cap_sel(0); - } - if (thread._vcpu_sel.value()) { - free_sel(thread._vcpu_sel); - thread._vcpu_sel = Cap_sel(0); - } - if (thread._vcpu_notify_sel.value()) { - free_sel(thread._vcpu_notify_sel); - thread._vcpu_notify_sel = Cap_sel(0); - } - return false; - } - - thread._pd = this; - /* * Map IPC buffer * @@ -99,23 +67,14 @@ bool Platform_pd::bind_thread(Platform_thread &thread) .executable = false, .flush_support = true }; enum { ONE_PAGE = 1 }; - _vm_space.alloc_page_tables(thread._utcb, get_page_size()); - _vm_space.map(thread._info.ipc_buffer_phys, thread._utcb, ONE_PAGE, attr); - return true; + _vm_space.alloc_page_tables(to.addr, get_page_size()); + _vm_space.map(from.addr, to.addr, ONE_PAGE, attr); } -void Platform_pd::unbind_thread(Platform_thread &thread) +void Platform_pd::unmap_ipc_buffer(Utcb_virt const utcb) { - if (not thread.main_thread()) - free_sel(thread._lock_sel); - - free_sel(thread._fault_handler_sel); - free_sel(thread._ep_sel); - free_sel(thread._vcpu_sel); - free_sel(thread._vcpu_notify_sel); - - _vm_space.unmap(thread._utcb, 1); + _vm_space.unmap(utcb.addr, 1); } diff --git a/repos/base-sel4/src/core/platform_thread.cc b/repos/base-sel4/src/core/platform_thread.cc index c95e4bd691..6b97b81bd4 100644 --- a/repos/base-sel4/src/core/platform_thread.cc +++ b/repos/base-sel4/src/core/platform_thread.cc @@ -94,10 +94,10 @@ bool Core::install_mapping(Mapping const &mapping, unsigned long pager_object_ba ** Utilities to support the Platform_thread interface ** ********************************************************/ -static void prepopulate_ipc_buffer(addr_t const ipc_buffer_phys, - Cap_sel const ep_sel, - Cap_sel const lock_sel, - addr_t const utcb_virt) +static void prepopulate_ipc_buffer(Ipc_buffer_phys const ipc_buffer_phys, + Cap_sel const ep_sel, + Cap_sel const lock_sel, + Utcb_virt const utcb_virt) { /* IPC buffer is one page */ size_t const page_rounded_size = get_page_size(); @@ -108,7 +108,7 @@ static void prepopulate_ipc_buffer(addr_t const ipc_buffer_phys, [&] (void *virt_ptr) { /* map the IPC buffer to core-local virtual addresses */ - map_local(ipc_buffer_phys, (addr_t)virt_ptr, 1); + map_local(ipc_buffer_phys.addr, (addr_t)virt_ptr, 1); /* populate IPC buffer with thread information */ Native_utcb &utcb = *(Native_utcb *)virt_ptr; @@ -139,25 +139,24 @@ static void prepopulate_ipc_buffer(addr_t const ipc_buffer_phys, ** Platform_thread interface ** *******************************/ -int Platform_thread::start(void *ip, void *sp, unsigned int) +void Platform_thread::start(void *ip, void *sp, unsigned int) { - ASSERT(_pd); ASSERT(_pager); /* pager endpoint in core */ Cap_sel const pager_sel(Capability_space::ipc_cap_data(_pager->cap()).sel); /* install page-fault handler endpoint selector to the PD's CSpace */ - _pd->cspace_cnode(_fault_handler_sel).copy(platform_specific().core_cnode(), - pager_sel, _fault_handler_sel); + _pd.cspace_cnode(_fault_handler_sel).copy(platform_specific().core_cnode(), + pager_sel, _fault_handler_sel); /* install the thread's endpoint selector to the PD's CSpace */ - _pd->cspace_cnode(_ep_sel).copy(platform_specific().core_cnode(), - _info.ep_sel, _ep_sel); + _pd.cspace_cnode(_ep_sel).copy(platform_specific().core_cnode(), + _info.ep_sel, _ep_sel); /* install the thread's notification object to the PD's CSpace */ - _pd->cspace_cnode(_lock_sel).mint(platform_specific().core_cnode(), - _info.lock_sel, _lock_sel); + _pd.cspace_cnode(_lock_sel).mint(platform_specific().core_cnode(), + _info.lock_sel, _lock_sel); /* * Populate the thread's IPC buffer with initial information about the @@ -168,21 +167,20 @@ int Platform_thread::start(void *ip, void *sp, unsigned int) /* bind thread to PD and CSpace */ seL4_CNode_CapData const guard_cap_data = - seL4_CNode_CapData_new(0, CONFIG_WORD_SIZE - _pd->cspace_size_log2()); + seL4_CNode_CapData_new(0, CONFIG_WORD_SIZE - _pd.cspace_size_log2()); seL4_CNode_CapData const no_cap_data = { { 0 } }; int const ret = seL4_TCB_SetSpace(_info.tcb_sel.value(), _fault_handler_sel.value(), - _pd->cspace_cnode_1st().sel().value(), + _pd.cspace_cnode_1st().sel().value(), guard_cap_data.words[0], - _pd->page_directory_sel().value(), + _pd.page_directory_sel().value(), no_cap_data.words[0]); ASSERT(ret == 0); start_sel4_thread(_info.tcb_sel, (addr_t)ip, (addr_t)(sp), _location.xpos(), - _utcb); - return 0; + _utcb.addr); } @@ -207,17 +205,18 @@ void Platform_thread::state(Thread_state) { } bool Platform_thread::install_mapping(Mapping const &mapping) { - return _pd->install_mapping(mapping, name()); + return _pd.install_mapping(mapping, name()); } -Platform_thread::Platform_thread(size_t, const char *name, unsigned priority, - Affinity::Location location, addr_t utcb) +Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, + unsigned priority, Affinity::Location location, + addr_t utcb) : _name(name), _utcb(utcb ? utcb : addr_t(INITIAL_IPC_BUFFER_VIRT)), _pager_obj_sel(platform_specific().core_sel_alloc().alloc()), - _location(location), + _pd(pd), _location(location), _priority((uint16_t)(Cpu_session::scale_priority(CONFIG_NUM_PRIORITIES, priority))) { @@ -228,14 +227,52 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned priority, _info.init(_utcb, _priority); platform_thread_registry().insert(*this); + + try { + /* allocate fault handler selector in the PD's CSpace */ + _fault_handler_sel = _pd.alloc_sel(); + /* allocate endpoint selector in the PD's CSpace */ + _ep_sel = _pd.alloc_sel(); + _vcpu_sel = _pd.alloc_sel(); + /* allocate asynchronous selector used for locks in the PD's CSpace */ + _lock_sel = main_thread() ? Cap_sel(INITIAL_SEL_LOCK) + : _pd.alloc_sel(); + _vcpu_notify_sel = _pd.alloc_sel(); + + _pd.map_ipc_buffer(_info.ipc_buffer_phys, _utcb); + _bound_to_pd = true; + } catch (Platform_pd::Sel_alloc::Out_of_indices) { + + /* revert allocations */ + if (_fault_handler_sel.value()) _pd.free_sel(_fault_handler_sel); + if (_ep_sel.value()) _pd.free_sel(_ep_sel); + if (_vcpu_sel.value()) _pd.free_sel(_vcpu_sel); + if (_vcpu_notify_sel.value()) _pd.free_sel(_vcpu_notify_sel); + + _fault_handler_sel = Cap_sel { 0 }; + _ep_sel = Cap_sel { 0 }; + _vcpu_sel = Cap_sel { 0 }; + _vcpu_notify_sel = Cap_sel { 0 }; + + _bound_to_pd = false; + } } Platform_thread::~Platform_thread() { - if (_pd) { - seL4_TCB_Suspend(_info.tcb_sel.value()); - _pd->unbind_thread(*this); + seL4_TCB_Suspend(_info.tcb_sel.value()); + + if (_bound_to_pd) { + if (!main_thread()) + _pd.free_sel(_lock_sel); + + _pd.free_sel(_fault_handler_sel); + _pd.free_sel(_ep_sel); + _pd.free_sel(_vcpu_sel); + _pd.free_sel(_vcpu_notify_sel); + + _pd.unmap_ipc_buffer(_utcb); } if (_pager) { @@ -252,6 +289,7 @@ Platform_thread::~Platform_thread() platform_specific().core_sel_alloc().free(_pager_obj_sel); } + Trace::Execution_time Platform_thread::execution_time() const { if (!Thread::myself() || !Thread::myself()->utcb()) { @@ -271,6 +309,7 @@ Trace::Execution_time Platform_thread::execution_time() const return { ec_time, sc_time, 10000, _priority}; } + void Platform_thread::setup_vcpu(Cap_sel ept, Cap_sel notification) { if (!_info.init_vcpu(platform_specific(), ept)) { @@ -279,10 +318,10 @@ void Platform_thread::setup_vcpu(Cap_sel ept, Cap_sel notification) } /* install the thread's endpoint selector to the PD's CSpace */ - _pd->cspace_cnode(_vcpu_sel).copy(platform_specific().core_cnode(), - _info.vcpu_sel, _vcpu_sel); - _pd->cspace_cnode(_vcpu_notify_sel).copy(platform_specific().core_cnode(), - notification, _vcpu_notify_sel); + _pd.cspace_cnode(_vcpu_sel).copy(platform_specific().core_cnode(), + _info.vcpu_sel, _vcpu_sel); + _pd.cspace_cnode(_vcpu_notify_sel).copy(platform_specific().core_cnode(), + notification, _vcpu_notify_sel); prepopulate_ipc_buffer(_info.ipc_buffer_phys, _vcpu_sel, _vcpu_notify_sel, _utcb); diff --git a/repos/base-sel4/src/core/thread_start.cc b/repos/base-sel4/src/core/thread_start.cc index 03d14ca820..4d4deca40c 100644 --- a/repos/base-sel4/src/core/thread_start.cc +++ b/repos/base-sel4/src/core/thread_start.cc @@ -32,7 +32,7 @@ using namespace Core; void Thread::_init_platform_thread(size_t, Type type) { - addr_t const utcb_virt_addr = (addr_t)&_stack->utcb(); + Utcb_virt const utcb_virt { (addr_t)&_stack->utcb() }; if (type == MAIN) { native_thread().tcb_sel = seL4_CapInitThreadTCB; @@ -41,12 +41,12 @@ void Thread::_init_platform_thread(size_t, Type type) } Thread_info thread_info; - thread_info.init(utcb_virt_addr, CONFIG_NUM_PRIORITIES - 1); + thread_info.init(utcb_virt, CONFIG_NUM_PRIORITIES - 1); - if (!map_local(thread_info.ipc_buffer_phys, utcb_virt_addr, 1)) { + if (!map_local(thread_info.ipc_buffer_phys.addr, utcb_virt.addr, 1)) { error(__func__, ": could not map IPC buffer " - "phys=", Hex(thread_info.ipc_buffer_phys), " " - "local=%", Hex(utcb_virt_addr)); + "phys=", Hex(thread_info.ipc_buffer_phys.addr), " " + "local=%", Hex(utcb_virt.addr)); } native_thread().tcb_sel = thread_info.tcb_sel.value(); @@ -102,7 +102,7 @@ void Thread::_thread_start() Thread::Start_result Thread::start() { /* write ipcbuffer address to utcb*/ - utcb()->ipcbuffer(addr_t(utcb())); + utcb()->ipcbuffer(Native_utcb::Virt { addr_t(utcb()) }); start_sel4_thread(Cap_sel(native_thread().tcb_sel), (addr_t)&_thread_start, (addr_t)stack_top(), _affinity.xpos(), addr_t(utcb())); diff --git a/repos/base-sel4/src/include/base/internal/native_utcb.h b/repos/base-sel4/src/include/base/internal/native_utcb.h index edb061ae33..8e62a8bb90 100644 --- a/repos/base-sel4/src/include/base/internal/native_utcb.h +++ b/repos/base-sel4/src/include/base/internal/native_utcb.h @@ -38,7 +38,9 @@ struct Genode::Native_utcb static addr_t constexpr tls_ipcbuffer_offset = (ELEMENTS - 3) * sizeof(_raw[0]); - void ipcbuffer(addr_t const addr) { _raw[ELEMENTS - 3] = addr; } + struct Virt { addr_t addr; }; + + void ipcbuffer(Virt const virt) { _raw[ELEMENTS - 3] = virt.addr; } }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_UTCB_H_ */ diff --git a/repos/base/src/core/cpu_session_component.cc b/repos/base/src/core/cpu_session_component.cc index e1274c1462..e00093ea92 100644 --- a/repos/base/src/core/cpu_session_component.cc +++ b/repos/base/src/core/cpu_session_component.cc @@ -57,27 +57,33 @@ Cpu_session_component::create_thread(Capability pd_cap, Mutex::Guard slab_lock_guard(_thread_alloc_lock); - try { - Cpu_thread_component &thread = *new (&_thread_alloc) - Cpu_thread_component( - cap(), _thread_ep, _pager_ep, *pd, _trace_control_area, - _trace_sources, weight, _weight_to_quota(weight.value), - _thread_affinity(affinity), _label, name, - _priority, utcb); + pd->with_threads([&] (Pd_session_component::Threads &pd_threads) { + pd->with_platform_pd([&] (Platform_pd &platform_pd) { + try { + Cpu_thread_component &thread = *new (&_thread_alloc) + Cpu_thread_component( + cap(), *this, _thread_ep, _pager_ep, *pd, platform_pd, + pd_threads, _trace_control_area, _trace_sources, + weight, _weight_to_quota(weight.value), + _thread_affinity(affinity), _label, name, + _priority, utcb); - if (!thread.valid()) { - destroy(_thread_alloc, &thread); - return; - } + if (!thread.valid()) { /* 'Platform_thread' creation failed */ + destroy(&_thread_alloc, &thread); + result = Create_thread_error::DENIED; + return; + } - thread.session_exception_sigh(_exception_sigh); + thread.session_exception_sigh(_exception_sigh); - _thread_list.insert(&thread); - result = thread.cap(); - } - catch (Out_of_ram) { result = Create_thread_error::OUT_OF_RAM; } - catch (Out_of_caps) { result = Create_thread_error::OUT_OF_CAPS; } - catch (...) { result = Create_thread_error::DENIED; } + _thread_list.insert(&thread); + result = thread.cap(); + } + catch (Out_of_ram) { result = Create_thread_error::OUT_OF_RAM; } + catch (Out_of_caps) { result = Create_thread_error::OUT_OF_CAPS; } + catch (...) { result = Create_thread_error::DENIED; } + }); + }); }); if (result.failed()) { diff --git a/repos/base/src/core/cpu_thread_component.cc b/repos/base/src/core/cpu_thread_component.cc index 8d694ed299..568bc4e947 100644 --- a/repos/base/src/core/cpu_thread_component.cc +++ b/repos/base/src/core/cpu_thread_component.cc @@ -12,7 +12,7 @@ */ /* core includes */ -#include +#include using namespace Core; @@ -26,6 +26,9 @@ void Cpu_thread_component::_update_exception_sigh() } +void Cpu_thread_component::destroy() { _cpu.kill_thread(cap()); } + + void Cpu_thread_component::quota(size_t quota) { _platform_thread.quota(quota); diff --git a/repos/base/src/core/include/cpu_thread_component.h b/repos/base/src/core/include/cpu_thread_component.h index 825784e217..5fd8fd4086 100644 --- a/repos/base/src/core/include/cpu_thread_component.h +++ b/repos/base/src/core/include/cpu_thread_component.h @@ -28,7 +28,10 @@ #include #include -namespace Core { class Cpu_thread_component; } +namespace Core { + class Cpu_session_component; + class Cpu_thread_component; +} class Core::Cpu_thread_component : public Rpc_object, @@ -39,6 +42,8 @@ class Core::Cpu_thread_component : public Rpc_object, typedef Trace::Thread_name Thread_name; + using Pd_threads = Pd_session_component::Threads; + private: friend class List; @@ -46,17 +51,13 @@ class Core::Cpu_thread_component : public Rpc_object, Rpc_entrypoint &_ep; Pager_entrypoint &_pager_ep; + Cpu_session_component &_cpu; Region_map_component &_address_space_region_map; Cpu_session::Weight const _weight; Session_label const _session_label; Thread_name const _name; + Pd_threads::Element _pd_element; Platform_thread _platform_thread; - bool const _bound_to_pd; - - bool _bind_to_pd(Pd_session_component &pd) - { - return pd.bind_thread(_platform_thread); - } /** * Exception handler as defined by 'Cpu_session::exception_sigh' @@ -138,9 +139,12 @@ class Core::Cpu_thread_component : public Rpc_object, * \param utcb user-local UTCB base */ Cpu_thread_component(Cpu_session_capability cpu_session_cap, + Cpu_session_component &cpu, Rpc_entrypoint &ep, Pager_entrypoint &pager_ep, Pd_session_component &pd, + Platform_pd &platform_pd, + Pd_threads &pd_threads, Trace::Control_area &trace_control_area, Trace::Source_registry &trace_sources, Cpu_session::Weight weight, @@ -151,12 +155,12 @@ class Core::Cpu_thread_component : public Rpc_object, unsigned priority, addr_t utcb) : - _ep(ep), _pager_ep(pager_ep), + _ep(ep), _pager_ep(pager_ep), _cpu(cpu), _address_space_region_map(pd.address_space_region_map()), _weight(weight), _session_label(label), _name(name), - _platform_thread(quota, name.string(), priority, location, utcb), - _bound_to_pd(_bind_to_pd(pd)), + _pd_element(pd_threads, *this), + _platform_thread(platform_pd, quota, name.string(), priority, location, utcb), _trace_control_slot(trace_control_area), _trace_sources(trace_sources), _managed_thread_cap(_ep, *this), @@ -181,7 +185,9 @@ class Core::Cpu_thread_component : public Rpc_object, _address_space_region_map.remove_client(_rm_client); } - bool valid() const { return _bound_to_pd; }; + bool valid() { return _platform_thread.valid(); } + + void destroy(); /* solely called by ~Pd_session_component */ /******************************************** diff --git a/repos/base/src/core/include/pd_session_component.h b/repos/base/src/core/include/pd_session_component.h index 370b1c85f2..b4c1e6b5b1 100644 --- a/repos/base/src/core/include/pd_session_component.h +++ b/repos/base/src/core/include/pd_session_component.h @@ -38,7 +38,10 @@ #include #include -namespace Core { class Pd_session_component; } +namespace Core { + class Pd_session_component; + class Cpu_thread_component; +} class Core::Pd_session_component : public Session_object @@ -47,6 +50,8 @@ class Core::Pd_session_component : public Session_object enum class Managing_system { DENIED, PERMITTED }; + using Threads = Registry; + private: Constructible > _cap_account { }; @@ -71,6 +76,8 @@ class Core::Pd_session_component : public Session_object Managing_system _managing_system; + Threads _threads { }; + friend class Native_pd_component; @@ -159,6 +166,8 @@ class Core::Pd_session_component : public Session_object } } + ~Pd_session_component(); + /** * Initialize cap and RAM accounts without providing a reference account * @@ -171,20 +180,16 @@ class Core::Pd_session_component : public Session_object _ram_account.construct(_ram_quota_guard(), _label); } - /** - * Associate thread with PD - * - * \return true on success - * - * This function may fail for platform-specific reasons such as a - * limit on the number of threads per protection domain or a limited - * thread ID namespace. - */ - bool bind_thread(Platform_thread &thread) + void with_platform_pd(auto const &fn) { - return _pd->bind_thread(thread); + if (_pd.constructed()) + fn(*_pd); + else + error("unexpected call for 'with_platform_pd'"); } + void with_threads(auto const &fn) { fn(_threads); } + Region_map_component &address_space_region_map() { return _address_space; diff --git a/repos/base/src/core/pd_session_component.cc b/repos/base/src/core/pd_session_component.cc index de43c03fdd..ad9a88649a 100644 --- a/repos/base/src/core/pd_session_component.cc +++ b/repos/base/src/core/pd_session_component.cc @@ -13,6 +13,7 @@ /* core includes */ #include +#include using namespace Core; @@ -207,3 +208,15 @@ Pd_session_component::attach_dma(Dataspace_capability ds_cap, addr_t at) return _address_space.attach_dma(ds_cap, at); } + + +Pd_session_component::~Pd_session_component() +{ + /* + * As `Platform_thread` objects point to their corresponding `Platform_pd` + * objects, we need to destroy the threads when the `Platform_pd` ceases to + * exist. + */ + _threads.for_each([&] (Cpu_thread_component &thread) { + thread.destroy(); }); +}