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
This commit is contained in:
Alexander Boettcher 2013-09-26 14:31:56 +02:00 committed by Norman Feske
parent 816b4e0479
commit fe19103546
9 changed files with 83 additions and 40 deletions

View File

@ -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;

View File

@ -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_ */

View File

@ -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);
};
}

View File

@ -48,7 +48,11 @@ namespace Genode {
if (_sem.valid()) return;
/* request mapping of semaphore capability selector */
_sem = call<Rpc_request_semaphore>();
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<Rpc_register_semaphore>(_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();
/*

View File

@ -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;
}
};
}

View File

@ -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<Pager_object>::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<unsigned long>(_context->name + 6))

View File

@ -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();

View File

@ -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()

View File

@ -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);