core: remove exception from Trace::Control alloc

This patch models the 'Trace::Control_area' as an allocator of slots
using the new 'Allocation' utility and thereby removes the former
exception-based error propagation.

Issue #5245
This commit is contained in:
Norman Feske 2025-04-05 18:47:17 +02:00
parent b4a746bc89
commit 08010003e3
6 changed files with 94 additions and 104 deletions

View File

@ -62,32 +62,8 @@ class Core::Vm_session_component
Session_label const &_label;
addr_t const _pd_sel;
struct Trace_control_slot
{
unsigned index = 0;
Trace::Control_area &_trace_control_area;
Trace_control_slot(Trace::Control_area &trace_control_area)
: _trace_control_area(trace_control_area)
{
if (!_trace_control_area.alloc(index))
throw Out_of_ram();
}
~Trace_control_slot()
{
_trace_control_area.free(index);
}
Trace::Control &control()
{
return *_trace_control_area.at(index);
}
};
Trace_control_slot _trace_control_slot;
Trace::Source _trace_source { *this, _trace_control_slot.control() };
Trace::Control_area::Result _trace_control_slot;
Constructible<Trace::Source> _trace_source { };
public:

View File

@ -162,7 +162,7 @@ Vm_session_component::Vcpu::Vcpu(Rpc_entrypoint &ep,
_priority(priority),
_label(label),
_pd_sel(pd_sel),
_trace_control_slot(trace_control_area)
_trace_control_slot(trace_control_area.alloc())
{
/* account caps required to setup vCPU */
Cap_quota_guard::Reservation caps(_cap_alloc, Cap_quota{CAP_RANGE});
@ -220,7 +220,12 @@ Vm_session_component::Vcpu::Vcpu(Rpc_entrypoint &ep,
_ep.manage(this);
_trace_sources.insert(&_trace_source);
trace_control_area.with_control(_trace_control_slot,
[&] (Trace::Control &control) {
_trace_source.construct(*this, control);
Trace::Source &source = *_trace_source;
_trace_sources.insert(&source);
});
caps.acknowledge();
}
@ -230,7 +235,10 @@ Vm_session_component::Vcpu::~Vcpu()
{
_ep.dissolve(this);
_trace_sources.remove(&_trace_source);
if (_trace_source.constructed()) {
Trace::Source &source = *_trace_source;
_trace_sources.remove(&source);
}
if (_sel_sm_ec_sc != invalid_sel()) {
_cap_alloc.replenish(Cap_quota{CAP_RANGE});

View File

@ -274,6 +274,9 @@ Cpu_session_component::Cpu_session_component(Rpc_entrypoint &session_ep,
_quota(quota), _ref(0),
_native_cpu(*this, args)
{
if (!_trace_control_area.valid())
raise(_trace_control_area.error);
Arg a = Arg_string::find_arg(args, "priority");
if (a.valid()) {
_priority = (unsigned)a.ulong_value(0);

View File

@ -93,18 +93,24 @@ void Cpu_thread_component::affinity(Affinity::Location location)
unsigned Cpu_thread_component::trace_control_index()
{
return _trace_control_slot.index;
return _trace_control_slot.convert<unsigned>(
[&] (Trace::Control_area::Slot const &slot) { return slot.index; },
[&] (Trace::Control_area::Error) { return 0u; });
}
Dataspace_capability Cpu_thread_component::trace_buffer()
{
return _trace_source.buffer();
if (!_trace_source.constructed())
return { };
return _trace_source->buffer();
}
Dataspace_capability Cpu_thread_component::trace_policy()
{
return _trace_source.policy();
if (!_trace_source.constructed())
return { };
return _trace_source->policy();
}

View File

@ -69,32 +69,9 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
*/
Signal_context_capability _thread_sigh { };
struct Trace_control_slot
{
unsigned index = 0;
Trace::Control_area &trace_control_area;
Trace::Control_area::Result _trace_control_slot;
Trace_control_slot(Trace::Control_area &trace_control_area)
: trace_control_area(trace_control_area)
{
if (!trace_control_area.alloc(index))
throw Out_of_ram();
}
~Trace_control_slot()
{
trace_control_area.free(index);
}
Trace::Control &control()
{
return *trace_control_area.at(index);
}
};
Trace_control_slot _trace_control_slot;
Trace::Source _trace_source { *this, _trace_control_slot.control() };
Constructible<Trace::Source> _trace_source { };
Trace::Source_registry &_trace_sources;
@ -164,7 +141,7 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
_pd_element(pd_threads, *this),
_platform_thread(platform_pd, ep, cpu_ram, core_rm, quota, name.string(),
priority, location, utcb),
_trace_control_slot(trace_control_area),
_trace_control_slot(trace_control_area.alloc()),
_trace_sources(trace_sources),
_managed_thread_cap(_ep, *this),
_rm_client(cpu_session_cap, _managed_thread_cap.cap(),
@ -177,12 +154,20 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
_address_space_region_map.add_client(_rm_client);
_platform_thread.pager(_rm_client);
_trace_sources.insert(&_trace_source);
trace_control_area.with_control(_trace_control_slot,
[&] (Trace::Control &control) {
_trace_source.construct(*this, control);
Trace::Source &source = *_trace_source;
_trace_sources.insert(&source);
});
}
~Cpu_thread_component()
{
_trace_sources.remove(&_trace_source);
if (_trace_source.constructed()) {
Trace::Source &source = *_trace_source;
_trace_sources.remove(&source);
}
_pager_ep.dissolve(_rm_client);
_address_space_region_map.remove_client(_rm_client);

View File

@ -24,67 +24,79 @@
namespace Genode { namespace Trace { class Control_area; } }
class Genode::Trace::Control_area
struct Genode::Trace::Control_area : Noncopyable
{
public:
enum { SIZE = 8192 };
enum { SIZE = 8192 };
Alloc_error error = Alloc_error::DENIED;
Constructible<Attached_ram_dataspace> _area { };
private:
bool _index_valid(unsigned const index) const {
return index < SIZE / sizeof(Control); }
Ram_allocator &_ram;
Region_map &_rm;
Attached_ram_dataspace const _area;
auto _with_control_at_index(unsigned i, auto const &fn,
auto const &missing_fn) const
-> decltype(missing_fn())
{
if (!_area.constructed() || !_index_valid(i))
return missing_fn();
bool _index_valid(unsigned const index) const {
return index < SIZE / sizeof(Trace::Control); }
return fn(_area->local_addr<Control>()[i]);
}
/*
* Noncopyable
*/
Control_area(Control_area const &);
Control_area &operator = (Control_area const &);
Control_area(Ram_allocator &ram, Region_map &rm)
{
try { _area.construct(ram, rm, SIZE); }
catch (Out_of_ram) { error = Alloc_error::OUT_OF_RAM; }
catch (Out_of_caps) { error = Alloc_error::OUT_OF_CAPS; }
catch (...) { }
}
Trace::Control * _local_base() const {
return _area.local_addr<Trace::Control>(); }
~Control_area() { }
public:
bool valid() const { return _area.constructed(); }
Control_area(Ram_allocator &ram, Region_map &rm)
:
_ram(ram), _rm(rm), _area(ram, rm, SIZE)
{ }
Ram::Capability dataspace() const
{
return _area.constructed() ? _area->cap() : Ram::Capability();
}
~Control_area() { }
struct Attr { unsigned index; };
Dataspace_capability dataspace() const { return _area.cap(); }
using Error = Denied;
using Slot = Allocation<Control_area>;
using Result = Slot::Attempt;
bool alloc(unsigned &index_out)
Result alloc()
{
auto try_alloc = [&] (Control &control)
{
for (unsigned index = 0; _index_valid(index); index++) {
if (!_local_base()[index].is_free()) {
continue;
}
if (!control.is_free())
return false;
control.alloc();
return true;
};
_local_base()[index].alloc();
index_out = index;
return true;
}
for (unsigned i = 0; _index_valid(i); i++)
if (_with_control_at_index(i, try_alloc, [&] { return false; }))
return { *this, { i } };
error("trace-control allocation failed");
return false;
}
return Error();
}
void free(unsigned index)
{
if (_index_valid(index))
_local_base()[index].reset();
}
void _free(Slot &slot)
{
_with_control_at_index(slot.index,
[&] (Control &control) { control.reset(); }, [] { });
}
Trace::Control *at(unsigned index)
{
return _index_valid(index) ? &(_local_base()[index]) : nullptr;
}
void with_control(Result const &slot, auto const &fn) const
{
slot.with_result(
[&] (Slot const &slot) {
_with_control_at_index(slot.index, fn, [&] { }); },
[&] (Error) { });
}
};
#endif /* _CORE__INCLUDE__TRACE__CONTROL_AREA_H_ */