diff --git a/repos/base-hw/src/core/kernel/ipc_node.cc b/repos/base-hw/src/core/kernel/ipc_node.cc index 59f59f6d44..ade00fad04 100644 --- a/repos/base-hw/src/core/kernel/ipc_node.cc +++ b/repos/base-hw/src/core/kernel/ipc_node.cc @@ -19,74 +19,16 @@ #include /* core includes */ -#include #include -#include #include #include using namespace Kernel; -static inline void free_obj_id_ref(Pd &pd, void *ptr) -{ - pd.platform_pd().capability_slab().free(ptr, sizeof(Object_identity_reference)); -} - - -void Ipc_node::copy_msg(Ipc_node &sender) -{ - using namespace Genode; - using Reference = Object_identity_reference; - - /* copy payload and set destination capability id */ - *_utcb = *sender._utcb; - _utcb->destination(sender._capid); - - /* translate capabilities */ - for (unsigned i = 0; i < _rcv_caps; i++) { - - capid_t id = sender._utcb->cap_get(i); - - /* if there is no capability to send, just free the pre-allocation */ - if (i >= sender._utcb->cap_cnt()) { - free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); - continue; - } - - /* lookup the capability id within the caller's cap space */ - Reference *oir = (id == cap_id_invalid()) - ? nullptr : sender.pd().cap_tree().find(id); - - /* if the caller's capability is invalid, free the pre-allocation */ - if (!oir) { - _utcb->cap_add(cap_id_invalid()); - free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); - continue; - } - - /* lookup the capability id within the callee's cap space */ - Reference *dst_oir = oir->find(pd()); - - /* if it is not found, and the target is not core, create a reference */ - if (!dst_oir && (&pd() != &core_pd())) { - dst_oir = oir->factory(_obj_id_ref_ptr[i], pd()); - if (!dst_oir) - free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); - } else /* otherwise free the pre-allocation */ - free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); - - if (dst_oir) dst_oir->add_to_utcb(); - - /* add the translated capability id to the target buffer */ - _utcb->cap_add(dst_oir ? dst_oir->capid() : cap_id_invalid()); - } -} - - void Ipc_node::_receive_request(Ipc_node &caller) { - copy_msg(caller); + _thread.ipc_copy_msg(caller._thread); _caller = &caller; _state = INACTIVE; } @@ -94,9 +36,9 @@ void Ipc_node::_receive_request(Ipc_node &caller) void Ipc_node::_receive_reply(Ipc_node &callee) { - copy_msg(callee); + _thread.ipc_copy_msg(callee._thread); _state = INACTIVE; - _send_request_succeeded(); + _thread.ipc_send_request_succeeded(); } @@ -105,7 +47,7 @@ void Ipc_node::_announce_request(Ipc_node &node) /* directly receive request if we've awaited it */ if (_state == AWAIT_REQUEST) { _receive_request(node); - _await_request_succeeded(); + _thread.ipc_await_request_succeeded(); return; } @@ -152,40 +94,24 @@ void Ipc_node::_outbuf_request_cancelled() _callee = nullptr; _state = INACTIVE; - _send_request_failed(); + _thread.ipc_send_request_failed(); } bool Ipc_node::_helps_outbuf_dst() { return (_state == AWAIT_REPLY) && _help; } -void Ipc_node::_init(Genode::Native_utcb &utcb, Ipc_node &starter) +bool Ipc_node::can_send_request() { - _utcb = &utcb; - _rcv_caps = starter._utcb->cap_cnt(); - Genode::Allocator &slab = pd().platform_pd().capability_slab(); - for (unsigned i = 0; i < _rcv_caps; i++) - _obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference)); - copy_msg(starter); + return _state == INACTIVE; } -void Ipc_node::send_request(Ipc_node &callee, capid_t capid, bool help, - unsigned rcv_caps) +void Ipc_node::send_request(Ipc_node &callee, bool help) { - if (_state != INACTIVE) { - Genode::raw("IPC send request: bad state"); - return; - } - Genode::Allocator &slab = pd().platform_pd().capability_slab(); - for (unsigned i = 0; i < rcv_caps; i++) - _obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference)); - _state = AWAIT_REPLY; _callee = &callee; - _capid = capid; _help = false; - _rcv_caps = rcv_caps; /* announce request */ _callee->_announce_request(*this); @@ -198,18 +124,14 @@ Ipc_node * Ipc_node::helping_sink() { return _helps_outbuf_dst() ? _callee->helping_sink() : this; } -bool Ipc_node::await_request(unsigned rcv_caps) +bool Ipc_node::can_await_request() { - if (_state != INACTIVE) { - Genode::raw("IPC await request: bad state"); - return true; - } - Genode::Allocator &slab = pd().platform_pd().capability_slab(); - for (unsigned i = 0; i < rcv_caps; i++) - _obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference)); + return _state == INACTIVE; +} - _rcv_caps = rcv_caps; +bool Ipc_node::await_request() +{ /* if no request announced then wait */ bool announced = false; _state = AWAIT_REQUEST; @@ -239,11 +161,11 @@ void Ipc_node::cancel_waiting() case AWAIT_REPLY: _cancel_outbuf_request(); _state = INACTIVE; - _send_request_failed(); + _thread.ipc_send_request_failed(); break; case AWAIT_REQUEST: _state = INACTIVE; - _await_request_failed(); + _thread.ipc_await_request_failed(); break; return; default: return; @@ -251,6 +173,12 @@ void Ipc_node::cancel_waiting() } +Ipc_node::Ipc_node(Thread &thread) +: + _thread(thread) +{ } + + Ipc_node::~Ipc_node() { _cancel_request_queue(); diff --git a/repos/base-hw/src/core/kernel/ipc_node.h b/repos/base-hw/src/core/kernel/ipc_node.h index 135546d208..cb31f35096 100644 --- a/repos/base-hw/src/core/kernel/ipc_node.h +++ b/repos/base-hw/src/core/kernel/ipc_node.h @@ -15,18 +15,14 @@ #ifndef _CORE__KERNEL__IPC_NODE_H_ #define _CORE__KERNEL__IPC_NODE_H_ -/* base-local includes */ -#include - -/* core includes */ -#include -#include +/* Genode includes */ +#include namespace Genode { class Msgbuf_base; }; namespace Kernel { - class Pd; + class Thread; /** * Backend for end points of synchronous interprocess communication @@ -47,27 +43,19 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element AWAIT_REQUEST = 3, }; - void _init(Genode::Native_utcb &utcb, Ipc_node &callee); private: friend class Core_thread; friend class Genode::Fifo; - State _state = INACTIVE; - capid_t _capid = cap_id_invalid(); - Ipc_node * _caller = nullptr; - Ipc_node * _callee = nullptr; - bool _help = false; - size_t _rcv_caps = 0; /* max capability num to receive */ - Genode::Native_utcb * _utcb = nullptr; + Thread &_thread; + State _state { INACTIVE }; + Ipc_node * _caller { nullptr }; + Ipc_node * _callee { nullptr }; + bool _help { false }; Ipc_node_queue _request_queue { }; - /* pre-allocation array for obkject identity references */ - void * _obj_id_ref_ptr[Genode::Msgbuf_base::MAX_CAPS_PER_MSG]; - - inline void copy_msg(Ipc_node &sender); - /** * Buffer next request from request queue in 'r' to handle it */ @@ -114,40 +102,26 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element bool _helps_outbuf_dst(); /** - * IPC node returned from waiting due to reply receipt + * Make the class noncopyable because it has pointer members */ - virtual void _send_request_succeeded() = 0; + Ipc_node(const Ipc_node&) = delete; /** - * IPC node returned from waiting due to reply cancellation + * Make the class noncopyable because it has pointer members */ - virtual void _send_request_failed() = 0; - - /** - * IPC node returned from waiting due to request receipt - */ - virtual void _await_request_succeeded() = 0; - - /** - * IPC node returned from waiting due to request cancellation - */ - virtual void _await_request_failed() = 0; - - protected: - - Pd * _pd = nullptr; /* pointer to PD this IPC node is part of */ - - - /*************** - ** Accessors ** - ***************/ - - Ipc_node * callee() { return _callee; } - State state() { return _state; } + const Ipc_node& operator=(const Ipc_node&) = delete; public: - virtual ~Ipc_node(); + /** + * Destructor + */ + ~Ipc_node(); + + /** + * Constructor + */ + Ipc_node(Thread &thread); /** * Send a request and wait for the according reply @@ -155,8 +129,8 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element * \param callee targeted IPC node * \param help wether the request implies a helping relationship */ - void send_request(Ipc_node &callee, capid_t capid, bool help, - unsigned rcv_caps); + bool can_send_request(); + void send_request(Ipc_node &callee, bool help); /** * Return root destination of the helping-relation tree we are in @@ -181,7 +155,8 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element * * \return wether a request could be received already */ - bool await_request(unsigned rcv_caps); + bool can_await_request(); + bool await_request(); /** * Reply to last request if there's any @@ -198,15 +173,9 @@ class Kernel::Ipc_node : private Ipc_node_queue::Element ** Accessors ** ***************/ - Pd &pd() const - { - if (_pd) - return *_pd; - - ASSERT_NEVER_CALLED; - } - - Genode::Native_utcb *utcb() { return _utcb; } + Ipc_node * callee() { return _callee; } + State state() { return _state; } + Thread &thread() { return _thread; } }; #endif /* _CORE__KERNEL__IPC_NODE_H_ */ diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index 9f4d6db3e7..3a0b9ccf4b 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -35,6 +35,72 @@ extern "C" void _core_start(void); using namespace Kernel; +static inline void free_obj_id_ref(Pd &pd, void *ptr) +{ + pd.platform_pd().capability_slab().free(ptr, sizeof(Object_identity_reference)); +} + + +void Thread::_ipc_init(Genode::Native_utcb &utcb, Thread &starter) +{ + _utcb = &utcb; + _ipc_rcv_caps = starter._utcb->cap_cnt(); + Genode::Allocator &slab = pd().platform_pd().capability_slab(); + for (unsigned i = 0; i < _ipc_rcv_caps; i++) + _obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference)); + ipc_copy_msg(starter); +} + + +void Thread::ipc_copy_msg(Thread &sender) +{ + using namespace Genode; + using Reference = Object_identity_reference; + + /* copy payload and set destination capability id */ + *_utcb = *sender._utcb; + _utcb->destination(sender._ipc_capid); + + /* translate capabilities */ + for (unsigned i = 0; i < _ipc_rcv_caps; i++) { + + capid_t id = sender._utcb->cap_get(i); + + /* if there is no capability to send, just free the pre-allocation */ + if (i >= sender._utcb->cap_cnt()) { + free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); + continue; + } + + /* lookup the capability id within the caller's cap space */ + Reference *oir = (id == cap_id_invalid()) + ? nullptr : sender.pd().cap_tree().find(id); + + /* if the caller's capability is invalid, free the pre-allocation */ + if (!oir) { + _utcb->cap_add(cap_id_invalid()); + free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); + continue; + } + + /* lookup the capability id within the callee's cap space */ + Reference *dst_oir = oir->find(pd()); + + /* if it is not found, and the target is not core, create a reference */ + if (!dst_oir && (&pd() != &core_pd())) { + dst_oir = oir->factory(_obj_id_ref_ptr[i], pd()); + if (!dst_oir) + free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); + } else /* otherwise free the pre-allocation */ + free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); + + if (dst_oir) dst_oir->add_to_utcb(); + + /* add the translated capability id to the target buffer */ + _utcb->cap_add(dst_oir ? dst_oir->capid() : cap_id_invalid()); + } +} + Thread::Tlb_invalidation::Tlb_invalidation(Thread & caller, Pd & pd, addr_t addr, size_t size, @@ -114,7 +180,7 @@ void Thread::_receive_signal(void * const base, size_t const size) } -void Thread::_send_request_succeeded() +void Thread::ipc_send_request_succeeded() { assert(_state == AWAITS_IPC); user_arg_0(0); @@ -123,7 +189,7 @@ void Thread::_send_request_succeeded() } -void Thread::_send_request_failed() +void Thread::ipc_send_request_failed() { assert(_state == AWAITS_IPC); user_arg_0(-1); @@ -132,7 +198,7 @@ void Thread::_send_request_failed() } -void Thread::_await_request_succeeded() +void Thread::ipc_await_request_succeeded() { assert(_state == AWAITS_IPC); user_arg_0(0); @@ -140,7 +206,7 @@ void Thread::_await_request_succeeded() } -void Thread::_await_request_failed() +void Thread::ipc_await_request_failed() { assert(_state == AWAITS_IPC); user_arg_0(-1); @@ -151,15 +217,15 @@ void Thread::_await_request_failed() void Thread::_deactivate_used_shares() { Cpu_job::_deactivate_own_share(); - Ipc_node::for_each_helper([&] (Ipc_node &h) { - static_cast(h)._deactivate_used_shares(); }); + _ipc_node.for_each_helper([&] (Ipc_node &ipc_node) { + ipc_node.thread()._deactivate_used_shares(); }); } void Thread::_activate_used_shares() { Cpu_job::_activate_own_share(); - Ipc_node::for_each_helper([&] (Ipc_node &h) { - static_cast(h)._activate_used_shares(); }); + _ipc_node.for_each_helper([&] (Ipc_node &ipc_node) { + ipc_node.thread()._activate_used_shares(); }); } void Thread::_become_active() @@ -180,7 +246,7 @@ void Thread::_die() { _become_inactive(DEAD); } Cpu_job * Thread::helping_sink() { - return static_cast(Ipc_node::helping_sink()); } + return &_ipc_node.helping_sink()->thread(); } size_t Thread::_core_to_kernel_quota(size_t const quota) const @@ -212,7 +278,7 @@ void Thread::_call_start_thread() /* join protection domain */ thread._pd = (Pd *) user_arg_3(); - thread.Ipc_node::_init(*(Native_utcb *)user_arg_4(), *this); + thread._ipc_init(*(Native_utcb *)user_arg_4(), *this); thread._become_active(); } @@ -285,7 +351,7 @@ void Thread::_cancel_blocking() _become_active(); return; case AWAITS_IPC: - Ipc_node::cancel_waiting(); + _ipc_node.cancel_waiting(); return; case AWAITS_SIGNAL: Signal_handler::cancel_waiting(); @@ -339,7 +405,18 @@ void Thread::_call_delete_thread() void Thread::_call_await_request_msg() { - if (Ipc_node::await_request(user_arg_1())) { + if (!_ipc_node.can_await_request()) { + Genode::raw("IPC await request: bad state"); + user_arg_0(0); + return; + } + unsigned const rcv_caps = user_arg_1(); + Genode::Allocator &slab = pd().platform_pd().capability_slab(); + for (unsigned i = 0; i < rcv_caps; i++) + _obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference)); + + _ipc_rcv_caps = rcv_caps; + if (_ipc_node.await_request()) { user_arg_0(0); return; } @@ -390,8 +467,19 @@ void Thread::_call_send_request_msg() bool const help = Cpu_job::_helping_possible(*dst); oir = oir->find(dst->pd()); - Ipc_node::send_request(*dst, oir ? oir->capid() : cap_id_invalid(), - help, user_arg_2()); + if (!_ipc_node.can_send_request()) { + Genode::raw("IPC send request: bad state"); + } else { + unsigned const rcv_caps = user_arg_2(); + Genode::Allocator &slab = pd().platform_pd().capability_slab(); + for (unsigned i = 0; i < rcv_caps; i++) + _obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference)); + + _ipc_capid = oir ? oir->capid() : cap_id_invalid(); + _ipc_rcv_caps = rcv_caps; + _ipc_node.send_request(dst->_ipc_node, help); + } + _state = AWAITS_IPC; if (!help || !dst->own_share_active()) { _deactivate_used_shares(); } } @@ -399,7 +487,7 @@ void Thread::_call_send_request_msg() void Thread::_call_send_reply_msg() { - Ipc_node::send_reply(); + _ipc_node.send_reply(); bool const await_request_msg = user_arg_2(); if (await_request_msg) { _call_await_request_msg(); } else { user_arg_0(0); } @@ -730,7 +818,7 @@ void Thread::_mmu_exception() Thread::Thread(unsigned const priority, unsigned const quota, char const * const label, bool core) : - Cpu_job(priority, quota), _state(AWAITS_START), + Cpu_job(priority, quota), _ipc_node(*this), _state(AWAITS_START), _signal_receiver(0), _label(label), _core(core), regs(core) { } diff --git a/repos/base-hw/src/core/kernel/thread.h b/repos/base-hw/src/core/kernel/thread.h index c3a4584581..c632beff02 100644 --- a/repos/base-hw/src/core/kernel/thread.h +++ b/repos/base-hw/src/core/kernel/thread.h @@ -14,6 +14,8 @@ #ifndef _CORE__KERNEL__THREAD_H_ #define _CORE__KERNEL__THREAD_H_ + +/* Genode includes */ #include #include @@ -24,6 +26,12 @@ #include #include #include +#include +#include + +/* base-local includes */ +#include + namespace Kernel { @@ -50,9 +58,8 @@ struct Kernel::Thread_fault */ class Kernel::Thread : - public Kernel::Object, public Cpu_job, - public Ipc_node, public Signal_context_killer, public Signal_handler, - private Timeout + public Kernel::Object, public Cpu_job, public Signal_context_killer, + public Signal_handler, private Timeout { private: @@ -121,15 +128,21 @@ class Kernel::Thread DEAD = 7, }; - Signal_context * _pager = nullptr; - Thread_fault _fault { }; - State _state; - Signal_receiver * _signal_receiver; - char const * const _label; - capid_t _timeout_sigid = 0; - bool _paused = false; - bool _cancel_next_await_signal = false; - bool const _core = false; + void *_obj_id_ref_ptr[Genode::Msgbuf_base::MAX_CAPS_PER_MSG]; + Ipc_node _ipc_node; + capid_t _ipc_capid { cap_id_invalid() }; + size_t _ipc_rcv_caps { 0 }; + Genode::Native_utcb *_utcb { nullptr }; + Pd *_pd { nullptr }; + Signal_context *_pager { nullptr }; + Thread_fault _fault { }; + State _state; + Signal_receiver *_signal_receiver; + char const *const _label; + capid_t _timeout_sigid { 0 }; + bool _paused { false }; + bool _cancel_next_await_signal { false }; + bool const _core { false }; Genode::Constructible _tlb_invalidation {}; Genode::Constructible _destroy {}; @@ -258,6 +271,8 @@ class Kernel::Thread kobj.destruct(); } + void _ipc_init(Genode::Native_utcb &utcb, Thread &callee); + /*************************** ** Signal_context_killer ** @@ -276,15 +291,6 @@ class Kernel::Thread void _receive_signal(void * const base, size_t const size) override; - /************** - ** Ipc_node ** - **************/ - - void _send_request_succeeded() override; - void _send_request_failed() override; - void _await_request_succeeded() override; - void _await_request_failed() override; - public: Genode::Align_at regs; @@ -373,6 +379,16 @@ class Kernel::Thread void print(Genode::Output &out) const; + /************** + ** Ipc_node ** + **************/ + + void ipc_send_request_succeeded() ; + void ipc_send_request_failed() ; + void ipc_await_request_succeeded(); + void ipc_await_request_failed() ; + void ipc_copy_msg(Thread &sender) ; + /************* ** Cpu_job ** @@ -396,6 +412,15 @@ class Kernel::Thread char const * label() const { return _label; } Thread_fault fault() const { return _fault; } + Genode::Native_utcb *utcb() { return _utcb; } + + Pd &pd() const + { + if (_pd) + return *_pd; + + ASSERT_NEVER_CALLED; + } };