nova: avoid deadlocks by self-destructing threads

Issue #1687
This commit is contained in:
Alexander Boettcher 2015-09-22 14:39:48 +02:00 committed by Christian Helmuth
parent 6426d4098c
commit ae12f04354
3 changed files with 28 additions and 13 deletions

View File

@ -61,7 +61,7 @@ namespace Genode {
Cap_range *find_by_id(addr_t); Cap_range *find_by_id(addr_t);
void inc(unsigned id, bool inc_if_one = false); void inc(unsigned id, bool inc_if_one = false);
void dec(unsigned id, bool revoke = true); void dec(unsigned id, bool revoke = true, unsigned num_log2 = 0);
addr_t alloc(size_t const num_log2); addr_t alloc(size_t const num_log2);

View File

@ -63,15 +63,20 @@ void Cap_range::inc(unsigned id, bool inc_if_one)
} }
void Cap_range::dec(unsigned id, bool revoke) void Cap_range::dec(unsigned const id_start, bool revoke, unsigned num_log_2)
{ {
bool failure = false; bool failure = false;
{ {
unsigned const end = min(id_start + (1U << num_log_2), elements());
Lock::Guard guard(_lock); Lock::Guard guard(_lock);
if (_cap_array[id] == 0) for (unsigned id = id_start; id < end; id++) {
failure = true; if (_cap_array[id] == 0) {
else { failure = true;
continue;
}
if (revoke && _cap_array[id] == 1) if (revoke && _cap_array[id] == 1)
Nova::revoke(Nova::Obj_crd(_base + id, 0)); Nova::revoke(Nova::Obj_crd(_base + id, 0));
@ -80,8 +85,8 @@ void Cap_range::dec(unsigned id, bool revoke)
} }
if (failure) if (failure)
PERR("cap reference counting error - count of cap=%lx is already zero", PERR("cap reference counting error - one counter of cap range %lx+%x "
_base + id); "has been already zero", _base + id_start, 1 << num_log_2);
} }
@ -161,12 +166,23 @@ addr_t Capability_map::insert(size_t const num_log_2, addr_t const sel)
} }
void Capability_map::remove(Genode::addr_t sel, uint8_t num_log_2, bool revoke) void Capability_map::remove(Genode::addr_t const sel, uint8_t num_log_2,
bool revoke)
{ {
Cap_range * range = _tree.first() ? _tree.first()->find_by_id(sel) : 0; Cap_range * range = _tree.first() ? _tree.first()->find_by_id(sel) : 0;
if (!range) if (!range)
return; return;
for (unsigned i = 0; i < 1UL << num_log_2; i++) range->dec(sel - range->base(), revoke, num_log_2);
range->dec(sel + i - range->base(), revoke);
Genode::addr_t last_sel = sel + (1UL << num_log_2);
Genode::addr_t last_range = range->base() + range->elements();
while (last_sel > last_range) {
uint8_t left_log2 = log2(last_sel - last_range);
remove(last_range, left_log2, revoke);
last_range += 1UL << left_log2;
}
} }

View File

@ -134,13 +134,12 @@ void Thread_base::_deinit_platform_thread()
cap_map()->remove(_tid.ec_sel, 1, false); cap_map()->remove(_tid.ec_sel, 1, false);
} }
revoke(Obj_crd(_tid.exc_pt_sel, NUM_INITIAL_PT_LOG2));
cap_map()->remove(_tid.exc_pt_sel, NUM_INITIAL_PT_LOG2, false);
/* de-announce thread */ /* de-announce thread */
if (_thread_cap.valid()) if (_thread_cap.valid())
_cpu_session->kill_thread(_thread_cap); _cpu_session->kill_thread(_thread_cap);
cap_map()->remove(_tid.exc_pt_sel, NUM_INITIAL_PT_LOG2);
if (_pager_cap.valid()) if (_pager_cap.valid())
env()->rm_session()->remove_client(_pager_cap); env()->rm_session()->remove_client(_pager_cap);
} }