Remove exceptions from TRACE session interface

- Use attempt pattern for error handling
- Replace lookup of pointers by with_ pattern
- Remove virtual Trace::Session methods
- Merge client.h into connection.h
- Update coding style of test/trace

Issue #5245
This commit is contained in:
Norman Feske
2024-06-11 16:53:03 +02:00
parent 7de2f57ef2
commit a52c2ce141
20 changed files with 606 additions and 602 deletions

View File

@ -41,7 +41,7 @@ class Core::Trace::Policy : public List<Policy>::Element
Allocator &_md_alloc;
Policy_id const _id;
Dataspace_capability _ds;
size_t const _size;
Policy_size const _size;
/**
* Constructor
@ -49,7 +49,7 @@ class Core::Trace::Policy : public List<Policy>::Element
* \param md_alloc allocator that holds the 'Policy' object
*/
Policy(Policy_owner const &owner, Policy_id const id,
Allocator &md_alloc, Dataspace_capability ds, size_t size)
Allocator &md_alloc, Dataspace_capability ds, Policy_size size)
:
_owner(owner), _md_alloc(md_alloc), _id(id), _ds(ds), _size(size)
{ }
@ -66,7 +66,7 @@ class Core::Trace::Policy : public List<Policy>::Element
public:
Dataspace_capability dataspace() const { return _ds; }
size_t size() const { return _size; }
Policy_size size() const { return _size; }
};
@ -81,13 +81,12 @@ class Core::Trace::Policy_registry
Mutex _mutex { };
List<Policy> _policies { };
Policy &_unsynchronized_lookup(Policy_owner const &owner, Policy_id id)
void _with_policy_unsynchronized(Policy_owner const &owner,
Policy_id const id, auto const &fn)
{
for (Policy *p = _policies.first(); p; p = p->next())
if (p->owned_by(owner) && p->has_id(id))
return *p;
throw Nonexistent_policy();
fn(*p);
}
Policy *_any_policy_owned_by(Policy_owner const &owner)
@ -110,7 +109,7 @@ class Core::Trace::Policy_registry
}
void insert(Policy_owner const &owner, Policy_id const id,
Allocator &md_alloc, Dataspace_capability ds, size_t size)
Allocator &md_alloc, Dataspace_capability ds, Policy_size size)
{
Mutex::Guard guard(_mutex);
@ -143,18 +142,22 @@ class Core::Trace::Policy_registry
}
}
Dataspace_capability dataspace(Policy_owner &owner, Policy_id id)
void with_dataspace(Policy_owner &owner, Policy_id id, auto const &fn)
{
Mutex::Guard guard(_mutex);
return _unsynchronized_lookup(owner, id).dataspace();
_with_policy_unsynchronized(owner, id, [&] (Policy &p) {
fn(p.dataspace()); });
}
size_t size(Policy_owner &owner, Policy_id id)
Policy_size size(Policy_owner &owner, Policy_id id)
{
Mutex::Guard guard(_mutex);
return _unsynchronized_lookup(owner, id).size();
Policy_size result { 0 };
_with_policy_unsynchronized(owner, id, [&] (Policy const &p) {
result = p.size(); });
return result;
}
};

View File

@ -30,8 +30,7 @@ namespace Core { namespace Trace { class Session_component; } }
class Core::Trace::Session_component
:
public Session_object<Trace::Session,
Trace::Session_component>,
public Session_object<Trace::Session, Trace::Session_component>,
public Trace::Policy_owner
{
private:
@ -81,17 +80,16 @@ class Core::Trace::Session_component
***********************/
Dataspace_capability dataspace();
size_t subjects();
size_t subject_infos();
Policy_id alloc_policy(size_t) override;
Dataspace_capability policy(Policy_id) override;
void unload_policy(Policy_id) override;
void trace(Subject_id, Policy_id, size_t) override;
void pause(Subject_id) override;
void resume(Subject_id) override;
Dataspace_capability buffer(Subject_id) override;
void free(Subject_id) override;
Subjects_rpc_result subjects();
Infos_rpc_result subject_infos();
Alloc_policy_rpc_result alloc_policy(Policy_size);
Dataspace_capability policy(Policy_id);
void unload_policy(Policy_id);
Trace_rpc_result trace(Subject_id, Policy_id, Buffer_size);
void pause(Subject_id);
void resume(Subject_id);
Dataspace_capability buffer(Subject_id);
void free(Subject_id);
};
#endif /* _CORE__INCLUDE__TRACE__SESSION_COMPONENT_H_ */

