mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-21 16:39:39 +00:00
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:
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user