diff --git a/repos/base-nova/include/base/cap_map.h b/repos/base-nova/include/base/cap_map.h index 7d63d15704..41ab802ee0 100644 --- a/repos/base-nova/include/base/cap_map.h +++ b/repos/base-nova/include/base/cap_map.h @@ -61,7 +61,7 @@ namespace Genode { Cap_range *find_by_id(addr_t); 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); diff --git a/repos/base-nova/src/base/env/cap_map.cc b/repos/base-nova/src/base/env/cap_map.cc index 4a938ff588..5a85b15b96 100644 --- a/repos/base-nova/src/base/env/cap_map.cc +++ b/repos/base-nova/src/base/env/cap_map.cc @@ -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; { + unsigned const end = min(id_start + (1U << num_log_2), elements()); + Lock::Guard guard(_lock); - if (_cap_array[id] == 0) - failure = true; - else { + for (unsigned id = id_start; id < end; id++) { + if (_cap_array[id] == 0) { + failure = true; + continue; + } + if (revoke && _cap_array[id] == 1) Nova::revoke(Nova::Obj_crd(_base + id, 0)); @@ -80,8 +85,8 @@ void Cap_range::dec(unsigned id, bool revoke) } if (failure) - PERR("cap reference counting error - count of cap=%lx is already zero", - _base + id); + PERR("cap reference counting error - one counter of cap range %lx+%x " + "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; if (!range) return; - for (unsigned i = 0; i < 1UL << num_log_2; i++) - range->dec(sel + i - range->base(), revoke); + range->dec(sel - range->base(), revoke, num_log_2); + + 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; + } } diff --git a/repos/base-nova/src/base/thread/thread_nova.cc b/repos/base-nova/src/base/thread/thread_nova.cc index 1952375cfa..ddd2cc3e39 100644 --- a/repos/base-nova/src/base/thread/thread_nova.cc +++ b/repos/base-nova/src/base/thread/thread_nova.cc @@ -134,13 +134,12 @@ void Thread_base::_deinit_platform_thread() 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 */ if (_thread_cap.valid()) _cpu_session->kill_thread(_thread_cap); + cap_map()->remove(_tid.exc_pt_sel, NUM_INITIAL_PT_LOG2); + if (_pager_cap.valid()) env()->rm_session()->remove_client(_pager_cap); }