View File

@ -166,19 +166,6 @@ class Core::Trace::Subject
return Subject_info::UNATTACHED;
}
void _traceable_or_throw()
{
switch(_state()) {
case Subject_info::DEAD : throw Source_is_dead();
case Subject_info::FOREIGN : throw Traced_by_other_session();
case Subject_info::ERROR : throw Source_is_dead();
case Subject_info::INVALID : throw Nonexistent_subject();
case Subject_info::UNATTACHED : return;
case Subject_info::ATTACHED : return;
case Subject_info::TRACED : return;
}
}
public:
/**
@ -206,31 +193,40 @@ class Core::Trace::Subject
*/
bool has_source_id(Source::Id id) const { return id.value == _source_id.value; }
enum class Trace_result { OK, OUT_OF_RAM, OUT_OF_CAPS, FOREIGN,
SOURCE_IS_DEAD, INVALID_SUBJECT };
/**
* Start tracing
*
* \param size trace buffer size
*
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Source_is_dead
* \throw Traced_by_other_session
*/
void trace(Policy_id policy_id, Dataspace_capability policy_ds,
size_t policy_size, Ram_allocator &ram,
Region_map &local_rm, size_t size)
Trace_result trace(Policy_id policy_id, Dataspace_capability policy_ds,
Policy_size policy_size, Ram_allocator &ram,
Region_map &local_rm, Buffer_size size)
{
/* check state and throw error in case subject is not traceable */
_traceable_or_throw();
_buffer.setup(ram, size); /* may throw */
/* check state and return error if subject is not traceable */
switch(_state()) {
case Subject_info::DEAD: return Trace_result::SOURCE_IS_DEAD;
case Subject_info::ERROR: return Trace_result::SOURCE_IS_DEAD;
case Subject_info::FOREIGN: return Trace_result::FOREIGN;
case Subject_info::INVALID: return Trace_result::INVALID_SUBJECT;
case Subject_info::UNATTACHED:
case Subject_info::ATTACHED:
case Subject_info::TRACED: break;
}
try {
_policy.setup(ram, local_rm, policy_ds, policy_size);
} catch (...) {
_buffer.flush();
throw;
_buffer.setup(ram, size.num_bytes);
}
catch (Out_of_ram) { return Trace_result::OUT_OF_RAM; }
catch (Out_of_caps) { return Trace_result::OUT_OF_CAPS; }
try {
_policy.setup(ram, local_rm, policy_ds, policy_size.num_bytes);
}
catch (Out_of_ram) { _buffer.flush(); return Trace_result::OUT_OF_RAM; }
catch (Out_of_caps) { _buffer.flush(); return Trace_result::OUT_OF_CAPS; }
/* inform trace source about the new buffer */
Locked_ptr<Source> source(_source);
@ -238,12 +234,13 @@ class Core::Trace::Subject
if (!source->try_acquire(*this)) {
_policy.flush();
_buffer.flush();
throw Traced_by_other_session();
return Trace_result::FOREIGN;
}
_policy_id = policy_id;
source->trace(_policy.dataspace(), _buffer.dataspace());
return Trace_result::OK;
}
void pause()
@ -256,17 +253,13 @@ class Core::Trace::Subject
/**
* Resume tracing of paused source
*
* \throw Source_is_dead
*/
void resume()
{
Locked_ptr<Source> source(_source);
if (!source.valid())
throw Source_is_dead();
source->enable();
if (source.valid())
source->enable();
}
Subject_info info()
@ -331,24 +324,19 @@ class Core::Trace::Subject_registry
void _unsynchronized_destroy(Subject &s)
{
_entries.remove(&s);
s.release();
destroy(&_md_alloc, &s);
};
/**
* Obtain subject from given session-local ID
*
* \throw Nonexistent_subject
*/
Subject &_unsynchronized_lookup_by_id(Subject_id id)
void _with_subject_unsynchronized(Subject_id id, auto const &fn)
{
for (Subject *s = _entries.first(); s; s = s->next())
if (s->id() == id)
return *s;
throw Nonexistent_subject();
Subject *ptr = _entries.first();
for (; ptr && (ptr->id().id != id.id); ptr = ptr->next());
if (ptr)
fn(*ptr);
}
public:
@ -404,7 +392,7 @@ class Core::Trace::Subject_registry
/**
* Retrieve existing subject IDs
*/
size_t subjects(Subject_id *dst, size_t dst_len)
unsigned subjects(Subject_id *dst, size_t dst_len)
{
Mutex::Guard guard(_mutex);
@ -417,7 +405,7 @@ class Core::Trace::Subject_registry
/**
* Retrieve Subject_infos batched
*/
size_t subjects(Subject_info * const dst, Subject_id * ids, size_t const len)
unsigned subjects(Subject_info * const dst, Subject_id * ids, size_t const len)
{
Mutex::Guard guard(_mutex);
@ -450,15 +438,15 @@ class Core::Trace::Subject_registry
{
Mutex::Guard guard(_mutex);
Subject &subject = _unsynchronized_lookup_by_id(subject_id);
_unsynchronized_destroy(subject);
_with_subject_unsynchronized(subject_id, [&] (Subject &subject) {
_unsynchronized_destroy(subject); });
}
Subject &lookup_by_id(Subject_id id)
void with_subject(Subject_id id, auto const &fn)
{
Mutex::Guard guard(_mutex);
return _unsynchronized_lookup_by_id(id);
return _with_subject_unsynchronized(id, fn);
}
};

View File

@ -28,100 +28,139 @@ Dataspace_capability Session_component::dataspace()
}
size_t Session_component::subjects()
Session_component::Subjects_rpc_result Session_component::subjects()
{
_subjects.import_new_sources(_sources);
return _subjects.subjects(_argument_buffer.local_addr<Subject_id>(),
_argument_buffer.size()/sizeof(Subject_id));
}
size_t Session_component::subject_infos()
{
_subjects.import_new_sources(_sources);
size_t const count = _argument_buffer.size() / (sizeof(Subject_info) + sizeof(Subject_id));
Subject_info *infos = _argument_buffer.local_addr<Subject_info>();
Subject_id *ids = reinterpret_cast<Subject_id *>(infos + count);
return _subjects.subjects(infos, ids, count);
}
Policy_id Session_component::alloc_policy(size_t size)
{
if (size > _argument_buffer.size())
throw Policy_too_large();
/*
* Using prefix incrementation makes sure a policy with id == 0 is
* invalid.
*/
Policy_id const id(++_policy_cnt);
Ram_dataspace_capability ds_cap = _ram.alloc(size); /* may throw */
try {
_policies.insert(*this, id, _policies_slab, ds_cap, size);
} catch (...) {
_ram.free(ds_cap);
throw;
_subjects.import_new_sources(_sources);
}
catch (Out_of_ram) { return Alloc_rpc_error::OUT_OF_RAM; }
catch (Out_of_caps) { return Alloc_rpc_error::OUT_OF_CAPS; }
return id;
return Num_subjects { _subjects.subjects(_argument_buffer.local_addr<Subject_id>(),
_argument_buffer.size()/sizeof(Subject_id)) };
}
Dataspace_capability Session_component::policy(Policy_id id)
{
return _policies.dataspace(*this, id);
}
void Session_component::unload_policy(Policy_id id)
Session_component::Infos_rpc_result Session_component::subject_infos()
{
try {
Dataspace_capability ds_cap = _policies.dataspace(*this, id);
_subjects.import_new_sources(_sources);
}
catch (Out_of_ram) { return Alloc_rpc_error::OUT_OF_RAM; }
catch (Out_of_caps) { return Alloc_rpc_error::OUT_OF_CAPS; }
unsigned const count = unsigned(_argument_buffer.size() /
(sizeof(Subject_info) + sizeof(Subject_id)));
Subject_info * const infos = _argument_buffer.local_addr<Subject_info>();
Subject_id * const ids = reinterpret_cast<Subject_id *>(infos + count);
return Num_subjects { _subjects.subjects(infos, ids, count) };
}
Session_component::Alloc_policy_rpc_result Session_component::alloc_policy(Policy_size size)
{
size.num_bytes = min(size.num_bytes, _argument_buffer.size());
Policy_id const id { ++_policy_cnt };
return _ram.try_alloc(size.num_bytes).convert<Alloc_policy_rpc_result>(
[&] (Ram_dataspace_capability const ds_cap) -> Alloc_policy_rpc_result {
try {
_policies.insert(*this, id, _policies_slab, ds_cap, size);
}
catch (Out_of_ram) { _ram.free(ds_cap); return Alloc_policy_rpc_error::OUT_OF_RAM; }
catch (Out_of_caps) { _ram.free(ds_cap); return Alloc_policy_rpc_error::OUT_OF_CAPS; }
return id;
},
[&] (Ram_allocator::Alloc_error const e) -> Alloc_policy_rpc_result {
switch (e) {
case Ram_allocator::Alloc_error::OUT_OF_RAM: return Alloc_policy_rpc_error::OUT_OF_RAM;
case Ram_allocator::Alloc_error::OUT_OF_CAPS: return Alloc_policy_rpc_error::OUT_OF_CAPS;
case Ram_allocator::Alloc_error::DENIED: break;
}
return Alloc_policy_rpc_error::INVALID;
});
}
Dataspace_capability Session_component::policy(Policy_id const id)
{
Dataspace_capability result { };
_policies.with_dataspace(*this, id, [&] (Dataspace_capability ds) {
result = ds; });
return result;
}
void Session_component::unload_policy(Policy_id const id)
{
_policies.with_dataspace(*this, id, [&] (Dataspace_capability ds) {
_policies.remove(*this, id);
_ram.free(static_cap_cast<Ram_dataspace>(ds_cap));
} catch (Nonexistent_policy) { }
_ram.free(static_cap_cast<Ram_dataspace>(ds)); });
}
void Session_component::trace(Subject_id subject_id, Policy_id policy_id,
size_t buffer_size)
Session_component::Trace_rpc_result
Session_component::trace(Subject_id subject_id, Policy_id policy_id, Buffer_size size)
{
size_t const policy_size = _policies.size(*this, policy_id);
Policy_size const policy_size = _policies.size(*this, policy_id);
Trace::Subject &subject = _subjects.lookup_by_id(subject_id);
if (policy_size.num_bytes == 0)
return Trace_rpc_error::INVALID_POLICY;
subject.trace(policy_id, _policies.dataspace(*this, policy_id),
policy_size, _ram, _local_rm, buffer_size);
Dataspace_capability const ds = policy(policy_id);
auto rpc_result = [] (Subject::Trace_result const result) -> Trace_rpc_result
{
using Result = Subject::Trace_result;
switch (result) {
case Result::OK: return Trace_ok { };
case Result::OUT_OF_RAM: return Trace_rpc_error::OUT_OF_RAM;
case Result::OUT_OF_CAPS: return Trace_rpc_error::OUT_OF_CAPS;
case Result::FOREIGN: return Trace_rpc_error::FOREIGN;
case Result::SOURCE_IS_DEAD: return Trace_rpc_error::SOURCE_IS_DEAD;
case Result::INVALID_SUBJECT: break;
};
return Trace_rpc_error::INVALID_SUBJECT;
};
Trace_rpc_result result = Trace_rpc_error::INVALID_SUBJECT;
_subjects.with_subject(subject_id, [&] (Subject &subject) {
result = rpc_result(subject.trace(policy_id, ds, policy_size, _ram,
_local_rm, size)); });
return result;
}
void Session_component::pause(Subject_id subject_id)
void Session_component::pause(Subject_id id)
{
_subjects.lookup_by_id(subject_id).pause();
_subjects.with_subject(id, [&] (Subject &subject) { subject.pause(); });
}
void Session_component::resume(Subject_id subject_id)
void Session_component::resume(Subject_id id)
{
_subjects.lookup_by_id(subject_id).resume();
_subjects.with_subject(id, [&] (Subject &subject) { subject.resume(); });
}
Dataspace_capability Session_component::buffer(Subject_id subject_id)
Dataspace_capability Session_component::buffer(Subject_id id)
{
return _subjects.lookup_by_id(subject_id).buffer();
Dataspace_capability result { };
_subjects.with_subject(id, [&] (Subject &subject) {
result = subject.buffer(); });
return result;
}
void Session_component::free(Subject_id subject_id)
void Session_component::free(Subject_id id)
{
_subjects.release(subject_id);
_subjects.release(id);
}