nova: fix cleanup handling in server object

As first step the rpc object must be freed up so that the kernel object
(portal) vanishes. Then the object must be removed from the internal object
pool list so that the object can't be obtained anymore. And then the cleanup
call can be performed (_leave_server_object) since now all names to the
rpc_object are gone.

Doing it in different order (as before the commit) there is a very very little
chance (but the bomb test triggers it occasionally) that the rpc_object can be
obtained again by an incoming IPC - even it is already scheduled for removal.

Fixes partly #549
This commit is contained in:
Alexander Boettcher
2012-12-12 12:06:54 +01:00
committed by Norman Feske
parent f50d816555
commit 28f7cf5dc2

View File

@@ -38,7 +38,7 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
Untyped_capability ec_cap, ep_cap;
/* _ec_sel is invalid until thread gets started */
if (tid().ec_sel != ~0UL)
if (tid().ec_sel != Native_thread::INVALID_INDEX)
ec_cap = Native_capability(tid().ec_sel);
else
ec_cap = _thread_cap;
@@ -56,8 +56,11 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
void Rpc_entrypoint::_dissolve(Rpc_object_base *obj)
{
/* Avoid any incoming IPC early, keep local cap solely */
Nova::revoke(Nova::Obj_crd(obj->cap().local_name(), 0), false);
/* de-announce object from cap_session */
_cap_session->free(obj->cap());
/* avoid any incoming IPC */
Nova::revoke(Nova::Obj_crd(obj->cap().local_name(), 0), true);
/* make sure nobody is able to find this object */
remove_locked(obj);
@@ -74,14 +77,9 @@ void Rpc_entrypoint::_dissolve(Rpc_object_base *obj)
/* wait until nobody is inside dispatch */
obj->acquire();
/* De-announce object from cap_session */
_cap_session->free(obj->cap());
/* Revoke also local cap finally */
Nova::revoke(Nova::Obj_crd(obj->cap().local_name(), 0), true);
/* free cap selector */
cap_selector_allocator()->free(obj->cap().local_name(), 0);
/* XXX we need cap ref counting to avoid reuse bug which triggers */
//cap_selector_allocator()->free(obj->cap().local_name(), 0);
}
void Rpc_entrypoint::_activation_entry()
@@ -158,24 +156,27 @@ void Rpc_entrypoint::entry()
}
void Rpc_entrypoint::_leave_server_object(Rpc_object_base *obj)
void Rpc_entrypoint::_leave_server_object(Rpc_object_base *)
{
{
Lock::Guard lock_guard(_curr_obj_lock);
using namespace Nova;
if (obj == _curr_obj)
cancel_blocking();
}
Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(
Thread_base::myself()->utcb());
Utcb *utcb = reinterpret_cast<Utcb *>(Thread_base::myself()->utcb());
/* don't call ourself */
if (utcb != reinterpret_cast<Nova::Utcb *>(&_context->utcb)) {
utcb->msg[0] = 0xdead;
utcb->set_msg_word(1);
if (uint8_t res = Nova::call(obj->cap().local_name()))
PERR("could not clean up entry point - %u", res);
}
if (utcb == reinterpret_cast<Utcb *>(this->utcb()))
return;
/*
* Required outside of core. E.g. launchpad needs it to forcefully kill
* a client which blocks on a session opening request where the service
* is not up yet.
*/
cancel_blocking();
utcb->msg[0] = 0xdead;
utcb->set_msg_word(1);
if (uint8_t res = call(_cap.local_name()))
PERR("%8p - could not clean up entry point of thread 0x%p - res %u",
utcb, this->utcb(), res);
}
@@ -211,7 +212,7 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
* setup in the early bootstrap phase of core. In core the thread
* is created 'manually'.
*/
if (_tid.ec_sel == ~0UL) {
if (_tid.ec_sel == Native_thread::INVALID_INDEX) {
/* create new pager object and assign it to the new thread */
_pager_cap = env()->rm_session()->add_client(_thread_cap);
if (!_pager_cap.valid())
@@ -257,6 +258,13 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
*/
Thread_base::start();
/* create cleanup portal */
_cap = _cap_session->alloc(Native_capability(_tid.ec_sel),
(addr_t)_activation_entry);
if (!_cap.valid())
throw Cpu_session::Thread_creation_failed();
/* prepare portal receive window of new thread */
_rcv_buf.rcv_prepare_pt_sel_window((Nova::Utcb *)&_context->utcb);
if (start_on_construction)
@@ -275,4 +283,13 @@ Rpc_entrypoint::~Rpc_entrypoint()
while (Rpc_object_base *obj = Pool::first())
_dissolve(obj);
}
if (!_cap.valid())
return;
/* de-announce object from cap_session */
_cap_session->free(_cap);
Nova::revoke(Nova::Obj_crd(_cap.local_name(), 0), true);
cap_selector_allocator()->free(_cap.local_name(), 0);
}