diff --git a/repos/base-fiasco/src/core/pager.cc b/repos/base-fiasco/src/core/pager.cc index cba6f257af..458125d76e 100644 --- a/repos/base-fiasco/src/core/pager.cc +++ b/repos/base-fiasco/src/core/pager.cc @@ -101,7 +101,9 @@ void Ipc_pager::acknowledge_wakeup() Untyped_capability Pager_entrypoint::_pager_object_cap(unsigned long badge) { - return Capability_space::import(native_thread().l4id, Rpc_obj_key(badge)); + return with_native_thread( + [&] (Native_thread &nt) { return Capability_space::import(nt.l4id, Rpc_obj_key(badge)); }, + [&] { return Untyped_capability(); }); } diff --git a/repos/base-fiasco/src/core/thread_start.cc b/repos/base-fiasco/src/core/thread_start.cc index 53b4302d94..7c49f350fa 100644 --- a/repos/base-fiasco/src/core/thread_start.cc +++ b/repos/base-fiasco/src/core/thread_start.cc @@ -35,21 +35,30 @@ void Thread::_thread_start() Thread::Start_result Thread::start() { + if (!_stack) + return Start_result::DENIED; + + Stack &stack = *_stack; + + Native_thread &nt = stack.native_thread(); + /* create and start platform thread */ - native_thread().pt = new (platform().core_mem_alloc()) - Platform_thread(platform_specific().core_pd(), _stack->name().string()); + try { + nt.pt = new (platform().core_mem_alloc()) + Platform_thread(platform_specific().core_pd(), stack.name().string()); + } + catch (...) { return Start_result::DENIED; } - native_thread().pt->pager(platform_specific().core_pager()); - native_thread().l4id = native_thread().pt->native_thread_id(); + nt.pt->pager(platform_specific().core_pager()); + nt.l4id = nt.pt->native_thread_id(); - native_thread().pt->start((void *)_thread_start, stack_top()); + nt.pt->start((void *)_thread_start, (void *)stack.top()); return Start_result::OK; } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { - /* destruct platform thread */ - destroy(platform().core_mem_alloc(), native_thread().pt); + destroy(platform().core_mem_alloc(), stack.native_thread().pt); } diff --git a/repos/base-fiasco/src/include/base/internal/native_thread.h b/repos/base-fiasco/src/include/base/internal/native_thread.h index 1234c529e5..cd32cd2400 100644 --- a/repos/base-fiasco/src/include/base/internal/native_thread.h +++ b/repos/base-fiasco/src/include/base/internal/native_thread.h @@ -15,7 +15,7 @@ #define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ /* Genode includes */ -#include +#include /* L4/Fiasco includes */ #include @@ -25,9 +25,9 @@ namespace Core { struct Platform_thread; } namespace Genode { struct Native_thread; } -struct Genode::Native_thread +struct Genode::Native_thread : Noncopyable { - Fiasco::l4_threadid_t l4id; + Fiasco::l4_threadid_t l4id { }; /** * Only used in core @@ -36,7 +36,9 @@ struct Genode::Native_thread * thread object, which is going to be destroyed on destruction of the * 'Thread'. */ - Core::Platform_thread *pt; + struct { Core::Platform_thread *pt = nullptr; }; + + Native_thread() { } }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */ diff --git a/repos/base-fiasco/src/lib/base/thread_bootstrap.cc b/repos/base-fiasco/src/lib/base/thread_bootstrap.cc index a2415bd40c..ce88819b54 100644 --- a/repos/base-fiasco/src/lib/base/thread_bootstrap.cc +++ b/repos/base-fiasco/src/lib/base/thread_bootstrap.cc @@ -42,7 +42,7 @@ void Genode::prepare_init_main_thread() { } void Thread::_thread_bootstrap() { } -void Thread::_init_platform_thread(size_t, Type type) +void Thread::_init_native_thread(Stack &, size_t, Type type) { if (type == NORMAL) return; diff --git a/repos/base-foc/include/foc/native_thread.h b/repos/base-foc/include/foc/native_thread.h index 4fe5f7c130..724a578ed3 100644 --- a/repos/base-foc/include/foc/native_thread.h +++ b/repos/base-foc/include/foc/native_thread.h @@ -19,22 +19,21 @@ #define _INCLUDE__FOC__NATIVE_THREAD_H_ /* Genode includes */ -#include +#include #include #include namespace Genode { struct Native_thread; } -struct Genode::Native_thread +struct Genode::Native_thread : Noncopyable { - Foc::l4_cap_idx_t kcap = 0; + Foc::l4_cap_idx_t kcap { }; /* receive window for capability selectors received at the server side */ Receive_window rcv_window { }; Native_thread() { } - explicit Native_thread(Foc::l4_cap_idx_t kcap) : kcap(kcap) { } }; #endif /* _INCLUDE__FOC__NATIVE_THREAD_H_ */ diff --git a/repos/base-foc/src/core/thread_start.cc b/repos/base-foc/src/core/thread_start.cc index 48a8d7afa5..6ef235f3ce 100644 --- a/repos/base-foc/src/core/thread_start.cc +++ b/repos/base-foc/src/core/thread_start.cc @@ -29,40 +29,13 @@ using namespace Core; -void Thread::_deinit_platform_thread() -{ - warning(__func__, ": not implemented yet!"); -} +void Thread::_deinit_native_thread(Stack &) { } -void Thread::_init_platform_thread(size_t, Type) { } +void Thread::_init_native_thread(Stack &, size_t, Type) { } -Thread::Start_result Thread::start() -{ - using namespace Foc; - - /* create and start platform thread */ - Platform_thread &pt = *new (platform().core_mem_alloc()) - Platform_thread(_stack->name().string()); - - platform_specific().core_pd().bind_thread(pt); - - l4_utcb_t * const foc_utcb = (l4_utcb_t *)(pt.utcb()); - - native_thread() = Native_thread(pt.gate().remote); - - utcb()->foc_utcb = foc_utcb; - - _thread_cap = - reinterpret_cap_cast(Native_capability(pt.thread().local)); - - pt.pager(platform_specific().core_pager()); - - l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_BADGE] = (unsigned long) pt.gate().local.data(); - l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this; - - pt.start((void *)_thread_start, stack_top()); +namespace { struct Core_trace_source : public Core::Trace::Source::Info_accessor, private Core::Trace::Control, @@ -95,9 +68,9 @@ Thread::Start_result Thread::start() } return { Session_label("core"), thread.name(), - Trace::Execution_time(ec_time, sc_time, 10000, - platform_thread.prio()), - thread._affinity }; + Genode::Trace::Execution_time(ec_time, sc_time, 10000, + platform_thread.prio()), + thread.affinity() }; } Core_trace_source(Core::Trace::Source_registry ®istry, Thread &t, @@ -109,9 +82,44 @@ Thread::Start_result Thread::start() registry.insert(this); } }; +} - new (platform().core_mem_alloc()) Core_trace_source(Core::Trace::sources(), - *this, pt); + +Thread::Start_result Thread::start() +{ + using namespace Foc; + + try { + /* create and start platform thread */ + Platform_thread &pt = *new (platform().core_mem_alloc()) + Platform_thread(_stack->name().string()); + + platform_specific().core_pd().bind_thread(pt); + + l4_utcb_t * const foc_utcb = (l4_utcb_t *)(pt.utcb()); + + with_native_thread([&] (Native_thread &nt) { + nt.kcap = pt.gate().remote; }); + + utcb()->foc_utcb = foc_utcb; + + _thread_cap = + reinterpret_cap_cast(Native_capability(pt.thread().local)); + + pt.pager(platform_specific().core_pager()); + + l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_BADGE] = (unsigned long) pt.gate().local.data(); + l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this; + + pt.start((void *)_thread_start, stack_top()); + + try { + new (platform().core_mem_alloc()) + Core_trace_source(Core::Trace::sources(), *this, pt); + } + catch (...) { } + } + catch (...) { return Start_result::DENIED; } return Start_result::OK; } diff --git a/repos/base-foc/src/include/base/internal/lock_helper.h b/repos/base-foc/src/include/base/internal/lock_helper.h index 3d2f16977f..861465909c 100644 --- a/repos/base-foc/src/include/base/internal/lock_helper.h +++ b/repos/base-foc/src/include/base/internal/lock_helper.h @@ -35,6 +35,17 @@ static inline void thread_yield() { Foc::l4_thread_yield(); } +static inline Foc::l4_cap_idx_t foc_cap_idx(Genode::Thread *thread_ptr) +{ + if (!thread_ptr) + return Foc::MAIN_THREAD_CAP; + + return thread_ptr->with_native_thread( + [&] (Genode::Native_thread &nt) { return nt.kcap; }, + [&] { return Foc::MAIN_THREAD_CAP; }); +} + + /** * Custom ExchangeRegisters wrapper for waking up a thread * @@ -44,13 +55,9 @@ static inline void thread_yield() { Foc::l4_thread_yield(); } * * \return true if the thread was in blocking state */ -static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) +static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_ptr) { - Foc::l4_cap_idx_t tid = thread_base ? - thread_base->native_thread().kcap : - Foc::MAIN_THREAD_CAP; - Foc::l4_cap_idx_t irq = tid + Foc::THREAD_IRQ_CAP; - Foc::l4_irq_trigger(irq); + Foc::l4_irq_trigger(foc_cap_idx(thread_ptr) + Foc::THREAD_IRQ_CAP); return true; } @@ -58,12 +65,9 @@ static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) /** * Yield CPU time to the specified thread */ -static inline void thread_switch_to(Genode::Thread *thread_base) +static inline void thread_switch_to(Genode::Thread *thread_ptr) { - Foc::l4_cap_idx_t tid = thread_base ? - thread_base->native_thread().kcap : - Foc::MAIN_THREAD_CAP; - Foc::l4_thread_switch(tid); + Foc::l4_thread_switch(foc_cap_idx(thread_ptr)); } @@ -78,13 +82,8 @@ __attribute__((used)) static void thread_stop_myself(Genode::Thread *) { using namespace Foc; - - Genode::Thread *myself = Genode::Thread::myself(); - Foc::l4_cap_idx_t tid = myself ? - myself->native_thread().kcap : - Foc::MAIN_THREAD_CAP; - Foc::l4_cap_idx_t irq = tid + THREAD_IRQ_CAP; - l4_irq_receive(irq, L4_IPC_NEVER); + l4_irq_receive(foc_cap_idx(Genode::Thread::myself()) + THREAD_IRQ_CAP, + L4_IPC_NEVER); } #endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */ diff --git a/repos/base-foc/src/lib/base/ipc.cc b/repos/base-foc/src/lib/base/ipc.cc index f096586385..c42bff717a 100644 --- a/repos/base-foc/src/lib/base/ipc.cc +++ b/repos/base-foc/src/lib/base/ipc.cc @@ -310,52 +310,57 @@ Rpc_request Genode::ipc_reply_wait(Reply_capability const &, Msgbuf_base &reply_msg, Msgbuf_base &request_msg) { - Receive_window &rcv_window = Thread::myself()->native_thread().rcv_window; + return Thread::myself()->with_native_thread([&] (Native_thread &nt) { - bool need_to_wait = false; + Receive_window &rcv_window = nt.rcv_window; - for (;;) { + bool need_to_wait = false; - request_msg.reset(); + for (;;) { - /* prepare receive window in UTCB */ - addr_t rcv_cap_sel = rcv_window.rcv_cap_sel_base(); - for (size_t i = 0; i < Msgbuf_base::MAX_CAPS_PER_MSG; i++) { - l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP; - rcv_cap_sel += L4_CAP_SIZE; + request_msg.reset(); + + /* prepare receive window in UTCB */ + addr_t rcv_cap_sel = rcv_window.rcv_cap_sel_base(); + for (size_t i = 0; i < Msgbuf_base::MAX_CAPS_PER_MSG; i++) { + l4_utcb_br()->br[i] = rcv_cap_sel | L4_RCV_ITEM_SINGLE_CAP; + rcv_cap_sel += L4_CAP_SIZE; + } + l4_utcb_br()->bdr &= ~L4_BDR_OFFSET_MASK; + + l4_msgtag_t request_tag; + l4_umword_t label = 0; /* kernel-protected label of invoked capability */ + + if (exc.value != Rpc_exception_code::INVALID_OBJECT && !need_to_wait) { + + l4_msgtag_t const reply_tag = copy_msgbuf_to_utcb(reply_msg, exc.value); + + request_tag = l4_ipc_reply_and_wait(l4_utcb(), reply_tag, &label, L4_IPC_SEND_TIMEOUT_0); + } else { + request_tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER); + } + + if (ipc_error(request_tag, false)) { + need_to_wait = true; + continue; + } else need_to_wait = false; + + /* copy request message from the UTCBs message registers */ + unsigned long const badge = + extract_msg_from_utcb(request_tag, rcv_window, request_msg); + + /* ignore request if we detect a forged badge */ + if (!badge_matches_label(badge, label)) { + raw("badge does not match label, ignoring request"); + continue; + } + + return Rpc_request(Native_capability(), badge); } - l4_utcb_br()->bdr &= ~L4_BDR_OFFSET_MASK; - - l4_msgtag_t request_tag; - l4_umword_t label = 0; /* kernel-protected label of invoked capability */ - - if (exc.value != Rpc_exception_code::INVALID_OBJECT - && !need_to_wait) { - - l4_msgtag_t const reply_tag = copy_msgbuf_to_utcb(reply_msg, exc.value); - - request_tag = l4_ipc_reply_and_wait(l4_utcb(), reply_tag, &label, L4_IPC_SEND_TIMEOUT_0); - } else { - request_tag = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER); - } - - if (ipc_error(request_tag, false)) { - need_to_wait = true; - continue; - } else need_to_wait = false; - - /* copy request message from the UTCBs message registers */ - unsigned long const badge = - extract_msg_from_utcb(request_tag, rcv_window, request_msg); - - /* ignore request if we detect a forged badge */ - if (!badge_matches_label(badge, label)) { - raw("badge does not match label, ignoring request"); - continue; - } - - return Rpc_request(Native_capability(), badge); - } + }, + [&] () -> Rpc_request { + sleep_forever(); /* ipc_reply_wait called by uninitialized thread */ + }); } @@ -363,7 +368,8 @@ Ipc_server::Ipc_server() : Native_capability((Cap_index*)Foc::l4_utcb_tcr()->user[Foc::UTCB_TCR_BADGE]) { - Thread::myself()->native_thread().rcv_window.init(); + Thread::myself()->with_native_thread([&] (Native_thread &nt) { + nt.rcv_window.init(); }); } diff --git a/repos/base-foc/src/lib/base/thread_start.cc b/repos/base-foc/src/lib/base/thread_start.cc index 92d6e1f07f..9ecfe9cef1 100644 --- a/repos/base-foc/src/lib/base/thread_start.cc +++ b/repos/base-foc/src/lib/base/thread_start.cc @@ -46,11 +46,11 @@ static Thread_capability main_thread_cap(Thread_capability main_cap = { }) } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { using namespace Foc; - if (native_thread().kcap) { + if (stack.native_thread().kcap) { Cap_index *i = (Cap_index*)l4_utcb_tcr_u(utcb()->foc_utcb)->user[UTCB_TCR_BADGE]; cap_map().remove(i); } @@ -61,7 +61,7 @@ void Thread::_deinit_platform_thread() } -void Thread::_init_platform_thread(size_t weight, Type type) +void Thread::_init_native_thread(Stack &stack, size_t weight, Type type) { _init_cpu_session_and_trace_control(); @@ -74,7 +74,7 @@ void Thread::_init_platform_thread(size_t weight, Type type) } /* adjust values whose computation differs for a main thread */ - native_thread().kcap = Foc::MAIN_THREAD_CAP; + stack.native_thread().kcap = Foc::MAIN_THREAD_CAP; _thread_cap = main_thread_cap(); if (_thread_cap.failed()) { @@ -104,7 +104,8 @@ Thread::Start_result Thread::start() Foc::l4_utcb_t * const foc_utcb = (Foc::l4_utcb_t *)state.utcb; utcb()->foc_utcb = foc_utcb; - native_thread() = Native_thread(state.kcap); + with_native_thread([&] (Native_thread &nt) { + nt.kcap = state.kcap; }); Cap_index *i = cap_map().insert(state.id, state.kcap); l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_BADGE] = (unsigned long) i; diff --git a/repos/base-foc/src/lib/base/x86/vm.cc b/repos/base-foc/src/lib/base/x86/vm.cc index a8fb4d598e..ac493368cf 100644 --- a/repos/base-foc/src/lib/base/x86/vm.cc +++ b/repos/base-foc/src/lib/base/x86/vm.cc @@ -423,9 +423,11 @@ struct Foc_vcpu : Thread, Noncopyable /* consume notification */ while (vcpu->sticky_flags) { - Foc::l4_cap_idx_t tid = native_thread().kcap; - Foc::l4_cap_idx_t irq = tid + Foc::TASK_VCPU_IRQ_CAP; - l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0); + with_native_thread([&] (Native_thread &nt) { + Foc::l4_cap_idx_t tid = nt.kcap; + Foc::l4_cap_idx_t irq = tid + Foc::TASK_VCPU_IRQ_CAP; + l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0); + }); } } } @@ -449,9 +451,11 @@ struct Foc_vcpu : Thread, Noncopyable /* consume notification */ while (vcpu->sticky_flags) { - Foc::l4_cap_idx_t tid = native_thread().kcap; - Foc::l4_cap_idx_t irq = tid + Foc::TASK_VCPU_IRQ_CAP; - l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0); + with_native_thread([&] (Native_thread &nt) { + Foc::l4_cap_idx_t tid = nt.kcap; + Foc::l4_cap_idx_t irq = tid + Foc::TASK_VCPU_IRQ_CAP; + l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0); + }); } } @@ -1341,9 +1345,11 @@ struct Foc_vcpu : Thread, Noncopyable _state_request = PAUSE; /* Trigger vCPU exit */ - Foc::l4_cap_idx_t tid = native_thread().kcap; - Foc::l4_cap_idx_t irq = tid + Foc::TASK_VCPU_IRQ_CAP; - Foc::l4_irq_trigger(irq); + with_native_thread([&] (Native_thread &nt) { + Foc::l4_cap_idx_t tid = nt.kcap; + Foc::l4_cap_idx_t irq = tid + Foc::TASK_VCPU_IRQ_CAP; + Foc::l4_irq_trigger(irq); + }); _wake_up.up(); } diff --git a/repos/base-foc/src/timer/foc/component.cc b/repos/base-foc/src/timer/foc/component.cc index 7058c5fde2..38ce2cace1 100644 --- a/repos/base-foc/src/timer/foc/component.cc +++ b/repos/base-foc/src/timer/foc/component.cc @@ -134,7 +134,7 @@ class Timer::Device void entry() override { - _myself = native_thread().kcap; + with_native_thread([&] (Native_thread &nt) { _myself = nt.kcap; }); for (;;) { diff --git a/repos/base-hw/src/core/pager.cc b/repos/base-hw/src/core/pager.cc index 98855756a8..157ed2b123 100644 --- a/repos/base-hw/src/core/pager.cc +++ b/repos/base-hw/src/core/pager.cc @@ -199,12 +199,11 @@ void Pager_entrypoint::dissolve(Pager_object &o) Pager_capability Pager_entrypoint::manage(Pager_object &o) { unsigned const cpu = o.location().xpos(); - if (cpu >= _cpus) { + if (cpu >= _cpus) error("Invalid location of pager object ", cpu); - } else { - o.start_paging(_threads[cpu]._kobj, - *_threads[cpu].native_thread().platform_thread); - } + else + _threads[cpu].with_native_thread([&] (Native_thread &nt) { + o.start_paging(_threads[cpu]._kobj, *nt.platform_thread); }); return reinterpret_cap_cast(o.cap()); } diff --git a/repos/base-hw/src/core/thread_start.cc b/repos/base-hw/src/core/thread_start.cc index 9c811da98f..a736fc2656 100644 --- a/repos/base-hw/src/core/thread_start.cc +++ b/repos/base-hw/src/core/thread_start.cc @@ -32,13 +32,7 @@ using namespace Core; namespace Hw { extern Untyped_capability _main_thread_cap; } -Thread::Start_result Thread::start() -{ - /* start thread with stack pointer at the top of stack */ - native_thread().platform_thread->start((void *)&_thread_start, stack_top()); - - if (_thread_cap.failed()) - return Start_result::DENIED; +namespace { struct Trace_source : public Core::Trace::Source::Info_accessor, private Core::Trace::Control, @@ -51,11 +45,11 @@ Thread::Start_result Thread::start() */ Info trace_source_info() const override { - Platform_thread * t = thread.native_thread().platform_thread; + Genode::Trace::Execution_time execution_time { 0, 0 }; - Trace::Execution_time execution_time { 0, 0 }; - if (t) - execution_time = t->execution_time(); + thread.with_native_thread([&] (Native_thread &nt) { + if (nt.platform_thread) + execution_time = nt.platform_thread->execution_time(); }); return { Session_label("core"), thread.name(), execution_time, thread.affinity() }; @@ -70,34 +64,52 @@ Thread::Start_result Thread::start() registry.insert(this); } }; +} + + +Thread::Start_result Thread::start() +{ + if (!_stack) + return Start_result::DENIED; + + Stack &stack = *_stack; + + Native_thread &nt = stack.native_thread(); + + /* start thread with stack pointer at the top of stack */ + nt.platform_thread->start((void *)&_thread_start, (void *)stack.top()); + + if (_thread_cap.failed()) + return Start_result::DENIED;; /* create trace sources for core threads */ - new (platform().core_mem_alloc()) Trace_source(Core::Trace::sources(), *this); + try { + new (platform().core_mem_alloc()) Trace_source(Core::Trace::sources(), *this); + } catch (...) { } return Start_result::OK; } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { - /* destruct platform thread */ - destroy(platform().core_mem_alloc(), native_thread().platform_thread); + destroy(platform().core_mem_alloc(), stack.native_thread().platform_thread); } -void Thread::_init_platform_thread(size_t, Type type) +void Thread::_init_native_thread(Stack &stack, size_t, Type type) { if (type == NORMAL) { - native_thread().platform_thread = new (platform().core_mem_alloc()) - Platform_thread(_stack->name(), _stack->utcb()); + stack.native_thread().platform_thread = new (platform().core_mem_alloc()) + Platform_thread(_stack->name(), stack.utcb()); return; } /* remap initial main-thread UTCB according to stack-area spec */ map_local(Platform::core_main_thread_phys_utcb(), - (addr_t)&_stack->utcb(), + (addr_t)&stack.utcb(), max(sizeof(Native_utcb) / get_page_size(), (size_t)1)); /* adjust initial object state in case of a main thread */ - native_thread().cap = Hw::_main_thread_cap; + stack.native_thread().cap = Hw::_main_thread_cap; } diff --git a/repos/base-hw/src/include/base/internal/lock_helper.h b/repos/base-hw/src/include/base/internal/lock_helper.h index 6e6e4e9bb8..5bb6c46686 100644 --- a/repos/base-hw/src/include/base/internal/lock_helper.h +++ b/repos/base-hw/src/include/base/internal/lock_helper.h @@ -32,11 +32,16 @@ static inline void thread_yield() { Kernel::yield_thread(); } /** * Return kernel name of thread t */ -static inline Kernel::capid_t -native_thread_id(Genode::Thread * const t) +static inline Kernel::capid_t native_thread_id(Genode::Thread *thread_ptr) { using Genode::Capability_space::capid; - return t ? capid(t->native_thread().cap) : capid(Hw::_main_thread_cap); + + if (!thread_ptr) + return capid(Hw::_main_thread_cap); + + return thread_ptr->with_native_thread( + [&] (Genode::Native_thread &nt) { return capid(nt.cap); }, + [&] { return Kernel::cap_id_invalid(); }); } @@ -52,10 +57,9 @@ static inline void thread_switch_to(Genode::Thread *) /** * Resume thread t and return wether t was paused or not */ -static inline bool -thread_check_stopped_and_restart(Genode::Thread * const t) +static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_ptr) { - return Kernel::restart_thread(native_thread_id(t)); + return Kernel::restart_thread(native_thread_id(thread_ptr)); } diff --git a/repos/base-hw/src/include/base/internal/native_thread.h b/repos/base-hw/src/include/base/internal/native_thread.h index fa412db38e..4c80e05e38 100644 --- a/repos/base-hw/src/include/base/internal/native_thread.h +++ b/repos/base-hw/src/include/base/internal/native_thread.h @@ -14,19 +14,21 @@ #ifndef _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ #define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ -#include +#include #include namespace Genode { struct Native_thread; } - namespace Core { class Platform_thread; } -struct Genode::Native_thread +struct Genode::Native_thread : Noncopyable { - Core::Platform_thread *platform_thread; - Native_capability cap; + Native_capability cap { }; + + struct { Core::Platform_thread *platform_thread; }; + + Native_thread() { } }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */ diff --git a/repos/base-hw/src/lib/base/ipc.cc b/repos/base-hw/src/lib/base/ipc.cc index 0bd382cb04..509ef198d2 100644 --- a/repos/base-hw/src/lib/base/ipc.cc +++ b/repos/base-hw/src/lib/base/ipc.cc @@ -165,11 +165,18 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &, } -Ipc_server::Ipc_server() -: - Native_capability(Thread::myself() ? Thread::myself()->native_thread().cap - : Hw::_main_thread_cap) -{ } +static inline Native_capability my_native_thread_cap() +{ + if (!Thread::myself()) + return Hw::_main_thread_cap; + + return Thread::myself()->with_native_thread( + [&] (Native_thread &nt) { return nt.cap; }, + [&] { return Native_capability(); }); +} + + +Ipc_server::Ipc_server() : Native_capability(my_native_thread_cap()) { } Ipc_server::~Ipc_server() { } diff --git a/repos/base-hw/src/lib/base/thread_bootstrap.cc b/repos/base-hw/src/lib/base/thread_bootstrap.cc index 77e6dd0303..fef7068771 100644 --- a/repos/base-hw/src/lib/base/thread_bootstrap.cc +++ b/repos/base-hw/src/lib/base/thread_bootstrap.cc @@ -84,8 +84,10 @@ void Thread::_thread_start() void Thread::_thread_bootstrap() { - Kernel::capid_t capid = myself()->utcb()->cap_get(Native_utcb::THREAD_MYSELF); - native_thread().cap = Capability_space::import(capid); - if (native_thread().cap.valid()) - Kernel::ack_cap(Capability_space::capid(native_thread().cap)); + with_native_thread([&] (Native_thread &nt) { + Kernel::capid_t capid = myself()->utcb()->cap_get(Native_utcb::THREAD_MYSELF); + nt.cap = Capability_space::import(capid); + if (nt.cap.valid()) + Kernel::ack_cap(Capability_space::capid(nt.cap)); + }); } diff --git a/repos/base-hw/src/lib/base/thread_start.cc b/repos/base-hw/src/lib/base/thread_start.cc index 4416750504..e49049362d 100644 --- a/repos/base-hw/src/lib/base/thread_start.cc +++ b/repos/base-hw/src/lib/base/thread_start.cc @@ -51,14 +51,14 @@ static Thread_capability main_thread_cap(Thread_capability main_cap = { }) ** Thread ** ************/ -void Thread::_init_platform_thread(size_t weight, Type type) +void Thread::_init_native_thread(Stack &stack, size_t weight, Type type) { _init_cpu_session_and_trace_control(); if (type == NORMAL) { /* create server object */ - addr_t const utcb = (addr_t)&_stack->utcb(); + addr_t const utcb = (addr_t)&stack.utcb(); _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), _affinity, Weight(weight), utcb); @@ -67,7 +67,7 @@ void Thread::_init_platform_thread(size_t weight, Type type) /* if we got reinitialized we have to get rid of the old UTCB */ size_t const utcb_size = sizeof(Native_utcb); addr_t const stack_area = stack_area_virtual_base(); - addr_t const utcb_new = (addr_t)&_stack->utcb() - stack_area; + addr_t const utcb_new = (addr_t)&stack.utcb() - stack_area; /* remap initial main-thread UTCB according to stack-area spec */ if (env_stack_area_region_map->attach(Hw::_main_thread_utcb_ds, { @@ -81,12 +81,12 @@ void Thread::_init_platform_thread(size_t weight, Type type) error("failed to attach UTCB to local address space"); /* adjust initial object state in case of a main thread */ - native_thread().cap = Hw::_main_thread_cap; + stack.native_thread().cap = Hw::_main_thread_cap; _thread_cap = main_thread_cap(); } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { if (!_cpu_session) { error("Thread::_cpu_session unexpectedly not defined"); @@ -98,8 +98,8 @@ void Thread::_deinit_platform_thread() [&] (Cpu_session::Create_thread_error) { }); /* detach userland stack */ - size_t const size = sizeof(_stack->utcb()); - addr_t utcb = Stack_allocator::addr_to_base(_stack) + + size_t const size = sizeof(stack.utcb()); + addr_t utcb = Stack_allocator::addr_to_base(&stack) + stack_virtual_size() - size - stack_area_virtual_base(); env_stack_area_region_map->detach(utcb); } @@ -107,6 +107,11 @@ void Thread::_deinit_platform_thread() Thread::Start_result Thread::start() { + if (!_stack) + return Start_result::DENIED; + + Stack &stack = *_stack; + while (avail_capability_slab() < 5) upgrade_capability_slab(); @@ -115,19 +120,19 @@ Thread::Start_result Thread::start() Cpu_thread_client cpu_thread(cap); /* attach UTCB at top of stack */ - size_t const size = sizeof(_stack->utcb()); + size_t const size = sizeof(stack.utcb()); return env_stack_area_region_map->attach(cpu_thread.utcb(), { .size = size, .offset = { }, .use_at = true, - .at = Stack_allocator::addr_to_base(_stack) + .at = Stack_allocator::addr_to_base(&stack) + stack_virtual_size() - size - stack_area_virtual_base(), .executable = { }, .writeable = true }).convert( [&] (Region_map::Range) { /* start execution with initial IP and aligned SP */ - cpu_thread.start((addr_t)_thread_start, _stack->top()); + cpu_thread.start((addr_t)_thread_start, stack.top()); return Start_result::OK; }, [&] (Region_map::Attach_error) { diff --git a/repos/base-linux/src/core/core_rpc_cap_alloc.cc b/repos/base-linux/src/core/core_rpc_cap_alloc.cc index f086920b74..a923cc9c84 100644 --- a/repos/base-linux/src/core/core_rpc_cap_alloc.cc +++ b/repos/base-linux/src/core/core_rpc_cap_alloc.cc @@ -27,11 +27,14 @@ void Genode::init_rpc_cap_alloc(Parent &) { } Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session &, Native_capability, addr_t) { - return Thread::native_thread().epoll.alloc_rpc_cap(); + return with_native_thread( + [&] (Native_thread &nt) { return nt.epoll.alloc_rpc_cap(); }, + [&] { return Native_capability(); }); } void Rpc_entrypoint::_free_rpc_cap(Pd_session &, Native_capability cap) { - Thread::native_thread().epoll.free_rpc_cap(cap); + with_native_thread([&] (Native_thread &nt) { + nt.epoll.free_rpc_cap(cap); }); } diff --git a/repos/base-linux/src/core/thread_linux.cc b/repos/base-linux/src/core/thread_linux.cc index beb5d34882..46f326df54 100644 --- a/repos/base-linux/src/core/thread_linux.cc +++ b/repos/base-linux/src/core/thread_linux.cc @@ -58,15 +58,19 @@ void Thread::_thread_start() } -void Thread::_init_platform_thread(size_t, Type) { } +void Thread::_init_native_thread(Stack &, size_t, Type) { } -void Thread::_deinit_platform_thread() { } +void Thread::_deinit_native_thread(Stack &) { } Thread::Start_result Thread::start() { - native_thread().tid = lx_create_thread(Thread::_thread_start, stack_top()); - native_thread().pid = lx_getpid(); - return Start_result::OK; + return with_native_thread( + [&] (Native_thread &nt) { + nt.tid = lx_create_thread(Thread::_thread_start, stack_top()); + nt.pid = lx_getpid(); + return Start_result::OK; + }, + [&] { return Start_result::DENIED; }); } diff --git a/repos/base-linux/src/include/base/internal/lock_helper.h b/repos/base-linux/src/include/base/internal/lock_helper.h index 37321ae45c..87c880c391 100644 --- a/repos/base-linux/src/include/base/internal/lock_helper.h +++ b/repos/base-linux/src/include/base/internal/lock_helper.h @@ -37,12 +37,23 @@ static inline void thread_yield() } -static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) +static inline int *futex_counter_ptr(Genode::Thread *thread_ptr) { - const int *futex_counter_ptr = thread_base ? - &thread_base->native_thread().futex_counter : - &main_thread_futex_counter; - return lx_futex(futex_counter_ptr, LX_FUTEX_WAKE, 1); + if (!thread_ptr) + return &main_thread_futex_counter; + + return thread_ptr->with_native_thread( + [&] (Genode::Native_thread &nt) { return &nt.futex_counter; }, + [&] { + Genode::error("attempt to access futex of invalid thread"); + return (int *)nullptr; + }); +} + + +static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_ptr) +{ + return lx_futex(futex_counter_ptr(thread_ptr), LX_FUTEX_WAKE, 1); } @@ -56,10 +67,7 @@ static inline void thread_stop_myself(Genode::Thread *myself) * 'thread_check_stopped_and_restart()' function will get called * repeatedly until this thread has actually executed the syscall. */ - const int *futex_counter_ptr = myself ? - &myself->native_thread().futex_counter : - &main_thread_futex_counter; - lx_futex(futex_counter_ptr, LX_FUTEX_WAIT, 0); + lx_futex(futex_counter_ptr(myself), LX_FUTEX_WAIT, 0); } #endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */ diff --git a/repos/base-linux/src/include/base/internal/native_thread.h b/repos/base-linux/src/include/base/internal/native_thread.h index 9f7740fd39..6eda9989ad 100644 --- a/repos/base-linux/src/include/base/internal/native_thread.h +++ b/repos/base-linux/src/include/base/internal/native_thread.h @@ -22,92 +22,82 @@ namespace Genode { struct Native_thread; } -class Genode::Native_thread +struct Genode::Native_thread : Noncopyable { - private: + /* + * Unfortunately, both - PID and TID - are needed for lx_tgkill() + */ + unsigned int tid = 0; /* Native thread ID type as returned by the + 'clone' system call */ + unsigned int pid = 0; /* process ID (resp. thread-group ID) */ - /* - * Noncopyable - */ - Native_thread(Native_thread const &); - Native_thread &operator = (Native_thread const &); + bool is_ipc_server = false; - public: + /** + * Natively aligned memory location used in the lock implementation + */ + int futex_counter __attribute__((aligned(sizeof(Genode::addr_t)))) = 0; - /* - * Unfortunately, both - PID and TID - are needed for lx_tgkill() - */ - unsigned int tid = 0; /* Native thread ID type as returned by the - 'clone' system call */ - unsigned int pid = 0; /* process ID (resp. thread-group ID) */ + struct Meta_data; - bool is_ipc_server = false; + /** + * Opaque pointer to additional thread-specific meta data + * + * This pointer is used by hybrid Linux/Genode programs to maintain + * POSIX-thread-related meta data. For non-hybrid Genode programs, it + * remains unused. + */ + struct { Meta_data *meta_data = nullptr; }; - /** - * Natively aligned memory location used in the lock implementation - */ - int futex_counter __attribute__((aligned(sizeof(Genode::addr_t)))) = 0; + class Epoll + { + private: - struct Meta_data; + Lx_socketpair _control { }; - /** - * Opaque pointer to additional thread-specific meta data - * - * This pointer is used by hybrid Linux/Genode programs to maintain - * POSIX-thread-related meta data. For non-hybrid Genode programs, it - * remains unused. - */ - Meta_data *meta_data = nullptr; + Lx_epoll_sd const _epoll; - class Epoll - { - private: + void _add (Lx_sd); + void _remove(Lx_sd); - Lx_socketpair _control { }; + bool _rpc_ep_exited = false; - Lx_epoll_sd const _epoll; + struct Control_function : Interface + { + virtual void execute() = 0; + }; - void _add (Lx_sd); - void _remove(Lx_sd); + /* + * Execute functor 'fn' in the context of the 'poll' method. + */ + void _exec_control(auto const &fn); - bool _rpc_ep_exited = false; + public: - struct Control_function : Interface - { - virtual void execute() = 0; - }; + Epoll(); - /* - * Execute functor 'fn' in the context of the 'poll' method. - */ - void _exec_control(auto const &fn); + ~Epoll(); - public: + /** + * Wait for incoming RPC messages + * + * \return valid socket descriptor that matches the invoked + * RPC object + */ + Lx_sd poll(); - Epoll(); + Native_capability alloc_rpc_cap(); - ~Epoll(); + void free_rpc_cap(Native_capability); - /** - * Wait for incoming RPC messages - * - * \return valid socket descriptor that matches the invoked - * RPC object - */ - Lx_sd poll(); + /** + * Flag RPC entrypoint as no longer in charge of dispatching + */ + void rpc_ep_exited() { _rpc_ep_exited = true; } - Native_capability alloc_rpc_cap(); + } epoll { }; - void free_rpc_cap(Native_capability); - - /** - * Flag RPC entrypoint as no longer in charge of dispatching - */ - void rpc_ep_exited() { _rpc_ep_exited = true; } - - } epoll { }; - - Native_thread() { } + Native_thread() { } }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */ diff --git a/repos/base-linux/src/lib/base/ipc.cc b/repos/base-linux/src/lib/base/ipc.cc index 2683db3256..f0e62580ad 100644 --- a/repos/base-linux/src/lib/base/ipc.cc +++ b/repos/base-linux/src/lib/base/ipc.cc @@ -392,36 +392,38 @@ Rpc_request Genode::ipc_reply_wait(Reply_capability const &last_caller, for (;;) lx_nanosleep(&ts, 0); } - Native_thread::Epoll &epoll = myself_ptr->native_thread().epoll; + return myself_ptr->with_native_thread([&] (Native_thread &nt) { - for (;;) { + for (;;) { - Lx_sd const selected_sd = epoll.poll(); + Lx_sd const selected_sd = nt.epoll.poll(); - Protocol_header &header = request_msg.header(); - Message msg(header.msg_start(), sizeof(Protocol_header) + request_msg.capacity()); + Protocol_header &header = request_msg.header(); + Message msg(header.msg_start(), sizeof(Protocol_header) + request_msg.capacity()); - msg.accept_sockets(Message::MAX_SDS_PER_MSG); + msg.accept_sockets(Message::MAX_SDS_PER_MSG); - request_msg.reset(); - int const ret = lx_recvmsg(selected_sd, msg.msg(), 0x40); + request_msg.reset(); + int const ret = lx_recvmsg(selected_sd, msg.msg(), 0x40); - if (ret < 0) - continue; + if (ret < 0) + continue; - if (msg.num_sockets() == 0 || !msg.socket_at_index(0).valid()) { - warning("ipc_reply_wait: failed to obtain reply socket"); - continue; + if (msg.num_sockets() == 0 || !msg.socket_at_index(0).valid()) { + warning("ipc_reply_wait: failed to obtain reply socket"); + continue; + } + + Lx_sd const reply_socket = msg.socket_at_index(0); + + /* start at offset 1 to skip the reply channel */ + extract_sds_from_message(1, msg, header, request_msg); + + return Rpc_request(Capability_space::import(Rpc_destination(reply_socket), + Rpc_obj_key()), selected_sd.value); } - Lx_sd const reply_socket = msg.socket_at_index(0); - - /* start at offset 1 to skip the reply channel */ - extract_sds_from_message(1, msg, header, request_msg); - - return Rpc_request(Capability_space::import(Rpc_destination(reply_socket), - Rpc_obj_key()), selected_sd.value); - } + }, [&] () -> Rpc_request { sleep_forever(); }); } @@ -435,16 +437,16 @@ Ipc_server::Ipc_server() if (!Thread::myself()) return; - Native_thread &native_thread = Thread::myself()->native_thread(); + Thread::myself()->with_native_thread([&] (Native_thread &nt) { - if (native_thread.is_ipc_server) { - Genode::raw(lx_getpid(), ":", lx_gettid(), - " unexpected multiple instantiation of Ipc_server by one thread"); - struct Ipc_server_multiple_instance { }; - throw Ipc_server_multiple_instance(); - } + if (nt.is_ipc_server) { + Genode::raw(lx_getpid(), ":", lx_gettid(), + " unexpected multiple instantiation of Ipc_server by one thread"); + sleep_forever(); + } - native_thread.is_ipc_server = true; + nt.is_ipc_server = true; + }); } @@ -457,7 +459,6 @@ Ipc_server::~Ipc_server() * Reset thread role to non-server such that we can enter 'sleep_forever' * without getting a warning. */ - Native_thread &native_thread = Thread::myself()->native_thread(); - - native_thread.is_ipc_server = false; + Thread::myself()->with_native_thread([&] (Native_thread &nt) { + nt.is_ipc_server = false; }); } diff --git a/repos/base-linux/src/lib/base/native_thread.cc b/repos/base-linux/src/lib/base/native_thread.cc index 5936fd7985..957c348b52 100644 --- a/repos/base-linux/src/lib/base/native_thread.cc +++ b/repos/base-linux/src/lib/base/native_thread.cc @@ -130,8 +130,12 @@ void Native_thread::Epoll::_exec_control(FN const &fn) * If 'myself_ptr' is nullptr, the caller is the initial thread w/o * a valid 'Thread' object associated yet. This thread is never polling. */ - bool const myself_is_polling = (myself_ptr != nullptr) - && (&myself_ptr->native_thread().epoll == this); + auto myself_is_polling = [&] + { + return myself_ptr && myself_ptr->with_native_thread( + [&] (Native_thread &nt) { return (&nt.epoll == this); }, + [&] { return false; }); + }; /* * If caller runs in the context of the same thread that executes 'poll' we @@ -139,7 +143,7 @@ void Native_thread::Epoll::_exec_control(FN const &fn) * block at this time. If the RPC entrypoint has existed its dispatch * loop, it also cannot poll anymore. */ - if (myself_is_polling || _rpc_ep_exited) { + if (myself_is_polling() || _rpc_ep_exited) { fn(); return; } diff --git a/repos/base-linux/src/lib/base/rpc_cap_alloc.cc b/repos/base-linux/src/lib/base/rpc_cap_alloc.cc index 044f942552..88f2ebec88 100644 --- a/repos/base-linux/src/lib/base/rpc_cap_alloc.cc +++ b/repos/base-linux/src/lib/base/rpc_cap_alloc.cc @@ -61,26 +61,29 @@ Native_capability Rpc_entrypoint::_alloc_rpc_cap(Pd_session& pd, Native_capabili "cap_quota=", cap_upgrade).string()); }); } - return Thread::native_thread().epoll.alloc_rpc_cap(); + return with_native_thread( + [&] (Native_thread &nt) { return nt.epoll.alloc_rpc_cap(); }, + [&] { return Native_capability(); }); } void Rpc_entrypoint::_free_rpc_cap(Pd_session& pd, Native_capability cap) { - Native_thread::Epoll &epoll = Thread::native_thread().epoll; + with_native_thread([&] (Native_thread &nt) { - /* - * Flag RPC entrypoint as exited to prevent 'free_rpc_cap' from issuing - * a remote control request. - */ - if (_exit_handler.exit) - epoll.rpc_ep_exited(); + /* + * Flag RPC entrypoint as exited to prevent 'free_rpc_cap' from issuing + * a remote control request. + */ + if (_exit_handler.exit) + nt.epoll.rpc_ep_exited(); - /* - * Perform the accounting of the PDs cap quota at core, to remain - * consistent with other kernel platforms. - */ - pd.free_rpc_cap(Native_capability()); + /* + * Perform the accounting of the PDs cap quota at core, to remain + * consistent with other kernel platforms. + */ + pd.free_rpc_cap(Native_capability()); - epoll.free_rpc_cap(cap); + nt.epoll.free_rpc_cap(cap); + }); } diff --git a/repos/base-linux/src/lib/base/thread_linux.cc b/repos/base-linux/src/lib/base/thread_linux.cc index f34b62e639..a5cb046fc4 100644 --- a/repos/base-linux/src/lib/base/thread_linux.cc +++ b/repos/base-linux/src/lib/base/thread_linux.cc @@ -83,10 +83,10 @@ void Thread::_thread_start() lx_sigaction(LX_SIGUSR1, empty_signal_handler, false); /* inform core about the new thread and process ID of the new thread */ - { + thread->with_native_thread([&] (Native_thread &nt) { Linux_native_cpu_client native_cpu(thread->_cpu_session->native_cpu()); - native_cpu.thread_id(thread->cap(), thread->native_thread().pid, thread->native_thread().tid); - } + native_cpu.thread_id(thread->cap(), nt.pid, nt.tid); + }); /* wakeup 'start' function */ startup_lock().wakeup(); @@ -100,7 +100,7 @@ void Thread::_thread_start() } -void Thread::_init_platform_thread(size_t /* weight */, Type type) +void Thread::_init_native_thread(Stack &stack, size_t /* weight */, Type type) { /* if no cpu session is given, use it from the environment */ if (!_cpu_session) { @@ -110,7 +110,7 @@ void Thread::_init_platform_thread(size_t /* weight */, Type type) /* for normal threads create an object at the CPU session */ if (type == NORMAL) { - _cpu_session->create_thread(pd_session_cap(), _stack->name().string(), + _cpu_session->create_thread(pd_session_cap(), stack.name(), Affinity::Location(), Weight()).with_result( [&] (Thread_capability cap) { _thread_cap = cap; }, [&] (Cpu_session::Create_thread_error) { @@ -119,12 +119,12 @@ void Thread::_init_platform_thread(size_t /* weight */, Type type) return; } /* adjust initial object state for main threads */ - native_thread().futex_counter = main_thread_futex_counter; + stack.native_thread().futex_counter = main_thread_futex_counter; _thread_cap = main_thread_cap(); } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { /* * Kill thread until it is really really dead @@ -139,12 +139,12 @@ void Thread::_deinit_platform_thread() * anymore. */ for (;;) { + Native_thread &nt = stack.native_thread(); /* destroy thread locally */ - int pid = native_thread().pid; - if (pid == 0) break; + if (nt.pid == 0) break; - int ret = lx_tgkill(pid, native_thread().tid, LX_SIGCANCEL); + int ret = lx_tgkill(nt.pid, nt.tid, LX_SIGCANCEL); if (ret < 0) break; @@ -180,8 +180,10 @@ Thread::Start_result Thread::start() threadlib_initialized = true; } - native_thread().tid = lx_create_thread(Thread::_thread_start, stack_top()); - native_thread().pid = lx_getpid(); + with_native_thread([&] (Native_thread &nt) { + nt.tid = lx_create_thread(Thread::_thread_start, stack_top()); + nt.pid = lx_getpid(); + }); /* wait until the 'thread_start' function got entered */ startup_lock().block(); diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc index 9bb2af2684..1d7501b501 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -383,9 +383,10 @@ static void adopt_thread(Native_thread::Meta_data *meta_data) /* * Initialize thread meta data */ - Native_thread &native_thread = meta_data->thread_base.native_thread(); - native_thread.tid = lx_gettid(); - native_thread.pid = lx_getpid(); + meta_data->thread_base.with_native_thread([&] (Native_thread &nt) { + nt.tid = lx_gettid(); + nt.pid = lx_getpid(); + }); } @@ -483,10 +484,10 @@ Thread *Thread::myself() new (global_alloc()) Thread_meta_data_adopted(thread); /* - * Initialize 'Thread::_native_thread' to point to the default- + * Initialize 'Thread::_native_thread_ptr' to point to the default- * constructed 'Native_thread' (part of 'Meta_data'). */ - meta_data->thread_base._native_thread = &meta_data->native_thread; + meta_data->thread_base._native_thread_ptr = &meta_data->native_thread; adopt_thread(meta_data); return thread; @@ -498,20 +499,20 @@ Thread::Start_result Thread::start() /* * Unblock thread that is supposed to slumber in 'thread_start'. */ - native_thread().meta_data->started(); + with_native_thread([&] (Native_thread &nt) { + nt.meta_data->started(); }); + return Start_result::OK; } void Thread::join() { - native_thread().meta_data->wait_for_join(); + with_native_thread([&] (Native_thread &nt) { + nt.meta_data->wait_for_join(); }); } -Native_thread &Thread::native_thread() { return *_native_thread; } - - Thread::Thread(size_t weight, const char *name, size_t /* stack size */, Type, Cpu_session * cpu_sess, Affinity::Location) : _cpu_session(cpu_sess), _affinity() @@ -519,7 +520,7 @@ Thread::Thread(size_t weight, const char *name, size_t /* stack size */, Native_thread::Meta_data *meta_data = new (global_alloc()) Thread_meta_data_created(this); - _native_thread = &meta_data->native_thread; + _native_thread_ptr = &meta_data->native_thread; int const ret = pthread_create(&meta_data->pt, 0, thread_start, meta_data); if (ret) { @@ -528,18 +529,21 @@ Thread::Thread(size_t weight, const char *name, size_t /* stack size */, throw Out_of_stack_space(); } - native_thread().meta_data->wait_for_construction(); + with_native_thread([&] (Native_thread &nt) { - _thread_cap = _cpu_session->create_thread(_env_ptr->pd_session_cap(), name, - Location(), Weight(weight)); - _thread_cap.with_result( - [&] (Thread_capability cap) { - Linux_native_cpu_client native_cpu(_cpu_session->native_cpu()); - native_cpu.thread_id(cap, native_thread().pid, native_thread().tid); - }, - [&] (Cpu_session::Create_thread_error) { - error("failed to create hybrid thread"); } - ); + nt.meta_data->wait_for_construction(); + + _thread_cap = _cpu_session->create_thread(_env_ptr->pd_session_cap(), name, + Location(), Weight(weight)); + _thread_cap.with_result( + [&] (Thread_capability cap) { + Linux_native_cpu_client native_cpu(_cpu_session->native_cpu()); + native_cpu.thread_id(cap, nt.pid, nt.tid); + }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create hybrid thread"); } + ); + }); } @@ -561,22 +565,25 @@ Thread::Thread(Env &env, Name const &name, size_t stack_size) Thread::~Thread() { - bool const needs_join = (pthread_cancel(native_thread().meta_data->pt) == 0); + with_native_thread([&] (Native_thread &nt) { - if (needs_join) { - int const ret = pthread_join(native_thread().meta_data->pt, 0); - if (ret) - warning("pthread_join unexpectedly returned " - "with ", ret, " (errno=", errno, ")"); - } + bool const needs_join = (pthread_cancel(nt.meta_data->pt) == 0); - Thread_meta_data_created *meta_data = - dynamic_cast(native_thread().meta_data); + if (needs_join) { + int const ret = pthread_join(nt.meta_data->pt, 0); + if (ret) + warning("pthread_join unexpectedly returned " + "with ", ret, " (errno=", errno, ")"); + } - if (meta_data) - destroy(global_alloc(), meta_data); + Thread_meta_data_created *meta_data = + dynamic_cast(nt.meta_data); - _native_thread = nullptr; + if (meta_data) + destroy(global_alloc(), meta_data); + }); + + _native_thread_ptr = nullptr; /* inform core about the killed thread */ _thread_cap.with_result( diff --git a/repos/base-nova/include/nova/native_thread.h b/repos/base-nova/include/nova/native_thread.h index 6f751a6f11..f71e36b127 100644 --- a/repos/base-nova/include/nova/native_thread.h +++ b/repos/base-nova/include/nova/native_thread.h @@ -19,21 +19,17 @@ #ifndef _INCLUDE__NOVA__NATIVE_THREAD_H_ #define _INCLUDE__NOVA__NATIVE_THREAD_H_ -#include #include namespace Genode { struct Native_thread; } -struct Genode::Native_thread + +struct Genode::Native_thread : Noncopyable { static constexpr unsigned long INVALID_INDEX = ~0UL; - addr_t ec_sel { 0 }; /* selector for execution context */ - addr_t exc_pt_sel { 0 }; /* base of event portal window */ - addr_t initial_ip { 0 }; /* initial IP of local thread */ - - /* receive window for capability selectors received at the server side */ - Receive_window server_rcv_window { }; + addr_t ec_sel = INVALID_INDEX; /* selector for execution context */ + addr_t exc_pt_sel = INVALID_INDEX; /* base of event portal window */ /* * Designated selector to populate with the result of an IPC call @@ -49,13 +45,19 @@ struct Genode::Native_thread */ addr_t client_rcv_sel = INVALID_INDEX; - void reset_client_rcv_sel() { client_rcv_sel = INVALID_INDEX; } + addr_t initial_ip = 0; + + /* receive window for capability selectors received at the server side */ + Receive_window server_rcv_window { }; Native_capability pager_cap { }; - Native_thread() : ec_sel(INVALID_INDEX), - exc_pt_sel(INVALID_INDEX), - initial_ip(0) { } + Native_thread() { } + + /* ec_sel is invalid until thread gets started */ + bool ec_valid() const { return ec_sel != INVALID_INDEX; } + + void reset_client_rcv_sel() { client_rcv_sel = INVALID_INDEX; } }; #endif /* _INCLUDE__NOVA__NATIVE_THREAD_H_ */ diff --git a/repos/base-nova/src/core/pager.cc b/repos/base-nova/src/core/pager.cc index 4ecc61667f..c7c410c525 100644 --- a/repos/base-nova/src/core/pager.cc +++ b/repos/base-nova/src/core/pager.cc @@ -569,13 +569,16 @@ void Exception_handlers::register_handler(Pager_object &obj, Mtd mtd, void (* __attribute__((regparm(1))) func)(Pager_object &)) { uint8_t res = !Nova::NOVA_OK; - with_pager_thread(obj.location(), platform_specific(), [&] (Pager_thread &pager_thread) { - addr_t const ec_sel = pager_thread.native_thread().ec_sel; + with_pager_thread(obj.location(), platform_specific(), [&] (Pager_thread &thread) { + thread.with_native_thread([&] (Native_thread &nt) { + addr_t const ec_sel = nt.ec_sel; - /* compiler generates instance of exception entry if not specified */ - addr_t entry = func ? (addr_t)func : (addr_t)(&_handler); - res = create_portal(obj.exc_pt_sel_client() + EV, - platform_specific().core_pd_sel(), ec_sel, mtd, entry, &obj); + /* compiler generates instance of exception entry if not specified */ + addr_t entry = func ? (addr_t)func : (addr_t)(&_handler); + res = create_portal(obj.exc_pt_sel_client() + EV, + platform_specific().core_pd_sel(), + ec_sel, mtd, entry, &obj); + }); }); if (res != Nova::NOVA_OK) @@ -644,13 +647,15 @@ void Pager_object::_construct_pager() uint8_t res = !Nova::NOVA_OK; with_pager_thread(_location, platform_specific(), [&] (Pager_thread &pager_thread) { + pager_thread.with_native_thread([&] (Native_thread &nt) { - addr_t const ec_sel = pager_thread.native_thread().ec_sel; + addr_t const ec_sel = nt.ec_sel; - /* create portal for final cleanup call used during destruction */ - res = create_portal(sel_pt_cleanup(), pd_sel, ec_sel, Mtd(0), - reinterpret_cast(_invoke_handler), - this); + /* create portal for final cleanup call used during destruction */ + res = create_portal(sel_pt_cleanup(), pd_sel, ec_sel, Mtd(0), + reinterpret_cast(_invoke_handler), + this); + }); }); if (res != Nova::NOVA_OK) { error("could not create pager cleanup portal, error=", res); @@ -872,8 +877,10 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, if (assert) { error("unknown OOM case - stop core pager thread"); - utcb.set_msg_word(0); - reply(myself.stack_top(), myself.native_thread().exc_pt_sel + Nova::SM_SEL_EC); + myself.with_native_thread([&] (Native_thread &nt) { + utcb.set_msg_word(0); + reply(myself.stack_top(), nt.exc_pt_sel + Nova::SM_SEL_EC); + }); } /* be strict in case of the -strict- STOP policy - stop causing thread */ @@ -892,8 +899,11 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, case SRC_PD_UNKNOWN: /* should not happen on Genode - we create and know every PD in core */ error("Unknown PD has insufficient kernel memory left - stop thread"); - utcb.set_msg_word(0); - reply(myself.stack_top(), myself.native_thread().exc_pt_sel + Nova::SM_SEL_EC); + myself.with_native_thread([&] (Native_thread &nt) { + utcb.set_msg_word(0); + reply(myself.stack_top(), nt.exc_pt_sel + Nova::SM_SEL_EC); + }); + break; case SRC_CORE_PD: /* core PD -> other PD, which has insufficient kernel resources */ @@ -943,13 +953,14 @@ addr_t Pager_object::create_oom_portal() { uint8_t res = !Nova::NOVA_OK; - with_pager_thread(_location, platform_specific(), - [&] (Pager_thread &thread) { + with_pager_thread(_location, platform_specific(), [&] (Pager_thread &thread) { + thread.with_native_thread([&] (Native_thread &nt) { addr_t const core_pd_sel = platform_specific().core_pd_sel(); - addr_t const ec_sel = thread.native_thread().ec_sel; + addr_t const ec_sel = nt.ec_sel; res = create_portal(sel_oom_portal(), core_pd_sel, ec_sel, Mtd(0), reinterpret_cast(_oom_handler), this); + }); }); if (res == Nova::NOVA_OK) diff --git a/repos/base-nova/src/core/thread_start.cc b/repos/base-nova/src/core/thread_start.cc index 78f7b8ab6c..9039d18c0a 100644 --- a/repos/base-nova/src/core/thread_start.cc +++ b/repos/base-nova/src/core/thread_start.cc @@ -30,51 +30,54 @@ using namespace Core; -void Thread::_init_platform_thread(size_t, Type type) +void Thread::_init_native_thread(Stack &stack, size_t, Type type) { + Native_thread &nt = stack.native_thread(); + /* * This function is called for constructing server activations and pager * objects. It allocates capability selectors for the thread's execution * context and a synchronization-helper semaphore needed for 'Lock'. */ - using namespace Nova; - if (type == MAIN) - { + if (type == MAIN) { + /* set EC selector according to NOVA spec */ - native_thread().ec_sel = platform_specific().core_pd_sel() + 1; + nt.ec_sel = platform_specific().core_pd_sel() + 1; /* * Exception base of first thread in core is 0. We have to set * it here so that Thread code finds the semaphore of the * main thread. */ - native_thread().exc_pt_sel = 0; - + nt.exc_pt_sel = 0; return; } - native_thread().ec_sel = cap_map().insert(1); - native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2); + + nt.ec_sel = cap_map().insert(1); + nt.exc_pt_sel = cap_map().insert(Nova::NUM_INITIAL_PT_LOG2); /* create running semaphore required for locking */ - addr_t rs_sel = native_thread().exc_pt_sel + SM_SEL_EC; - uint8_t res = create_sm(rs_sel, platform_specific().core_pd_sel(), 0); - if (res != NOVA_OK) + addr_t rs_sel = nt.exc_pt_sel + Nova::SM_SEL_EC; + uint8_t res = Nova::create_sm(rs_sel, platform_specific().core_pd_sel(), 0); + if (res != Nova::NOVA_OK) error("Thread::_init_platform_thread: create_sm returned ", res); } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { - unmap_local(Nova::Obj_crd(native_thread().ec_sel, 1)); - unmap_local(Nova::Obj_crd(native_thread().exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2)); + Native_thread &nt = stack.native_thread(); - cap_map().remove(native_thread().ec_sel, 1, false); - cap_map().remove(native_thread().exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2, false); + unmap_local(Nova::Obj_crd(nt.ec_sel, 1)); + unmap_local(Nova::Obj_crd(nt.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2)); + + cap_map().remove(nt.ec_sel, 1, false); + cap_map().remove(nt.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2, false); /* revoke utcb */ Nova::Rights rwx(true, true, true); - addr_t utcb = reinterpret_cast(&_stack->utcb()); + addr_t utcb = reinterpret_cast(&stack.utcb()); Nova::revoke(Nova::Mem_crd(utcb >> 12, 0, rwx)); } @@ -93,9 +96,11 @@ Thread::Start_result Thread::start() /* create local EC */ enum { LOCAL_THREAD = false }; unsigned const kernel_cpu_id = platform_specific().kernel_cpu_id(_affinity); - uint8_t res = create_ec(native_thread().ec_sel, - platform_specific().core_pd_sel(), kernel_cpu_id, - (mword_t)&utcb, sp, native_thread().exc_pt_sel, LOCAL_THREAD); + + uint8_t res { }; + with_native_thread([&] (Native_thread &nt) { + res = create_ec(nt.ec_sel, platform_specific().core_pd_sel(), kernel_cpu_id, + (mword_t)&utcb, sp, nt.exc_pt_sel, LOCAL_THREAD); }); if (res != NOVA_OK) { error("Thread::start: create_ec returned ", res); return Start_result::DENIED; @@ -109,10 +114,16 @@ Thread::Start_result Thread::start() if (i == SM_SEL_EC) continue; - if (map_local(platform_specific().core_pd_sel(), - *reinterpret_cast(Thread::myself()->utcb()), - Obj_crd(i, 0), - Obj_crd(native_thread().exc_pt_sel + i, 0))) { + bool page_fault_portal_ok = with_native_thread( + [&] (Native_thread &nt) { + return !map_local(platform_specific().core_pd_sel(), + *reinterpret_cast(Thread::myself()->utcb()), + Obj_crd(i, 0), + Obj_crd(nt.exc_pt_sel + i, 0)); + }, + [&] { return false; }); + + if (!page_fault_portal_ok) { error("Thread::start: failed to create page-fault portal"); return Start_result::DENIED; } @@ -131,9 +142,11 @@ Thread::Start_result Thread::start() { uint64_t ec_time = 0; - uint8_t res = Nova::ec_time(thread.native_thread().ec_sel, ec_time); - if (res != Nova::NOVA_OK) - warning("ec_time for core thread failed res=", res); + thread.with_native_thread([&] (Native_thread &nt) { + uint8_t res = Nova::ec_time(nt.ec_sel, ec_time); + if (res != Nova::NOVA_OK) + warning("ec_time for core thread failed res=", res); + }); return { Session_label("core"), thread.name(), Trace::Execution_time(ec_time, 0), thread._affinity }; diff --git a/repos/base-nova/src/include/base/internal/lock_helper.h b/repos/base-nova/src/include/base/internal/lock_helper.h index 58bbaf5379..566798aa3b 100644 --- a/repos/base-nova/src/include/base/internal/lock_helper.h +++ b/repos/base-nova/src/include/base/internal/lock_helper.h @@ -32,13 +32,22 @@ extern int main_thread_running_semaphore(); -static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) +static inline Genode::addr_t sm_sel_ec(Genode::Thread *thread_ptr) { - Genode::addr_t sem = thread_base ? - thread_base->native_thread().exc_pt_sel + Nova::SM_SEL_EC : - main_thread_running_semaphore(); + if (!thread_ptr) + return main_thread_running_semaphore(); - Nova::sm_ctrl(sem, Nova::SEMAPHORE_UP); + using namespace Genode; + + return thread_ptr->with_native_thread( + [&] (Native_thread &nt) { return nt.exc_pt_sel + Nova::SM_SEL_EC; }, + [&] { error("attempt to synchronize invalid thread"); return 0UL; }); +} + + +static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_ptr) +{ + Nova::sm_ctrl(sm_sel_ec(thread_ptr), Nova::SEMAPHORE_UP); return true; } @@ -48,16 +57,7 @@ static inline void thread_switch_to(Genode::Thread *) { } static inline void thread_stop_myself(Genode::Thread *myself) { - using namespace Genode; - using namespace Nova; - - addr_t sem; - if (myself) - sem = myself->native_thread().exc_pt_sel + SM_SEL_EC; - else - sem = main_thread_running_semaphore(); - - sm_ctrl(sem, SEMAPHORE_DOWNZERO); + Nova::sm_ctrl(sm_sel_ec(myself), Nova::SEMAPHORE_DOWNZERO); } #endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */ diff --git a/repos/base-nova/src/include/base/internal/spin_lock.h b/repos/base-nova/src/include/base/internal/spin_lock.h index 0ad7f70d93..d4025e845f 100644 --- a/repos/base-nova/src/include/base/internal/spin_lock.h +++ b/repos/base-nova/src/include/base/internal/spin_lock.h @@ -29,14 +29,28 @@ enum State { enum { RESERVED_BITS = 12, COUNTER_MASK = 0xFFC }; + +static inline Genode::addr_t ec_sel(Genode::Thread *thread_ptr) +{ + if (!thread_ptr) + return Nova::EC_SEL_THREAD; + + using namespace Genode; + + return thread_ptr->with_native_thread( + [&] (Native_thread &nt) { return nt.ec_sel; }, + [&] { error("failed to obtain ec_sel for invalid thread"); return 0UL; }); +} + + template static inline void spinlock_lock(volatile T *lock_variable) { using Genode::cmpxchg; Genode::Thread * myself = Genode::Thread::myself(); - T const tid = (T)(myself ? myself->native_thread().ec_sel - : (Genode::addr_t)Nova::EC_SEL_THREAD); + + T const tid = (T)ec_sel(myself); unsigned help_counter = 0; diff --git a/repos/base-nova/src/include/signal_source/client.h b/repos/base-nova/src/include/signal_source/client.h index ac64d000c8..691f0d6d89 100644 --- a/repos/base-nova/src/include/signal_source/client.h +++ b/repos/base-nova/src/include/signal_source/client.h @@ -54,11 +54,13 @@ namespace Genode { : Rpc_client(static_cap_cast(cap)) { /* request mapping of semaphore capability selector */ - Thread * myself = Thread::myself(); - auto const &exc_base = myself->native_thread().exc_pt_sel; - request_signal_sm_cap(exc_base + Nova::PT_SEL_PAGE_FAULT, - exc_base + Nova::SM_SEL_SIGNAL); - _sem = Capability_space::import(exc_base + Nova::SM_SEL_SIGNAL); + Thread &myself = *Thread::myself(); + myself.with_native_thread([&] (Native_thread &nt) { + auto const exc_base = nt.exc_pt_sel; + request_signal_sm_cap(exc_base + Nova::PT_SEL_PAGE_FAULT, + exc_base + Nova::SM_SEL_SIGNAL); + _sem = Capability_space::import(exc_base + Nova::SM_SEL_SIGNAL); + }); call(_sem); } diff --git a/repos/base-nova/src/lib/base/ipc.cc b/repos/base-nova/src/lib/base/ipc.cc index eb23dbce79..2054c5f6da 100644 --- a/repos/base-nova/src/lib/base/ipc.cc +++ b/repos/base-nova/src/lib/base/ipc.cc @@ -65,8 +65,15 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, * Determine manually defined selector for receiving the call result. * See the comment in 'base-nova/include/nova/native_thread.h'. */ - addr_t const manual_rcv_sel = myself ? myself->native_thread().client_rcv_sel - : Receive_window::INVALID_INDEX; + auto manual_rcv_sel_for_myself = [&] + { + addr_t sel = Receive_window::INVALID_INDEX; + if (myself) + myself->with_native_thread([&] (Native_thread &nt) { + sel = nt.client_rcv_sel; }); + return sel; + }; + addr_t const manual_rcv_sel = manual_rcv_sel_for_myself(); /* if we can't setup receive window, die in order to recognize the issue */ if (!rcv_window.prepare_rcv_window(utcb, manual_rcv_sel)) diff --git a/repos/base-nova/src/lib/base/rpc_entrypoint.cc b/repos/base-nova/src/lib/base/rpc_entrypoint.cc index eea468eac2..d8b91132b0 100644 --- a/repos/base-nova/src/lib/base/rpc_entrypoint.cc +++ b/repos/base-nova/src/lib/base/rpc_entrypoint.cc @@ -42,27 +42,29 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj) return obj->cap(); } - Untyped_capability ec_cap; + return with_native_thread( + [&] (Native_thread &nt) { - /* _ec_sel is invalid until thread gets started */ - if (native_thread().ec_sel != Native_thread::INVALID_INDEX) - ec_cap = Capability_space::import(native_thread().ec_sel); - else - ec_cap = Thread::cap(); + Untyped_capability const ec_cap = + nt.ec_valid() ? Capability_space::import(nt.ec_sel) : Thread::cap(); - Untyped_capability obj_cap = _alloc_rpc_cap(_pd_session, ec_cap, - (addr_t)&_activation_entry); - if (!obj_cap.valid()) - return obj_cap; + Untyped_capability const obj_cap = + _alloc_rpc_cap(_pd_session, ec_cap, (addr_t)&_activation_entry); - /* add server object to object pool */ - obj->cap(obj_cap); - insert(obj); + if (!obj_cap.valid()) + return Untyped_capability(); - /* return object capability managed by entrypoint thread */ - return obj_cap; + /* add server object to object pool */ + obj->cap(obj_cap); + insert(obj); + + /* return object capability managed by entrypoint thread */ + return obj_cap; + }, + [&] { return Untyped_capability(); }); } + static void cleanup_call(Rpc_object_base *obj, Nova::Utcb * ep_utcb, Native_capability &cap) { @@ -129,52 +131,54 @@ void Rpc_entrypoint::_activation_entry() Rpc_entrypoint &ep = *static_cast(Thread::myself()); Nova::Utcb &utcb = *(Nova::Utcb *)Thread::myself()->utcb(); - Receive_window &rcv_window = ep.native_thread().server_rcv_window; - rcv_window.post_ipc(utcb); + ep.with_native_thread([&] (Native_thread &nt) { + Receive_window &rcv_window = nt.server_rcv_window; + rcv_window.post_ipc(utcb); - /* handle ill-formed message */ - if (utcb.msg_words() < 2) { - ep._rcv_buf.word(0) = ~0UL; /* invalid opcode */ - } else { - copy_utcb_to_msgbuf(utcb, rcv_window, ep._rcv_buf); - } + /* handle ill-formed message */ + if (utcb.msg_words() < 2) { + ep._rcv_buf.word(0) = ~0UL; /* invalid opcode */ + } else { + copy_utcb_to_msgbuf(utcb, rcv_window, ep._rcv_buf); + } - Ipc_unmarshaller unmarshaller(ep._rcv_buf); + Ipc_unmarshaller unmarshaller(ep._rcv_buf); - Rpc_opcode opcode(0); - unmarshaller.extract(opcode); + Rpc_opcode opcode(0); + unmarshaller.extract(opcode); - /* default return value */ - Rpc_exception_code exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT); + /* default return value */ + Rpc_exception_code exc = Rpc_exception_code(Rpc_exception_code::INVALID_OBJECT); - /* in case of a portal cleanup call we are done here - just reply */ - if (ep._cap.local_name() == (long)id_pt) { - if (!rcv_window.prepare_rcv_window(utcb)) + /* in case of a portal cleanup call we are done here - just reply */ + if (ep._cap.local_name() == (long)id_pt) { + if (!rcv_window.prepare_rcv_window(utcb)) + warning("out of capability selectors for handling server requests"); + + ep._rcv_buf.reset(); + reply(utcb, exc, ep._snd_buf); + } + + /* atomically lookup and lock referenced object */ + auto lambda = [&] (Rpc_object_base *obj) + { + if (!obj) { + error("could not look up server object, return from call id_pt=", id_pt); + return; + } + + /* dispatch request */ + ep._snd_buf.reset(); + exc = obj->dispatch(opcode, unmarshaller, ep._snd_buf); + }; + ep.apply(id_pt, lambda); + + if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)ep.utcb())) warning("out of capability selectors for handling server requests"); ep._rcv_buf.reset(); reply(utcb, exc, ep._snd_buf); - } - - /* atomically lookup and lock referenced object */ - auto lambda = [&] (Rpc_object_base *obj) - { - if (!obj) { - error("could not look up server object, return from call id_pt=", id_pt); - return; - } - - /* dispatch request */ - ep._snd_buf.reset(); - exc = obj->dispatch(opcode, unmarshaller, ep._snd_buf); - }; - ep.apply(id_pt, lambda); - - if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)ep.utcb())) - warning("out of capability selectors for handling server requests"); - - ep._rcv_buf.reset(); - reply(utcb, exc, ep._snd_buf); + }); } @@ -202,28 +206,33 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size, _pd_session(*pd_session) { /* set magic value evaluated by thread_nova.cc to start a local thread */ - if (native_thread().ec_sel == Native_thread::INVALID_INDEX) { - native_thread().ec_sel = Native_thread::INVALID_INDEX - 1; - native_thread().initial_ip = (addr_t)&_activation_entry; - } + with_native_thread([&] (Native_thread &nt) { + if (nt.ec_valid()) + return; + + nt.ec_sel = Native_thread::INVALID_INDEX - 1; + nt.initial_ip = (addr_t)&_activation_entry; + }); /* required to create a 'local' EC */ Thread::start(); /* create cleanup portal */ - _cap = _alloc_rpc_cap(_pd_session, - Capability_space::import(native_thread().ec_sel), - (addr_t)_activation_entry); + with_native_thread([&] (Native_thread &nt) { + _cap = _alloc_rpc_cap(_pd_session, Capability_space::import(nt.ec_sel), + (addr_t)_activation_entry); }); if (!_cap.valid()) { error("failed to allocate RPC cap for new entrypoint"); return; } - Receive_window &rcv_window = Thread::native_thread().server_rcv_window; + with_native_thread([&] (Native_thread &nt) { + Receive_window &rcv_window = nt.server_rcv_window; - /* prepare portal receive window of new thread */ - if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb())) - error("failed to prepare receive window for RPC entrypoint"); + /* prepare portal receive window of new thread */ + if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb())) + error("failed to prepare receive window for RPC entrypoint"); + }); } diff --git a/repos/base-nova/src/lib/base/thread_start.cc b/repos/base-nova/src/lib/base/thread_start.cc index 964aa23a9b..bf3dac9102 100644 --- a/repos/base-nova/src/lib/base/thread_start.cc +++ b/repos/base-nova/src/lib/base/thread_start.cc @@ -55,8 +55,6 @@ static Thread_capability main_thread_cap(Thread_capability main_cap = { }) */ void Thread::_thread_start() { - using namespace Genode; - /* catch any exception at this point and try to print an error message */ try { Thread::myself()->entry(); @@ -83,24 +81,23 @@ void Thread::_thread_start() ** Thread base ** *****************/ -void Thread::_init_platform_thread(size_t weight, Type type) +void Thread::_init_native_thread(Stack &stack, size_t weight, Type type) { - using namespace Nova; + Native_thread &nt = stack.native_thread(); /* * Allocate capability selectors for the thread's execution context, * running semaphore and exception handler portals. */ - native_thread().ec_sel = Native_thread::INVALID_INDEX; /* for main threads the member initialization differs */ if (type == MAIN) { _thread_cap = main_thread_cap(); - native_thread().exc_pt_sel = 0; - native_thread().ec_sel = Nova::EC_SEL_THREAD; + nt.exc_pt_sel = 0; + nt.ec_sel = Nova::EC_SEL_THREAD; - request_native_ec_cap(PT_SEL_PAGE_FAULT, native_thread().ec_sel); + request_native_ec_cap(Nova::PT_SEL_PAGE_FAULT, nt.ec_sel); return; } @@ -113,12 +110,12 @@ void Thread::_init_platform_thread(size_t weight, Type type) * 'Cpu_session::kill_thread()' and is not able to revoke the UTCB * afterwards. */ - Rights rwx(true, true, true); - addr_t utcb = reinterpret_cast(&_stack->utcb()); - revoke(Mem_crd(utcb >> 12, 0, rwx)); + Nova::Rights rwx(true, true, true); + addr_t utcb = reinterpret_cast(&stack.utcb()); + Nova::revoke(Nova::Mem_crd(utcb >> 12, 0, rwx)); - native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2); - if (native_thread().exc_pt_sel == Native_thread::INVALID_INDEX) { + nt.exc_pt_sel = cap_map().insert(Nova::NUM_INITIAL_PT_LOG2); + if (nt.exc_pt_sel == Native_thread::INVALID_INDEX) { error("failed allocate exception-portal selector for new thread"); return; } @@ -134,88 +131,87 @@ void Thread::_init_platform_thread(size_t weight, Type type) } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { - using namespace Nova; + Native_thread &nt = stack.native_thread(); - if (native_thread().ec_sel != Native_thread::INVALID_INDEX) { - revoke(Obj_crd(native_thread().ec_sel, 0)); - } + if (nt.ec_valid()) + Nova::revoke(Nova::Obj_crd(nt.ec_sel, 0)); /* de-announce thread */ _thread_cap.with_result( [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, [&] (Cpu_session::Create_thread_error) { }); - cap_map().remove(native_thread().exc_pt_sel, NUM_INITIAL_PT_LOG2); + cap_map().remove(nt.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2); } Thread::Start_result Thread::start() { - if (native_thread().ec_sel < Native_thread::INVALID_INDEX - 1) { - error("Thread::start failed due to invalid exception portal selector"); - return Start_result::DENIED; - } + return with_native_thread([&] (Native_thread &nt) { - if (_thread_cap.failed()) - return Start_result::DENIED; + if (nt.ec_sel < Native_thread::INVALID_INDEX - 1) { + error("Thread::start failed due to invalid exception portal selector"); + return Start_result::DENIED; + } - /* - * Default: create global thread - ec.sel == INVALID_INDEX - * create local thread - ec.sel == INVALID_INDEX - 1 - */ - bool global = native_thread().ec_sel == Native_thread::INVALID_INDEX; + if (_thread_cap.failed()) + return Start_result::DENIED; - using namespace Genode; + /* + * Default: create global thread - ec.sel == INVALID_INDEX + * create local thread - ec.sel == INVALID_INDEX - 1 + */ + bool global = nt.ec_sel == Native_thread::INVALID_INDEX; - /* create EC at core */ + /* create EC at core */ - try { - Cpu_session::Native_cpu::Thread_type thread_type; + try { + Cpu_session::Native_cpu::Thread_type thread_type; + + if (global) + thread_type = Cpu_session::Native_cpu::Thread_type::GLOBAL; + else + thread_type = Cpu_session::Native_cpu::Thread_type::LOCAL; + + Cpu_session::Native_cpu::Exception_base exception_base { nt.exc_pt_sel }; + + Nova_native_cpu_client native_cpu(_cpu_session->native_cpu()); + native_cpu.thread_type(cap(), thread_type, exception_base); + } catch (...) { + error("Thread::start failed to set thread type"); + return Start_result::DENIED; + } + + /* local thread have no start instruction pointer - set via portal entry */ + addr_t thread_ip = global ? reinterpret_cast(_thread_start) : nt.initial_ip; + + Cpu_thread_client cpu_thread(cap()); + cpu_thread.start(thread_ip, _stack->top()); + + /* request native EC thread cap */ + nt.ec_sel = nt.exc_pt_sel + Nova::EC_SEL_THREAD; + + /* + * Requested ec cap that is used for recall and + * creation of portals (Native_pd::alloc_rpc_cap). + */ + request_native_ec_cap(nt.exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, + nt.ec_sel); + + /* default: we don't accept any mappings or translations */ + Nova::Utcb &utcb = *(Nova::Utcb *)Thread::utcb(); + utcb.crd_rcv = Nova::Obj_crd(); + utcb.crd_xlt = Nova::Obj_crd(); if (global) - thread_type = Cpu_session::Native_cpu::Thread_type::GLOBAL; - else - thread_type = Cpu_session::Native_cpu::Thread_type::LOCAL; + /* request creation of SC to let thread run*/ + cpu_thread.resume(); - Cpu_session::Native_cpu::Exception_base exception_base { native_thread().exc_pt_sel }; + return Start_result::OK; - Nova_native_cpu_client native_cpu(_cpu_session->native_cpu()); - native_cpu.thread_type(cap(), thread_type, exception_base); - } catch (...) { - error("Thread::start failed to set thread type"); - return Start_result::DENIED; - } - - /* local thread have no start instruction pointer - set via portal entry */ - addr_t thread_ip = global ? reinterpret_cast(_thread_start) : native_thread().initial_ip; - - Cpu_thread_client cpu_thread(cap()); - cpu_thread.start(thread_ip, _stack->top()); - - /* request native EC thread cap */ - native_thread().ec_sel = native_thread().exc_pt_sel + Nova::EC_SEL_THREAD; - - /* - * Requested ec cap that is used for recall and - * creation of portals (Native_pd::alloc_rpc_cap). - */ - request_native_ec_cap(native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, - native_thread().ec_sel); - - using namespace Nova; - - /* default: we don't accept any mappings or translations */ - Utcb * utcb_obj = reinterpret_cast(utcb()); - utcb_obj->crd_rcv = Obj_crd(); - utcb_obj->crd_xlt = Obj_crd(); - - if (global) - /* request creation of SC to let thread run*/ - cpu_thread.resume(); - - return Start_result::OK; + }, [&] { return Start_result::DENIED; }); } diff --git a/repos/base-nova/src/lib/base/vm.cc b/repos/base-nova/src/lib/base/vm.cc index 6f57fba4ea..f5c3e0f038 100644 --- a/repos/base-nova/src/lib/base/vm.cc +++ b/repos/base-nova/src/lib/base/vm.cc @@ -655,12 +655,13 @@ void Nova_vcpu::with_state(auto const &fn) static void nova_reply(Thread &myself, Nova::Utcb &utcb, auto &&... args) { - Receive_window &rcv_window = myself.native_thread().server_rcv_window; + myself.with_native_thread([&] (Native_thread &nt) { - /* reset receive window to values expected by RPC server code */ - rcv_window.prepare_rcv_window(utcb); + /* reset receive window to values expected by RPC server code */ + nt.server_rcv_window.prepare_rcv_window(utcb); - Nova::reply(myself.stack_top(), args...); + Nova::reply(myself.stack_top(), args...); + }); } @@ -697,19 +698,23 @@ Signal_context_capability Nova_vcpu::_create_exit_handler(Pd_session &pd, uint16_t exit_reason, Nova::Mtd mtd) { - Thread *tep = reinterpret_cast(&handler.rpc_ep()); + Thread *ep = reinterpret_cast(&handler.rpc_ep()); - Native_capability thread_cap = Capability_space::import(tep->native_thread().ec_sel); + return ep->with_native_thread([&] (Native_thread &nt) { - Nova_native_pd_client native_pd { pd.native_pd() }; + Native_capability thread_cap = Capability_space::import(nt.ec_sel); - Native_capability vm_exit_cap = - native_pd.alloc_rpc_cap(thread_cap, (addr_t)Nova_vcpu::_exit_entry, mtd.value()); + Nova_native_pd_client native_pd { pd.native_pd() }; - Badge const badge { vcpu_id, exit_reason }; - native_pd.imprint_rpc_cap(vm_exit_cap, badge.value()); + Native_capability vm_exit_cap = + native_pd.alloc_rpc_cap(thread_cap, (addr_t)Nova_vcpu::_exit_entry, mtd.value()); - return reinterpret_cap_cast(vm_exit_cap); + Badge const badge { vcpu_id, exit_reason }; + native_pd.imprint_rpc_cap(vm_exit_cap, badge.value()); + + return reinterpret_cap_cast(vm_exit_cap); + + }, [&] { return Signal_context_capability(); }); } diff --git a/repos/base-nova/src/test/nova/main.cc b/repos/base-nova/src/test/nova/main.cc index 060b5ce4c3..09a71cde80 100644 --- a/repos/base-nova/src/test/nova/main.cc +++ b/repos/base-nova/src/test/nova/main.cc @@ -227,8 +227,9 @@ void test_revoke(Genode::Env &env) * as used before by copy_session_cap */ Genode::Thread * myself = Genode::Thread::myself(); - request_native_ec_cap(myself->native_thread().exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, - copy_session_cap.local_name()); + myself->with_native_thread([&] (Native_thread &nt) { + request_native_ec_cap(nt.exc_pt_sel + Nova::PT_SEL_PAGE_FAULT, + copy_session_cap.local_name()); }); /* check whether the requested cap before is valid and placed well */ crd_ses = Nova::Obj_crd(copy_session_cap.local_name(), 0); @@ -319,33 +320,37 @@ void test_pat(Genode::Env &env) touch_read_write(reinterpret_cast( memory + offset)); } + Nova::Rights const all(true, true, true); + /* * Establish memory mapping with evilly wrong mapping attributes */ Nova_native_pd_client native_pd { env.pd().native_pd() }; Thread * thread = reinterpret_cast(&ep); - Native_capability const thread_cap - = Capability_space::import(thread->native_thread().ec_sel); - Untyped_capability const pt = - native_pd.alloc_rpc_cap(thread_cap, (addr_t)portal_entry, 0 /* MTD */); + thread->with_native_thread([&] (Native_thread &nt) { - Nova::Rights const all(true, true, true); - Nova::Mem_crd const rcv_crd(memory_remap >> PAGE_4K, DS_ORDER, all); - Nova::Mem_crd const snd_crd(memory_wc >> PAGE_4K, DS_ORDER, all); - Nova::Crd const old_crd = utcb.crd_rcv; + Native_capability const thread_cap = Capability_space::import(nt.ec_sel); - utcb.crd_rcv = rcv_crd; - utcb.set_msg_word(1); - utcb.msg()[0] = snd_crd.value(); + Untyped_capability const pt = + native_pd.alloc_rpc_cap(thread_cap, (addr_t)portal_entry, 0 /* MTD */); - uint8_t const res = Nova::call(pt.local_name()); - utcb.crd_rcv = old_crd; + Nova::Mem_crd const rcv_crd(memory_remap >> PAGE_4K, DS_ORDER, all); + Nova::Mem_crd const snd_crd(memory_wc >> PAGE_4K, DS_ORDER, all); + Nova::Crd const old_crd = utcb.crd_rcv; - if (res != Nova::NOVA_OK) { - Genode::error("establishing memory failed ", res); - failed++; - } + utcb.crd_rcv = rcv_crd; + utcb.set_msg_word(1); + utcb.msg()[0] = snd_crd.value(); + + uint8_t const res = Nova::call(pt.local_name()); + utcb.crd_rcv = old_crd; + + if (res != Nova::NOVA_OK) { + Genode::error("establishing memory failed ", res); + failed++; + } + }); /* sanity check - touch re-mapped area */ for (auto offset = 0; offset < DS_SIZE; offset += (1 << PAGE_4K)) @@ -488,20 +493,23 @@ class Pager : private Genode::Thread { touch_read(reinterpret_cast(_ds_mem)); /* request creation of a 'local' EC */ - Thread::native_thread().ec_sel = Native_thread::INVALID_INDEX - 1; - Thread::start(); + with_native_thread([&] (Native_thread &nt) { - Genode::warning("pager: created"); + nt.ec_sel = Native_thread::INVALID_INDEX - 1; - Native_capability thread_cap = - Capability_space::import(Thread::native_thread().ec_sel); + Thread::start(); - Genode::Nova_native_pd_client native_pd(env.pd().native_pd()); - Nova::Mtd mtd (Nova::Mtd::QUAL | Nova::Mtd::EIP | Nova::Mtd::ESP); - Genode::addr_t entry = reinterpret_cast(page_fault); + Genode::warning("pager: created"); - _call_to_map = native_pd.alloc_rpc_cap(thread_cap, entry, - mtd.value()); + Native_capability thread_cap = Capability_space::import(nt.ec_sel); + + Genode::Nova_native_pd_client native_pd(env.pd().native_pd()); + Nova::Mtd mtd (Nova::Mtd::QUAL | Nova::Mtd::EIP | Nova::Mtd::ESP); + Genode::addr_t entry = reinterpret_cast(page_fault); + + _call_to_map = native_pd.alloc_rpc_cap(thread_cap, entry, + mtd.value()); + }); } Native_capability call_to_map() { return _call_to_map; } @@ -700,11 +708,14 @@ Main::Main(Env &env) : env(env) }; addr_t sel_pd = cap_map().insert(); - addr_t sel_ec = myself->native_thread().ec_sel; + addr_t sel_ec = Native_thread::INVALID_INDEX; addr_t sel_cap = cap_map().insert(); addr_t handler = 0UL; uint8_t res = 0; + myself->with_native_thread([&] (Native_thread &nt) { + sel_ec = nt.ec_sel; }); + Nova::Mtd mtd(Nova::Mtd::ALL); if (sel_cap == ~0UL || sel_ec == ~0UL || sel_cap == ~0UL) { @@ -721,9 +732,10 @@ Main::Main(Env &env) : env(env) /* changing the badge of one of the portal must fail */ for (unsigned i = 0; i < (1U << Nova::NUM_INITIAL_PT_LOG2); i++) { - addr_t sel_exc = myself->native_thread().exc_pt_sel + i; - res = Nova::pt_ctrl(sel_exc, 0xbadbad); - check(res, "pt_ctrl ", i); + myself->with_native_thread([&] (Native_thread &nt) { + res = Nova::pt_ctrl(nt.exc_pt_sel + i, 0xbadbad); + check(res, "pt_ctrl ", i); + }); } /* test PAT kernel feature */ diff --git a/repos/base-nova/src/timer/nova/main.cc b/repos/base-nova/src/timer/nova/main.cc index dea30c022a..a72e925060 100644 --- a/repos/base-nova/src/timer/nova/main.cc +++ b/repos/base-nova/src/timer/nova/main.cc @@ -104,7 +104,9 @@ class Timer::Device static Sel init_signal_sem(Thread &thread) { - auto const exc_base = thread.native_thread().exc_pt_sel; + addr_t exc_base = Native_thread::INVALID_INDEX; + thread.with_native_thread([&] (Native_thread &nt) { + exc_base = nt.exc_pt_sel; }); request_signal_sm_cap(exc_base + Nova::PT_SEL_PAGE_FAULT, exc_base + Nova::SM_SEL_SIGNAL); diff --git a/repos/base-okl4/src/core/pager.cc b/repos/base-okl4/src/core/pager.cc index 148bb1003c..a079f7998d 100644 --- a/repos/base-okl4/src/core/pager.cc +++ b/repos/base-okl4/src/core/pager.cc @@ -144,7 +144,9 @@ void Ipc_pager::acknowledge_wakeup() Untyped_capability Pager_entrypoint::_pager_object_cap(unsigned long badge) { - return Capability_space::import(native_thread().l4id, Rpc_obj_key(badge)); + return with_native_thread( + [&] (Native_thread &nt) { return Capability_space::import(nt.l4id, Rpc_obj_key(badge)); }, + [&] { return Untyped_capability(); }); } diff --git a/repos/base-okl4/src/core/thread_start.cc b/repos/base-okl4/src/core/thread_start.cc index ec27f499e1..57df1a6d5c 100644 --- a/repos/base-okl4/src/core/thread_start.cc +++ b/repos/base-okl4/src/core/thread_start.cc @@ -35,18 +35,19 @@ void Thread::_thread_start() Thread::Start_result Thread::start() { - /* create and start platform thread */ - native_thread().pt = new (Core::platform_specific().thread_slab()) - Core::Platform_thread(Core::platform_specific().core_pd(), _stack->name().string()); - - native_thread().pt->start((void *)_thread_start, stack_top()); + with_native_thread([&] (Native_thread &nt) { + nt.pt = new (Core::platform_specific().thread_slab()) + Core::Platform_thread(Core::platform_specific().core_pd(), + _stack->name().string()); + nt.pt->start((void *)_thread_start, stack_top()); + }); return Start_result::OK; } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { /* destruct platform thread */ - destroy(Core::platform_specific().thread_slab(), native_thread().pt); + destroy(Core::platform_specific().thread_slab(), stack.native_thread().pt); } diff --git a/repos/base-okl4/src/include/base/internal/lock_helper.h b/repos/base-okl4/src/include/base/internal/lock_helper.h index 00bdd5462a..d8103affad 100644 --- a/repos/base-okl4/src/include/base/internal/lock_helper.h +++ b/repos/base-okl4/src/include/base/internal/lock_helper.h @@ -33,6 +33,18 @@ static inline void thread_yield() { Okl4::L4_Yield(); } extern Okl4::L4_ThreadId_t main_thread_tid; + +static inline Okl4::L4_ThreadId_t okl4_tid(Genode::Thread *thread_ptr) +{ + if (!thread_ptr) + return main_thread_tid; + + return thread_ptr->with_native_thread( + [&] (Genode::Native_thread &nt) { return nt.l4id; }, + [&] { return Okl4::L4_ThreadId_t { }; }); +} + + /** * Custom ExchangeRegisters wrapper for waking up a thread * @@ -42,20 +54,17 @@ extern Okl4::L4_ThreadId_t main_thread_tid; * * \return true if the thread was in blocking state */ -static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) +static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_ptr) { using namespace Okl4; - L4_Word_t dummy; - L4_ThreadId_t dummy_id; + L4_Word_t dummy; + L4_ThreadId_t dummy_id; L4_ThreadState_t state; - Okl4::L4_ThreadId_t tid = thread_base ? - thread_base->native_thread().l4id : - main_thread_tid; - - L4_ExchangeRegisters(tid, L4_ExReg_Resume + L4_ExReg_AbortIPC, 0, 0, 0, - 0, L4_nilthread, &state.raw, &dummy, &dummy, &dummy, + L4_ExchangeRegisters(okl4_tid(thread_ptr), + L4_ExReg_Resume + L4_ExReg_AbortIPC, 0, 0, 0, 0, + L4_nilthread, &state.raw, &dummy, &dummy, &dummy, &dummy, &dummy_id); return L4_ThreadWasHalted(state); @@ -65,24 +74,18 @@ static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) /** * Yield CPU time to the specified thread */ -static inline void thread_switch_to(Genode::Thread *thread_base) +static inline void thread_switch_to(Genode::Thread *thread_ptr) { - Okl4::L4_ThreadId_t tid = thread_base ? - thread_base->native_thread().l4id : - main_thread_tid; - Okl4::L4_ThreadSwitch(tid); + Okl4::L4_ThreadSwitch(okl4_tid(thread_ptr)); } /** * Unconditionally block the calling thread */ -static inline void thread_stop_myself(Genode::Thread *myself) +static inline void thread_stop_myself(Genode::Thread *thread_ptr) { - Okl4::L4_ThreadId_t tid = myself ? - myself->native_thread().l4id : - main_thread_tid; - Okl4::L4_Stop(tid); + Okl4::L4_Stop(okl4_tid(thread_ptr)); } #endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */ diff --git a/repos/base-okl4/src/include/base/internal/native_thread.h b/repos/base-okl4/src/include/base/internal/native_thread.h index bd9c0668f0..d6d5894c7f 100644 --- a/repos/base-okl4/src/include/base/internal/native_thread.h +++ b/repos/base-okl4/src/include/base/internal/native_thread.h @@ -15,6 +15,7 @@ #define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ /* Genode includes */ +#include #include /* base-internal includes */ @@ -22,22 +23,24 @@ namespace Core { class Platform_thread; } - namespace Genode { struct Native_thread; } -struct Genode::Native_thread +struct Genode::Native_thread : Noncopyable { - Okl4::L4_ThreadId_t l4id; + Okl4::L4_ThreadId_t l4id { }; /** * Only used in core * - * For 'Thread' objects created within core, 'pt' points to - * the physical thread object, which is going to be destroyed - * on destruction of the 'Thread'. + * For 'Thread' objects created within core, 'pt' points to the physical + * thread object, which is going to be destroyed on destruction of the + * 'Thread'. */ - Core::Platform_thread *pt; + + struct { Core::Platform_thread *pt = nullptr; }; + + Native_thread() { } }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */ diff --git a/repos/base-okl4/src/lib/base/thread_bootstrap.cc b/repos/base-okl4/src/lib/base/thread_bootstrap.cc index aa01bd65b1..eaf006189e 100644 --- a/repos/base-okl4/src/lib/base/thread_bootstrap.cc +++ b/repos/base-okl4/src/lib/base/thread_bootstrap.cc @@ -17,10 +17,10 @@ #include /* base-internal includes */ -#include #include #include #include +#include using namespace Genode; @@ -81,16 +81,17 @@ void Genode::prepare_init_main_thread() void Thread::_thread_bootstrap() { - native_thread().l4id.raw = Okl4::copy_uregister_to_utcb(); + with_native_thread([&] (Native_thread &nt) { + nt.l4id.raw = Okl4::copy_uregister_to_utcb(); }); } -void Thread::_init_platform_thread(size_t, Type type) +void Thread::_init_native_thread(Stack &stack, size_t, Type type) { if (type == NORMAL) return; - native_thread().l4id.raw = main_thread_tid.raw; + stack.native_thread().l4id.raw = main_thread_tid.raw; _thread_cap = main_thread_cap(); } diff --git a/repos/base-pistachio/src/core/pager.cc b/repos/base-pistachio/src/core/pager.cc index 1fd1bb210b..b8ea10a9fc 100644 --- a/repos/base-pistachio/src/core/pager.cc +++ b/repos/base-pistachio/src/core/pager.cc @@ -130,7 +130,9 @@ void Ipc_pager::acknowledge_wakeup() Untyped_capability Pager_entrypoint::_pager_object_cap(unsigned long badge) { - return Capability_space::import(native_thread().l4id, Rpc_obj_key(badge)); + return with_native_thread( + [&] (Native_thread &nt) { return Capability_space::import(nt.l4id, Rpc_obj_key(badge)); }, + [&] { return Untyped_capability(); }); } diff --git a/repos/base-pistachio/src/core/thread_start.cc b/repos/base-pistachio/src/core/thread_start.cc index 6232548265..283cd4ab79 100644 --- a/repos/base-pistachio/src/core/thread_start.cc +++ b/repos/base-pistachio/src/core/thread_start.cc @@ -36,21 +36,22 @@ void Thread::_thread_start() Thread::Start_result Thread::start() { - /* create and start platform thread */ - native_thread().pt = new (platform().core_mem_alloc()) - Platform_thread(platform_specific().core_pd(), _stack->name().string()); + return with_native_thread( + [&] (Native_thread &nt) { + nt.pt = new (platform().core_mem_alloc()) + 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(); + nt.pt->pager(platform_specific().core_pager()); + nt.l4id = nt.pt->native_thread_id(); - native_thread().pt->start((void *)_thread_start, stack_top()); - - return Start_result::OK; + nt.pt->start((void *)_thread_start, stack_top()); + return Start_result::OK; + }, + [&] { return Start_result::DENIED; }); } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { - /* destruct platform thread */ - destroy(platform().core_mem_alloc(), native_thread().pt); + destroy(platform().core_mem_alloc(), stack.native_thread().pt); } diff --git a/repos/base-pistachio/src/include/base/internal/lock_helper.h b/repos/base-pistachio/src/include/base/internal/lock_helper.h index d1fa78ed49..07c08ad494 100644 --- a/repos/base-pistachio/src/include/base/internal/lock_helper.h +++ b/repos/base-pistachio/src/include/base/internal/lock_helper.h @@ -33,6 +33,17 @@ extern Pistachio::L4_ThreadId_t main_thread_tid; static inline void thread_yield() { Pistachio::L4_Yield(); } +static inline Pistachio::L4_ThreadId_t pistachio_tid(Genode::Thread *thread_ptr) +{ + if (!thread_ptr) + return main_thread_tid; + + return thread_ptr->with_native_thread( + [&] (Genode::Native_thread &nt) { return nt.l4id; }, + [&] { return Pistachio::L4_ThreadId_t { }; }); +} + + /** * Custom ExchangeRegisters wrapper for waking up a thread * @@ -42,21 +53,17 @@ static inline void thread_yield() { Pistachio::L4_Yield(); } * * \return true if the thread was in blocking state */ -static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) +static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_ptr) { using namespace Pistachio; - L4_Word_t dummy; - L4_ThreadId_t dummy_id; + L4_Word_t dummy; + L4_ThreadId_t dummy_id; L4_ThreadState_t state; - Pistachio::L4_ThreadId_t tid = thread_base ? - thread_base->native_thread().l4id : - main_thread_tid; - enum { RESUME = 1 << 8, CANCEL_IPC = 3 << 1 }; - L4_ExchangeRegisters(tid, RESUME | CANCEL_IPC, 0, 0, 0, - 0, L4_nilthread, &state.raw, &dummy, &dummy, &dummy, + L4_ExchangeRegisters(pistachio_tid(thread_ptr), RESUME | CANCEL_IPC, 0, 0, 0, 0, + L4_nilthread, &state.raw, &dummy, &dummy, &dummy, &dummy, &dummy_id); return L4_ThreadWasHalted(state); @@ -66,24 +73,18 @@ static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) /** * Yield CPU time to the specified thread */ -static inline void thread_switch_to(Genode::Thread *thread_base) +static inline void thread_switch_to(Genode::Thread *thread_ptr) { - Pistachio::L4_ThreadId_t tid = thread_base ? - thread_base->native_thread().l4id : - main_thread_tid; - Pistachio::L4_ThreadSwitch(tid); + Pistachio::L4_ThreadSwitch(pistachio_tid(thread_ptr)); } /** * Unconditionally block the calling thread */ -static inline void thread_stop_myself(Genode::Thread *myself) +static inline void thread_stop_myself(Genode::Thread *thread_ptr) { - Pistachio::L4_ThreadId_t tid = myself ? - myself->native_thread().l4id : - main_thread_tid; - Pistachio::L4_Stop(tid); + Pistachio::L4_Stop(pistachio_tid(thread_ptr)); } #endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */ diff --git a/repos/base-pistachio/src/include/base/internal/native_thread.h b/repos/base-pistachio/src/include/base/internal/native_thread.h index d867c9ede5..5ff33f59a0 100644 --- a/repos/base-pistachio/src/include/base/internal/native_thread.h +++ b/repos/base-pistachio/src/include/base/internal/native_thread.h @@ -15,6 +15,7 @@ #define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ /* Genode includes */ +#include #include /* base-internal includes */ @@ -25,9 +26,9 @@ namespace Genode { struct Native_thread; } namespace Core { class Platform_thread; } -struct Genode::Native_thread +struct Genode::Native_thread : Noncopyable { - Pistachio::L4_ThreadId_t l4id; + Pistachio::L4_ThreadId_t l4id { }; /** * Only used in core @@ -36,7 +37,9 @@ struct Genode::Native_thread * the physical thread object, which is going to be destroyed * on destruction of the 'Thread'. */ - Core::Platform_thread *pt; + struct { Core::Platform_thread *pt = nullptr; }; + + Native_thread() { } }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */ diff --git a/repos/base-pistachio/src/lib/base/thread_bootstrap.cc b/repos/base-pistachio/src/lib/base/thread_bootstrap.cc index 36d74dcec8..496336b6e7 100644 --- a/repos/base-pistachio/src/lib/base/thread_bootstrap.cc +++ b/repos/base-pistachio/src/lib/base/thread_bootstrap.cc @@ -16,7 +16,7 @@ #include /* base-internal includes */ -#include +#include #include #include @@ -49,16 +49,17 @@ void Genode::prepare_init_main_thread() void Genode::Thread::_thread_bootstrap() { - native_thread().l4id = Pistachio::L4_Myself(); + with_native_thread([&] (Native_thread &nt) { + nt.l4id = Pistachio::L4_Myself(); }); } -void Genode::Thread::_init_platform_thread(size_t, Type type) +void Genode::Thread::_init_native_thread(Stack &stack, size_t, Type type) { if (type == NORMAL) return; - native_thread().l4id = main_thread_tid; + stack.native_thread().l4id = main_thread_tid; _thread_cap = main_thread_cap(); } diff --git a/repos/base-sel4/src/core/capability_space.cc b/repos/base-sel4/src/core/capability_space.cc index f13085c187..4f4c041f20 100644 --- a/repos/base-sel4/src/core/capability_space.cc +++ b/repos/base-sel4/src/core/capability_space.cc @@ -123,16 +123,19 @@ Capability_space::create_rpc_obj_cap(Native_capability ep_cap, Native_capability Capability_space::create_ep_cap(Thread &ep_thread) { - Cap_sel const ep_sel(ep_thread.native_thread().ep_sel); + return ep_thread.with_native_thread( + [&] (Native_thread &nt) { + Cap_sel const ep_sel(nt.attr.ep_sel); - /* entrypoint capabilities are not allocated from a PD session */ - Pd_session const *pd_session = nullptr; + /* entrypoint capabilities are not allocated from a PD session */ + Pd_session const *pd_session = nullptr; - Native_capability::Data &data = - local_capability_space().create_capability(ep_sel, pd_session, - Rpc_obj_key()); - - return Native_capability(&data); + Native_capability::Data &data = + local_capability_space().create_capability(ep_sel, pd_session, + Rpc_obj_key()); + return Native_capability(&data); + }, + [&] { return Native_capability(); }); } diff --git a/repos/base-sel4/src/core/pager.cc b/repos/base-sel4/src/core/pager.cc index f2eded3b7c..f6827c44ea 100644 --- a/repos/base-sel4/src/core/pager.cc +++ b/repos/base-sel4/src/core/pager.cc @@ -65,19 +65,19 @@ void Ipc_pager::reply_and_wait_for_fault() { seL4_Word badge = Rpc_obj_key::INVALID; - seL4_MessageInfo_t page_fault_msg_info; + seL4_MessageInfo_t page_fault_msg_info { }; - if (_badge) { + Thread::myself()->with_native_thread([&] (Native_thread &nt) { - seL4_MessageInfo_t const reply_msg = seL4_MessageInfo_new(0, 0, 0, 0); + if (_badge) { + seL4_MessageInfo_t const reply_msg = seL4_MessageInfo_new(0, 0, 0, 0); - page_fault_msg_info = - seL4_ReplyRecv(Thread::myself()->native_thread().ep_sel, reply_msg, &badge); + page_fault_msg_info = seL4_ReplyRecv(nt.attr.ep_sel, reply_msg, &badge); - } else { - page_fault_msg_info = - seL4_Recv(Thread::myself()->native_thread().ep_sel, &badge); - } + } else { + page_fault_msg_info = seL4_Recv(nt.attr.ep_sel, &badge); + } + }); Fault_info const fault_info(page_fault_msg_info); diff --git a/repos/base-sel4/src/core/thread_start.cc b/repos/base-sel4/src/core/thread_start.cc index 4d4deca40c..2b83f446c2 100644 --- a/repos/base-sel4/src/core/thread_start.cc +++ b/repos/base-sel4/src/core/thread_start.cc @@ -30,13 +30,15 @@ using namespace Core; -void Thread::_init_platform_thread(size_t, Type type) +void Thread::_init_native_thread(Stack &stack, size_t, Type type) { - Utcb_virt const utcb_virt { (addr_t)&_stack->utcb() }; + Native_thread &nt = stack.native_thread(); + + Utcb_virt const utcb_virt { (addr_t)&stack.utcb() }; if (type == MAIN) { - native_thread().tcb_sel = seL4_CapInitThreadTCB; - native_thread().lock_sel = INITIAL_SEL_LOCK; + nt.attr.tcb_sel = seL4_CapInitThreadTCB; + nt.attr.lock_sel = INITIAL_SEL_LOCK; return; } @@ -49,15 +51,15 @@ void Thread::_init_platform_thread(size_t, Type type) "local=%", Hex(utcb_virt.addr)); } - native_thread().tcb_sel = thread_info.tcb_sel.value(); - native_thread().ep_sel = thread_info.ep_sel.value(); - native_thread().lock_sel = thread_info.lock_sel.value(); + nt.attr.tcb_sel = thread_info.tcb_sel.value(); + nt.attr.ep_sel = thread_info.ep_sel.value(); + nt.attr.lock_sel = thread_info.lock_sel.value(); Platform &platform = platform_specific(); seL4_CNode_CapData guard = seL4_CNode_CapData_new(0, CONFIG_WORD_SIZE - 32); seL4_CNode_CapData no_cap_data = { { 0 } }; - int const ret = seL4_TCB_SetSpace(native_thread().tcb_sel, 0, + int const ret = seL4_TCB_SetSpace(nt.attr.tcb_sel, 0, platform.top_cnode().sel().value(), guard.words[0], seL4_CapInitThreadPD, no_cap_data.words[0]); @@ -69,24 +71,24 @@ void Thread::_init_platform_thread(size_t, Type type) platform.core_cnode().mint(platform.core_cnode(), unbadged_sel, lock_sel); - native_thread().lock_sel = lock_sel.value(); + nt.attr.lock_sel = lock_sel.value(); } -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &stack) { - addr_t const utcb_virt_addr = (addr_t)&_stack->utcb(); + addr_t const utcb_virt_addr = (addr_t)&stack.utcb(); bool ret = unmap_local(utcb_virt_addr, 1); ASSERT(ret); int res = seL4_CNode_Delete(seL4_CapInitThreadCNode, - native_thread().lock_sel, 32); + stack.native_thread().attr.lock_sel, 32); if (res) error(__PRETTY_FUNCTION__, ": seL4_CNode_Delete (", - Hex(native_thread().lock_sel), ") returned ", res); + Hex(stack.native_thread().attr.lock_sel), ") returned ", res); - platform_specific().core_sel_alloc().free(Cap_sel(native_thread().lock_sel)); + platform_specific().core_sel_alloc().free(Cap_sel(stack.native_thread().attr.lock_sel)); } @@ -99,13 +101,7 @@ void Thread::_thread_start() } -Thread::Start_result Thread::start() -{ - /* write ipcbuffer address to 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())); +namespace { struct Core_trace_source : public Core::Trace::Source::Info_accessor, private Core::Trace::Control, @@ -123,14 +119,15 @@ Thread::Start_result Thread::start() seL4_IPCBuffer &ipc_buffer = *reinterpret_cast(myself.utcb()); uint64_t const * const buf = reinterpret_cast(ipc_buffer.msg); - seL4_BenchmarkGetThreadUtilisation(_thread.native_thread().tcb_sel); + _thread.with_native_thread([&] (Native_thread &nt) { + seL4_BenchmarkGetThreadUtilisation(nt.attr.tcb_sel); }); + uint64_t const thread_time = buf[BENCHMARK_TCB_UTILISATION]; return { Session_label("core"), _thread.name(), - Trace::Execution_time(thread_time, 0), _thread._affinity }; + Genode::Trace::Execution_time(thread_time, 0), _thread.affinity() }; } - Core_trace_source(Core::Trace::Source_registry ®istry, Thread &t) : Core::Trace::Control(), @@ -139,9 +136,26 @@ Thread::Start_result Thread::start() registry.insert(this); } }; +} - new (platform().core_mem_alloc()) - Core_trace_source(Core::Trace::sources(), *this); + +Thread::Start_result Thread::start() +{ + if (!_stack) + return Start_result::DENIED; + + Stack &stack = *_stack; + + /* write ipcbuffer address to utcb*/ + utcb()->ipcbuffer(Native_utcb::Virt { addr_t(utcb()) }); + + start_sel4_thread(Cap_sel(stack.native_thread().attr.tcb_sel), + (addr_t)&_thread_start, stack.top(), + _affinity.xpos(), addr_t(utcb())); + try { + new (platform().core_mem_alloc()) + Core_trace_source(Core::Trace::sources(), *this); + } catch (...) { } return Start_result::OK; } diff --git a/repos/base-sel4/src/include/base/internal/kernel_debugger.h b/repos/base-sel4/src/include/base/internal/kernel_debugger.h index 3c1d2e6334..36e17a5679 100644 --- a/repos/base-sel4/src/include/base/internal/kernel_debugger.h +++ b/repos/base-sel4/src/include/base/internal/kernel_debugger.h @@ -32,7 +32,8 @@ static inline void kernel_debugger_panic(char const *msg) { kernel_debugger_outstring(msg); kernel_debugger_outstring("\n"); - seL4_TCB_Suspend(Genode::Thread::myself()->native_thread().tcb_sel); + Genode::Thread::myself()->with_native_thread([&] (Genode::Native_thread &nt) { + seL4_TCB_Suspend(nt.attr.tcb_sel); }); } #endif /* _INCLUDE__BASE__INTERNAL__KERNEL_DEBUGGER_H_ */ diff --git a/repos/base-sel4/src/include/base/internal/lock_helper.h b/repos/base-sel4/src/include/base/internal/lock_helper.h index ebbbc4295e..0225c6d88e 100644 --- a/repos/base-sel4/src/include/base/internal/lock_helper.h +++ b/repos/base-sel4/src/include/base/internal/lock_helper.h @@ -31,28 +31,28 @@ static inline void thread_switch_to(Genode::Thread *) } -static inline bool thread_check_stopped_and_restart(Genode::Thread *thread) +static inline unsigned sel4_lock_sel(Genode::Thread *thread_ptr) { - unsigned lock_sel = Genode::INITIAL_SEL_LOCK; /* main thread */ + if (!thread_ptr) + return Genode::INITIAL_SEL_LOCK; /* main thread */ - if (thread) - lock_sel = thread->native_thread().lock_sel; + return thread_ptr->with_native_thread( + [&] (Genode::Native_thread &nt) { return nt.attr.lock_sel; }, + [&] () -> unsigned { return Genode::INITIAL_SEL_LOCK; }); +} - seL4_Signal(lock_sel); +static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_ptr) +{ + seL4_Signal(sel4_lock_sel(thread_ptr)); return true; } -static inline void thread_stop_myself(Genode::Thread *myself) +static inline void thread_stop_myself(Genode::Thread *myself_ptr) { - unsigned lock_sel = Genode::INITIAL_SEL_LOCK; /* main thread */ - - if (myself) - lock_sel = myself->native_thread().lock_sel; - seL4_Word sender = ~0U; - seL4_Wait(lock_sel, &sender); + seL4_Wait(sel4_lock_sel(myself_ptr), &sender); } #endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */ diff --git a/repos/base-sel4/src/include/base/internal/native_thread.h b/repos/base-sel4/src/include/base/internal/native_thread.h index 8c32dd7907..26598be2e7 100644 --- a/repos/base-sel4/src/include/base/internal/native_thread.h +++ b/repos/base-sel4/src/include/base/internal/native_thread.h @@ -14,16 +14,17 @@ #ifndef _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ #define _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ +#include #include namespace Genode { struct Native_thread; } -struct Genode::Native_thread + +struct Genode::Native_thread : Noncopyable { - unsigned tcb_sel = 0; - unsigned ep_sel = 0; - unsigned rcv_sel = 0; - unsigned lock_sel = 0; + struct Attr { unsigned tcb_sel, ep_sel, rcv_sel, lock_sel; } attr { }; + + Native_thread() { } }; #endif /* _INCLUDE__BASE__INTERNAL__NATIVE_THREAD_H_ */ diff --git a/repos/base-sel4/src/lib/base/capability_space.cc b/repos/base-sel4/src/lib/base/capability_space.cc index a7705a398e..6249cd7b07 100644 --- a/repos/base-sel4/src/lib/base/capability_space.cc +++ b/repos/base-sel4/src/lib/base/capability_space.cc @@ -95,11 +95,15 @@ namespace { Native_capability Capability_space::create_ep_cap(Thread &ep_thread) { - Cap_sel const ep_sel = Cap_sel(ep_thread.native_thread().ep_sel); + return ep_thread.with_native_thread( + [&] (Native_thread &nt) { + Cap_sel const ep_sel = Cap_sel(nt.attr.ep_sel); - Native_capability::Data *data = - &local_capability_space().create_capability(ep_sel, Rpc_obj_key()); - return Native_capability(data); + Native_capability::Data *data = + &local_capability_space().create_capability(ep_sel, Rpc_obj_key()); + return Native_capability(data); + }, + [&] { return Native_capability(); }); } diff --git a/repos/base-sel4/src/lib/base/ipc.cc b/repos/base-sel4/src/lib/base/ipc.cc index f4c79cf5a1..717411aacc 100644 --- a/repos/base-sel4/src/lib/base/ipc.cc +++ b/repos/base-sel4/src/lib/base/ipc.cc @@ -39,10 +39,17 @@ enum { }; +static unsigned &main_rcv_sel() +{ + static unsigned _main_rcv_sel = Capability_space::alloc_rcv_sel(); + return _main_rcv_sel; +} + + /** - * Return reference to receive selector of the calling thread + * Call 'fn' with a reference to the receive selector of the calling thread */ -static unsigned &rcv_sel() +static void with_rcv_sel_ref(auto const &fn) { /* * When the function is called at the very early initialization phase, we @@ -50,12 +57,21 @@ static unsigned &rcv_sel() * Thread object of the main thread does not exist yet. During this * phase, we return a reference to the 'main_rcv_sel' variable. */ - if (Thread::myself()) { - return Thread::myself()->native_thread().rcv_sel; - } + Thread * const myself_ptr = Thread::myself(); + if (!myself_ptr) + fn(main_rcv_sel()); + else + myself_ptr->with_native_thread( + [&] (Native_thread &nt) { fn(nt.attr.rcv_sel); }, + [&] { ASSERT(false); /* thread w/o stack cannot execute */ }); +} - static unsigned main_rcv_sel = Capability_space::alloc_rcv_sel(); - return main_rcv_sel; + +static void allocate_and_define_rcv_sel() +{ + with_rcv_sel_ref([&] (unsigned &rcv_sel) { + if (!rcv_sel) + rcv_sel = Capability_space::alloc_rcv_sel(); }); } @@ -253,34 +269,37 @@ static void decode_seL4_message(seL4_MessageInfo_t const &msg_info, Native_capability arg_cap = Capability_space::lookup(rpc_obj_key); - if (arg_cap.valid()) { + with_rcv_sel_ref([&] (unsigned &rcv_sel_ref) { - /* - * Discard the received selector and keep using the already - * present one. - * - * XXX We'd need to find out if both the received and the - * looked-up selector refer to the same endpoint. - * Unfortunaltely, seL4 lacks such a comparison operation. - */ + if (arg_cap.valid()) { - Capability_space::reset_sel(rcv_sel()); + /* + * Discard the received selector and keep using the already + * present one. + * + * XXX We'd need to find out if both the received and the + * looked-up selector refer to the same endpoint. + * Unfortunaltely, seL4 lacks such a comparison operation. + */ - dst_msg.insert(arg_cap); + Capability_space::reset_sel(rcv_sel_ref); - } else { + dst_msg.insert(arg_cap); - Capability_space::Ipc_cap_data const - ipc_cap_data(rpc_obj_key, rcv_sel()); + } else { - dst_msg.insert(Capability_space::import(ipc_cap_data)); + Capability_space::Ipc_cap_data const + ipc_cap_data(rpc_obj_key, rcv_sel_ref); - /* - * Since we keep using the received selector, we need to - * allocate a fresh one for the next incoming delegation. - */ - rcv_sel() = Capability_space::alloc_rcv_sel(); - } + dst_msg.insert(Capability_space::import(ipc_cap_data)); + + /* + * Since we keep using the received selector, we need to + * allocate a fresh one for the next incoming delegation. + */ + rcv_sel_ref = Capability_space::alloc_rcv_sel(); + } + }); } curr_sel4_cap_idx++; } @@ -300,9 +319,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, kernel_debugger_panic("IPC destination is invalid"); } - /* allocate and define receive selector */ - if (!rcv_sel()) - rcv_sel() = Capability_space::alloc_rcv_sel(); + allocate_and_define_rcv_sel(); rcv_msg.reset(); @@ -330,9 +347,7 @@ Rpc_exception_code Genode::ipc_call(Native_capability dst, void Genode::ipc_reply(Native_capability, Rpc_exception_code exc, Msgbuf_base &snd_msg) { - /* allocate and define receive selector */ - if (!rcv_sel()) - rcv_sel() = Capability_space::alloc_rcv_sel(); + allocate_and_define_rcv_sel(); /** * Do not use Genode primitives after this point until the return which may @@ -352,29 +367,30 @@ Genode::Rpc_request Genode::ipc_reply_wait(Reply_capability const &, Msgbuf_base &reply_msg, Msgbuf_base &request_msg) { - /* allocate and define receive selector */ - if (!rcv_sel()) - rcv_sel() = Capability_space::alloc_rcv_sel(); + allocate_and_define_rcv_sel(); - seL4_CPtr const dest = Thread::myself()->native_thread().ep_sel; seL4_Word badge = 0; - if (exc.value == Rpc_exception_code::INVALID_OBJECT) - reply_msg.reset(); + Thread::myself()->with_native_thread([&] (Native_thread &nt) { - request_msg.reset(); + seL4_CPtr const dest = nt.attr.ep_sel; - /** - * Do not use Genode primitives after this point until the return which may - * alter the content of the IPCBuffer, e.g. Lock or RPC. - */ + if (exc.value == Rpc_exception_code::INVALID_OBJECT) + reply_msg.reset(); - seL4_MessageInfo_t const reply_msg_info = new_seL4_message(reply_msg); - seL4_SetMR(MR_IDX_EXC_CODE, exc.value); - seL4_MessageInfo_t const req = seL4_ReplyRecv(dest, reply_msg_info, &badge); + request_msg.reset(); - decode_seL4_message(req, request_msg); + /** + * Do not use Genode primitives after this point until the return which may + * alter the content of the IPCBuffer, e.g. Lock or RPC. + */ + seL4_MessageInfo_t const reply_msg_info = new_seL4_message(reply_msg); + seL4_SetMR(MR_IDX_EXC_CODE, exc.value); + seL4_MessageInfo_t const req = seL4_ReplyRecv(dest, reply_msg_info, &badge); + + decode_seL4_message(req, request_msg); + }); return Rpc_request(Native_capability(), badge); } diff --git a/repos/base-sel4/src/lib/base/thread_bootstrap.cc b/repos/base-sel4/src/lib/base/thread_bootstrap.cc index 035b612d58..af3c9ccc82 100644 --- a/repos/base-sel4/src/lib/base/thread_bootstrap.cc +++ b/repos/base-sel4/src/lib/base/thread_bootstrap.cc @@ -31,12 +31,14 @@ void Genode::prepare_init_main_thread() { } ** Thread ** ************/ -void Genode::Thread::_thread_bootstrap() +void Genode::Thread::_thread_bootstrap() { - if (native_thread().ep_sel == 0) { - native_thread().ep_sel = (unsigned)_stack->utcb().ep_sel(); - native_thread().lock_sel = (unsigned)_stack->utcb().lock_sel(); - } + with_native_thread([&] (Native_thread &nt) { + if (nt.attr.ep_sel == 0) { + nt.attr.ep_sel = (unsigned)_stack->utcb().ep_sel(); + nt.attr.lock_sel = (unsigned)_stack->utcb().lock_sel(); + } + }); } diff --git a/repos/base-sel4/src/lib/base/thread_init.cc b/repos/base-sel4/src/lib/base/thread_init.cc index 1da467661a..aba78aa634 100644 --- a/repos/base-sel4/src/lib/base/thread_init.cc +++ b/repos/base-sel4/src/lib/base/thread_init.cc @@ -13,22 +13,20 @@ /* Genode includes */ #include -#include +#include #include using namespace Genode; -void Thread::_init_platform_thread(size_t, Type type) +void Thread::_init_native_thread(Stack &stack, size_t, Type type) { - /** + /* * Reset to default values. The default values trigger initial allocations * and associations the thread, like IPCbuffer in ipc.cc. */ - native_thread() = Native_thread(); + stack.native_thread().attr = { }; - if (type == MAIN) { - native_thread().lock_sel = INITIAL_SEL_LOCK; - return; - } + if (type == MAIN) + stack.native_thread().attr.lock_sel = INITIAL_SEL_LOCK; } diff --git a/repos/base/include/base/thread.h b/repos/base/include/base/thread.h index 0ae686895d..8ee6395bec 100644 --- a/repos/base/include/base/thread.h +++ b/repos/base/include/base/thread.h @@ -84,7 +84,7 @@ class Genode::Thread /** * Hook for platform-specific destructor supplements */ - void _deinit_platform_thread(); + void _deinit_native_thread(Stack &); /* * Noncopyable @@ -125,7 +125,7 @@ class Genode::Thread /** * Pointer to kernel-specific meta data */ - Native_thread *_native_thread = nullptr; + Native_thread *_native_thread_ptr = nullptr; /** * Blockade used for synchronizing the finalization of the thread @@ -163,7 +163,7 @@ class Genode::Thread * \param weight weighting regarding the CPU session quota * \param type enables selection of special initialization */ - void _init_platform_thread(size_t weight, Type type); + void _init_native_thread(Stack &, size_t weight, Type type); void _init_cpu_session_and_trace_control(); @@ -330,9 +330,26 @@ class Genode::Thread } /** - * Return kernel-specific thread meta data + * Call 'fn' with kernel-specific 'Native_thread &' as argument, + * or 'invalid_fn' if the thread has not been successfully constructed */ - Native_thread &native_thread(); + auto with_native_thread(auto const &fn, + auto const &invalid_fn) const -> decltype(invalid_fn()) + { + if (_native_thread_ptr) { + Native_thread &native_thread = *_native_thread_ptr; + return fn(native_thread); + } + return invalid_fn(); + } + + /** + * Conditionally call 'fn' with kernel-specific 'Native_thread &' + */ + void with_native_thread(auto const &fn) const + { + with_native_thread(fn, [&] { }); + } /** * Return top of primary stack diff --git a/repos/base/src/lib/base/thread.cc b/repos/base/src/lib/base/thread.cc index b8ebd7d83b..dd6916642e 100644 --- a/repos/base/src/lib/base/thread.cc +++ b/repos/base/src/lib/base/thread.cc @@ -201,11 +201,6 @@ void Thread::free_secondary_stack(void* stack_addr) } -Native_thread &Thread::native_thread() { - - return _stack->native_thread(); } - - void *Thread::stack_top() const { return (void *)_stack->top(); } @@ -250,7 +245,8 @@ Thread::Thread(size_t weight, const char *name, size_t stack_size, _trace_control(nullptr), _stack(_alloc_stack(stack_size, name, type == MAIN)) { - _init_platform_thread(weight, type); + _native_thread_ptr = &_stack->native_thread(); + _init_native_thread(*_stack, weight, type); } @@ -308,7 +304,8 @@ Thread::~Thread() sleep_forever(); } - _deinit_platform_thread(); + _deinit_native_thread(*_stack); + _free_stack(_stack); cxx_free_tls(this); diff --git a/repos/base/src/lib/base/thread_start.cc b/repos/base/src/lib/base/thread_start.cc index 5b6d619850..5c1e6148ee 100644 --- a/repos/base/src/lib/base/thread_start.cc +++ b/repos/base/src/lib/base/thread_start.cc @@ -64,7 +64,7 @@ void Thread::_thread_start() ** Thread ** ************/ -void Thread::_deinit_platform_thread() +void Thread::_deinit_native_thread(Stack &) { if (!_cpu_session) { error("Thread::_cpu_session unexpectedly not defined"); @@ -81,8 +81,13 @@ Thread::Start_result Thread::start() { _init_cpu_session_and_trace_control(); + if (!_stack) + return Start_result::DENIED; + + Stack &stack = *_stack; + /* create thread at core */ - addr_t const utcb = (addr_t)&_stack->utcb(); + addr_t const utcb = (addr_t)&stack.utcb(); _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), _affinity, Weight(), utcb); @@ -90,7 +95,7 @@ Thread::Start_result Thread::start() [&] (Thread_capability cap) { /* start execution at initial instruction pointer and stack pointer */ - Cpu_thread_client(cap).start((addr_t)_thread_start, _stack->top()); + Cpu_thread_client(cap).start((addr_t)_thread_start, stack.top()); return Start_result::OK; }, [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; }); diff --git a/repos/ports/include/vmm/vcpu_dispatcher.h b/repos/ports/include/vmm/vcpu_dispatcher.h index 73d6103c58..a213ac7407 100644 --- a/repos/ports/include/vmm/vcpu_dispatcher.h +++ b/repos/ports/include/vmm/vcpu_dispatcher.h @@ -79,7 +79,9 @@ class Vmm::Vcpu_dispatcher : public T using namespace Genode; /* request creation of a 'local' EC */ - T::native_thread().ec_sel = Native_thread::INVALID_INDEX - 1; + T::with_native_thread([&] (Native_thread &nt) { + nt.ec_sel = Native_thread::INVALID_INDEX - 1; }); + T::start(); } @@ -95,25 +97,32 @@ class Vmm::Vcpu_dispatcher : public T */ void (*entry)() = &_portal_entry; - /* create the portal at the desired selector index (EV) */ - Native_capability thread_cap = - Capability_space::import(T::native_thread().ec_sel); + Untyped_capability handler { }; - Untyped_capability handler = - retry( - [&] () { - /* manually define selector used for RPC result */ - Thread::myself()->native_thread().client_rcv_sel = exc_base + EV; - return _native_pd.alloc_rpc_cap(thread_cap, (addr_t)entry, - mtd.value()); - }, - [&] () { - Thread::myself()->native_thread().reset_client_rcv_sel(); - _env.parent().upgrade(Parent::Env::pd(), "ram_quota=16K"); - }); + T::with_native_thread([&] (Native_thread &nt) { - /* revert selector allocation to automatic mode of operation */ - Thread::myself()->native_thread().reset_client_rcv_sel(); + /* create the portal at the desired selector index (EV) */ + Native_capability thread_cap = + Capability_space::import(nt.ec_sel); + + Thread::myself()->with_native_thread([&] (Native_thread &myself_nt) { + + handler = retry( + [&] () { + /* manually define selector used for RPC result */ + myself_nt.client_rcv_sel = exc_base + EV; + return _native_pd.alloc_rpc_cap(thread_cap, (addr_t)entry, + mtd.value()); + }, + [&] () { + myself_nt.reset_client_rcv_sel(); + _env.parent().upgrade(Parent::Env::pd(), "ram_quota=16K"); + }); + + /* revert selector allocation to automatic mode of operation */ + myself_nt.reset_client_rcv_sel(); + }); + }); return handler.valid() && (exc_base + EV == (addr_t)handler.local_name()); } diff --git a/repos/ports/include/vmm/vcpu_thread.h b/repos/ports/include/vmm/vcpu_thread.h index 9d2353e252..cc19fcfdd3 100644 --- a/repos/ports/include/vmm/vcpu_thread.h +++ b/repos/ports/include/vmm/vcpu_thread.h @@ -112,9 +112,9 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread * Translate vcpu_vm thread cap via current executing thread, * which is used to lookup current PD to delegate VM-exit portals. */ - addr_t const current = Thread::myself()->native_thread().exc_pt_sel - + Nova::PT_SEL_PAGE_FAULT; - translate_remote_pager(current, vcpu_vm.local_name()); + Thread::myself()->with_native_thread([&] (Native_thread &nt) { + addr_t const current = nt.exc_pt_sel + Nova::PT_SEL_PAGE_FAULT; + translate_remote_pager(current, vcpu_vm.local_name()); }); /* start vCPU in separate PD */ cpu_thread.start(0, 0); diff --git a/repos/ports/src/virtualbox5/spec/nova/sup.cc b/repos/ports/src/virtualbox5/spec/nova/sup.cc index aaa7b98bd0..040b830328 100644 --- a/repos/ports/src/virtualbox5/spec/nova/sup.cc +++ b/repos/ports/src/virtualbox5/spec/nova/sup.cc @@ -725,10 +725,14 @@ void genode_update_tsc(void (*update_func)(void), Genode::uint64_t update_us) Trace::Timestamp wakeup_absolute = Trace::timestamp(); /* initialize first time in context of running thread */ - auto const &exc_base = Thread::myself()->native_thread().exc_pt_sel; - request_signal_sm_cap(exc_base + Nova::PT_SEL_PAGE_FAULT, - exc_base + Nova::SM_SEL_SIGNAL); - Genode::addr_t const sem = exc_base + SM_SEL_SIGNAL; + Genode::addr_t const sem = Thread::myself()->with_native_thread( + [&] (Native_thread &nt) { + auto const &exc_base = nt.exc_pt_sel; + request_signal_sm_cap(exc_base + Nova::PT_SEL_PAGE_FAULT, + exc_base + Nova::SM_SEL_SIGNAL); + return exc_base + SM_SEL_SIGNAL; + }, + [&] () -> Genode::addr_t { return Native_thread::INVALID_INDEX; }); for (;;) { update_func();