mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 13:47:56 +00:00
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:
parent
816b4e0479
commit
fe19103546
@ -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;
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user