From fe19103546ce8a88494ffe21bf3490ffcc629de7 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Thu, 26 Sep 2013 14:31:56 +0200 Subject: [PATCH] nova: create sm for signalling via pager The 'pause' call on base-nova assumes that a thread can solely block in its associated semaphore. Main reason is that so core can unblock a thread in order that the recall exception gets delivered and the register state can be obtained. Unfortunately the signal session implementation creates a semaphore, which is unknown by the pager code. Instead create the semaphore via the pager of the thread, so that the pager can unblock the signal thread when a pause is issued. Issue #478 --- base-nova/include/base/pager.h | 4 ++ base-nova/include/nova/util.h | 12 +++- .../include/signal_session/nova_source.h | 5 +- .../include/signal_session/source_client.h | 9 ++- .../signal_session/source_rpc_object.h | 7 ++- base-nova/src/base/pager/pager.cc | 63 ++++++++++++++----- base-nova/src/base/thread/thread_nova.cc | 6 +- base-nova/src/core/signal_source_component.cc | 11 +--- base-nova/src/core/thread_start.cc | 6 +- 9 files changed, 83 insertions(+), 40 deletions(-) diff --git a/base-nova/include/base/pager.h b/base-nova/include/base/pager.h index ddd58f2c4b..72ba9f2bea 100644 --- a/base-nova/include/base/pager.h +++ b/base-nova/include/base/pager.h @@ -62,6 +62,7 @@ namespace Genode { DEAD = 0x2U, SINGLESTEP = 0x4U, CLIENT_CANCEL = 0x8U, + SIGNAL_SM = 0x10U, }; uint8_t _status; @@ -78,6 +79,9 @@ namespace Genode { inline bool is_dead() { return _status & DEAD; } inline bool singlestep() { return _status & SINGLESTEP; } + + inline void mark_signal_sm() { _status |= SIGNAL_SM; } + inline bool has_signal_sm() { return _status & SIGNAL_SM; } } _state; Thread_capability _thread_cap; diff --git a/base-nova/include/nova/util.h b/base-nova/include/nova/util.h index ba22ef8f8f..159fae9dc2 100644 --- a/base-nova/include/nova/util.h +++ b/base-nova/include/nova/util.h @@ -46,16 +46,22 @@ inline void request_event_portal(Genode::Native_capability const &cap, utcb->set_msg_word(2); uint8_t res = call(cap.local_name()); - if (res) - PERR("request of event (%lu) capability selector failed", event); /* restore original receive window */ utcb->crd_rcv = orig_crd; + + if (res) + PERR("request of event (%lu) capability selector failed", event); } inline void request_native_ec_cap(Genode::Native_capability const &cap, Genode::addr_t sel) { - request_event_portal(cap, sel , ~0U, 0); } + request_event_portal(cap, sel , ~0UL, 1); } + + +inline void request_signal_sm_cap(Genode::Native_capability const &cap, + Genode::addr_t sel) { + request_event_portal(cap, sel, ~0UL - 1, 0); } #endif /* _NOVA__INCLUDE__UTIL_H_ */ diff --git a/base-nova/include/signal_session/nova_source.h b/base-nova/include/signal_session/nova_source.h index 3a3a4e5f94..8ba79f8a5c 100644 --- a/base-nova/include/signal_session/nova_source.h +++ b/base-nova/include/signal_session/nova_source.h @@ -25,9 +25,10 @@ namespace Genode { ** RPC declaration ** *********************/ - GENODE_RPC(Rpc_request_semaphore, Native_capability, _request_semaphore); + GENODE_RPC(Rpc_register_semaphore, void, _register_semaphore, + Native_capability const &); - GENODE_RPC_INTERFACE_INHERIT(Signal_source, Rpc_request_semaphore); + GENODE_RPC_INTERFACE_INHERIT(Signal_source, Rpc_register_semaphore); }; } diff --git a/base-nova/include/signal_session/source_client.h b/base-nova/include/signal_session/source_client.h index 06fc76ec4c..c69aa25bd9 100644 --- a/base-nova/include/signal_session/source_client.h +++ b/base-nova/include/signal_session/source_client.h @@ -48,7 +48,11 @@ namespace Genode { if (_sem.valid()) return; /* request mapping of semaphore capability selector */ - _sem = call(); + Thread_base * myself = Thread_base::myself(); + request_signal_sm_cap(Native_capability(myself->tid().ec_sel + 1), + myself->tid().exc_pt_sel + Nova::PT_SEL_STARTUP); + _sem = Native_capability(myself->tid().exc_pt_sel + Nova::PT_SEL_STARTUP); + call(_sem); } public: @@ -77,8 +81,7 @@ namespace Genode { * Block on semaphore, will be unblocked if * signal is available */ - if (Nova::sm_ctrl(_sem.local_name(), - Nova::SEMAPHORE_DOWN)) + if (Nova::sm_ctrl(_sem.local_name(), Nova::SEMAPHORE_DOWN)) nova_die(); /* diff --git a/base-nova/include/signal_session/source_rpc_object.h b/base-nova/include/signal_session/source_rpc_object.h index 15f9b972a7..8ed857f5f1 100644 --- a/base-nova/include/signal_session/source_rpc_object.h +++ b/base-nova/include/signal_session/source_rpc_object.h @@ -32,7 +32,12 @@ namespace Genode { public: - Native_capability _request_semaphore() { return _blocking_semaphore; } + void _register_semaphore(Native_capability const &cap) + { + if (_blocking_semaphore.valid()) + PWRN("overwritting blocking signal semaphore !!!"); + _blocking_semaphore = cap; + } }; } diff --git a/base-nova/src/base/pager/pager.cc b/base-nova/src/base/pager/pager.cc index ee45556aac..261f7d016c 100644 --- a/base-nova/src/base/pager/pager.cc +++ b/base-nova/src/base/pager/pager.cc @@ -84,7 +84,7 @@ void Pager_object::_page_fault_handler() myself->name(client_name, sizeof(client_name)); PDBG("unhandled page fault, '%s' address=0x%lx ip=0x%lx", - client_name, ipc_pager.fault_addr(), ipc_pager.fault_ip()); + client_name, ipc_pager.fault_addr(), ipc_pager.fault_ip()); } utcb->set_msg_word(0); @@ -101,20 +101,18 @@ void Pager_object::_exception_handler(addr_t portal_id) Pager_object *obj; Utcb *utcb = _check_handler(myself, obj); addr_t fault_ip = utcb->ip; + uint8_t res = Nova::NOVA_OK; - if (obj->submit_exception_signal()) { - /* somebody takes care don't die - just recall and block */ - if (obj->client_recall() != Nova::NOVA_OK) { - PERR("recall failed exception_handler"); - nova_die(); - } - } - else { + if (obj->submit_exception_signal()) + res = obj->client_recall(); + + if (res != NOVA_OK) { char client_name[Context::NAME_LEN]; myself->name(client_name, sizeof(client_name)); - PWRN("unresolvable exception at ip 0x%lx, exception portal 0x%lx, " - "'%s'", fault_ip, portal_id, client_name); + PWRN("unresolvable exception at ip 0x%lx, exception portal 0x%lx, %s, " + "'%s'", fault_ip, portal_id, res == NOVA_OK ? "" : "recall failed", + client_name); Nova::revoke(Obj_crd(portal_id, 0)); obj->_state.mark_dead(); @@ -200,6 +198,7 @@ void Pager_object::_invoke_handler() utcb->mtd = 0; utcb->set_msg_word(0); + /* native ec cap requested */ if (event == ~0UL) { /** * Return native EC cap with specific rights mask set. @@ -216,15 +215,40 @@ void Pager_object::_invoke_handler() */ bool res = utcb->append_item(Obj_crd(obj->_state.sel_client_ec, 0, Obj_crd::RIGHT_EC_RECALL), 0); + res = utcb->append_item(Obj_crd(obj->Object_pool::Entry::cap().local_name(), 0), 1); (void)res; + reply(myself->stack_top()); } - /* sanity check - if event is not valid return nothing */ + /* semaphore for signaling thread is requested, reuse PT_SEL_STARTUP. */ + if (event == ~0UL - 1) { + /* create semaphore only once */ + if (!obj->_state.has_signal_sm()) { + + revoke(Obj_crd(obj->exc_pt_sel_client() + PT_SEL_STARTUP, 0)); + + bool res = Nova::create_sm(obj->exc_pt_sel_client() + PT_SEL_STARTUP, + __core_pd_sel, 0); + if (res != Nova::NOVA_OK) + reply(myself->stack_top()); + + obj->_state.mark_signal_sm(); + } + + bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() + + PT_SEL_STARTUP, 0), 0); + (void)res; + + reply(myself->stack_top()); + } + + /* sanity check, if event is not valid return nothing */ if (logcount > NUM_INITIAL_PT_LOG2 || event > 1UL << NUM_INITIAL_PT_LOG2 || event + (1UL << logcount) > (1UL << NUM_INITIAL_PT_LOG2)) reply(myself->stack_top()); + /* valid event portal is requested, delegate it to caller */ bool res = utcb->append_item(Obj_crd(obj->exc_pt_sel_client() + event, logcount), 0); (void)res; @@ -250,7 +274,14 @@ void Pager_object::client_cancel_blocking() uint8_t res = sm_ctrl(exc_pt_sel_client() + SM_SEL_EC, SEMAPHORE_UP); if (res != NOVA_OK) - PWRN("cancel blocking failed"); + PWRN("canceling blocked client failed (thread sm)"); + + if (!_state.has_signal_sm()) + return; + + res = sm_ctrl(exc_pt_sel_client() + PT_SEL_STARTUP, SEMAPHORE_UP); + if (res != NOVA_OK) + PWRN("canceling blocked client failed (signal sm)"); } @@ -277,17 +308,19 @@ void Pager_object::cleanup_call() utcb, this->utcb(), res); } + static uint8_t create_portal(addr_t pt, addr_t pd, addr_t ec, Mtd mtd, - addr_t eip) + addr_t eip) { uint8_t res = create_pt(pt, pd, ec, mtd, eip); if (res == NOVA_OK) revoke(Obj_crd(pt, 0, Obj_crd::RIGHT_PT_CTRL)); - return res; + return res; } + Pager_object::Pager_object(unsigned long badge, Affinity::Location location) : Thread_base("pager:", PF_HANDLER_STACK_SIZE), _badge(reinterpret_cast(_context->name + 6)) diff --git a/base-nova/src/base/thread/thread_nova.cc b/base-nova/src/base/thread/thread_nova.cc index 4c5b49ef39..5fad812a53 100644 --- a/base-nova/src/base/thread/thread_nova.cc +++ b/base-nova/src/base/thread/thread_nova.cc @@ -100,8 +100,8 @@ void Thread_base::_deinit_platform_thread() using namespace Nova; if (_tid.ec_sel != ~0UL) { - revoke(Obj_crd(_tid.ec_sel, 0)); - cap_selector_allocator()->free(_tid.ec_sel, 0); + revoke(Obj_crd(_tid.ec_sel, 1)); + cap_selector_allocator()->free(_tid.ec_sel, 1); } revoke(Obj_crd(_tid.exc_pt_sel, NUM_INITIAL_PT_LOG2)); @@ -166,7 +166,7 @@ void Thread_base::start() throw Cpu_session::Thread_creation_failed(); /* request native EC thread cap */ - _tid.ec_sel = cap_selector_allocator()->alloc(); + _tid.ec_sel = cap_selector_allocator()->alloc(1); if (_tid.ec_sel == Native_thread::INVALID_INDEX) throw Cpu_session::Thread_creation_failed(); diff --git a/base-nova/src/core/signal_source_component.cc b/base-nova/src/core/signal_source_component.cc index e4b677c244..83d5b9c690 100644 --- a/base-nova/src/core/signal_source_component.cc +++ b/base-nova/src/core/signal_source_component.cc @@ -71,16 +71,7 @@ Signal_source::Signal Signal_source_component::wait_for_signal() Signal_source_component::Signal_source_component(Rpc_entrypoint *ep) : _entrypoint(ep), _finalizer(*this), - _finalizer_cap(_entrypoint->manage(&_finalizer)) -{ - /* initialized blocking semaphore */ - addr_t sem_sel = cap_selector_allocator()->alloc(); - uint8_t ret = Nova::create_sm(sem_sel, Platform_pd::pd_core_sel(), 0); - if (ret) - PERR("create_sm returned %u", ret); - - _blocking_semaphore = Native_capability(sem_sel); -} + _finalizer_cap(_entrypoint->manage(&_finalizer)) { } Signal_source_component::~Signal_source_component() diff --git a/base-nova/src/core/thread_start.cc b/base-nova/src/core/thread_start.cc index edddb97816..b0cd803d41 100644 --- a/base-nova/src/core/thread_start.cc +++ b/base-nova/src/core/thread_start.cc @@ -39,7 +39,7 @@ void Thread_base::_init_platform_thread() */ using namespace Nova; - _tid.ec_sel = cap_selector_allocator()->alloc(); + _tid.ec_sel = cap_selector_allocator()->alloc(1); _tid.exc_pt_sel = cap_selector_allocator()->alloc(NUM_INITIAL_PT_LOG2); addr_t pd_sel = Platform_pd::pd_core_sel(); @@ -55,10 +55,10 @@ void Thread_base::_init_platform_thread() void Thread_base::_deinit_platform_thread() { - unmap_local(Nova::Obj_crd(_tid.ec_sel, 0)); + unmap_local(Nova::Obj_crd(_tid.ec_sel, 1)); unmap_local(Nova::Obj_crd(_tid.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2)); - cap_selector_allocator()->free(_tid.ec_sel, 0); + cap_selector_allocator()->free(_tid.ec_sel, 1); cap_selector_allocator()->free(_tid.exc_pt_sel, Nova::NUM_INITIAL_PT_LOG2);