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

@ -23,18 +23,12 @@
namespace Genode { namespace Trace {
/*********************
** Exception types **
*********************/
using Thread_name = String<32>;
struct Policy_too_large : Exception { };
struct Nonexistent_subject : Exception { };
struct Source_is_dead : Exception { };
struct Nonexistent_policy : Exception { };
struct Traced_by_other_session : Exception { };
struct Subject_not_traced : Exception { };
typedef String<32> Thread_name;
struct Num_subjects { unsigned value; };
struct Policy_size { size_t num_bytes; };
struct Buffer_size { size_t num_bytes; };
struct Trace_ok { };
struct Policy_id;
struct Subject_id;
@ -48,10 +42,7 @@ namespace Genode { namespace Trace {
*/
struct Genode::Trace::Policy_id
{
unsigned id;
Policy_id() : id(0) { }
Policy_id(unsigned id) : id(id) { }
unsigned id { };
bool operator == (Policy_id const &other) const { return id == other.id; }
};
@ -62,10 +53,7 @@ struct Genode::Trace::Policy_id
*/
struct Genode::Trace::Subject_id
{
unsigned id;
Subject_id() : id(0) { }
Subject_id(unsigned id) : id(id) { }
unsigned id { };
bool operator == (Subject_id const &other) const { return id == other.id; }
};

View File

@ -1,131 +0,0 @@
/*
* \brief Client-side TRACE session interface
* \author Norman Feske
* \date 2013-08-12
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _INCLUDE__TRACE_SESSION__CLIENT_H_
#define _INCLUDE__TRACE_SESSION__CLIENT_H_
#include <trace_session/trace_session.h>
#include <base/rpc_client.h>
#include <base/env.h>
namespace Genode { namespace Trace { struct Session_client; } }
struct Genode::Trace::Session_client : Genode::Rpc_client<Genode::Trace::Session>
{
private:
/**
* Shared-memory buffer used for carrying the payload of the
* 'subjects()' RPC function.
*/
class Argument_buffer
{
private:
/*
* Noncopyable
*/
Argument_buffer(Argument_buffer const &);
Argument_buffer &operator = (Argument_buffer const &);
public:
Region_map &rm;
char *base;
size_t size;
Argument_buffer(Region_map &rm, Dataspace_capability ds)
:
rm(rm),
base(rm.attach(ds)),
size(ds.call<Dataspace::Rpc_size>())
{ }
~Argument_buffer()
{
rm.detach(base);
}
};
Argument_buffer _argument_buffer;
public:
/**
* Constructor
*/
explicit Session_client(Region_map &rm, Capability<Trace::Session> session)
:
Rpc_client<Trace::Session>(session),
_argument_buffer(rm, call<Rpc_dataspace>())
{ }
/**
* Retrieve subject directory
*
* \throw Out_of_ram
* \throw Out_of_caps
*/
virtual size_t subjects(Subject_id *dst, size_t dst_len)
{
size_t const num_subjects = min(call<Rpc_subjects>(), dst_len);
memcpy(dst, _argument_buffer.base, num_subjects*sizeof(Subject_id));
return num_subjects;
}
struct For_each_subject_info_result { size_t count; size_t limit; };
For_each_subject_info_result for_each_subject_info(auto const &fn)
{
size_t const num_subjects = call<Rpc_subject_infos>();
size_t const max_subjects = _argument_buffer.size / (sizeof(Subject_info) + sizeof(Subject_id));
Subject_info * const infos = reinterpret_cast<Subject_info *>(_argument_buffer.base);
Subject_id * const ids = reinterpret_cast<Subject_id *>(infos + max_subjects);
for (unsigned i = 0; i < num_subjects; i++) {
fn(ids[i], infos[i]);
}
return { .count = num_subjects, .limit = max_subjects };
}
Policy_id alloc_policy(size_t size) override {
return call<Rpc_alloc_policy>(size); }
Dataspace_capability policy(Policy_id policy_id) override {
return call<Rpc_policy>(policy_id); }
void unload_policy(Policy_id policy_id) override {
call<Rpc_unload_policy>(policy_id); }
void trace(Subject_id s, Policy_id p, size_t buffer_size) override {
call<Rpc_trace>(s, p, buffer_size); }
void pause(Subject_id subject) override {
call<Rpc_pause>(subject); }
void resume(Subject_id subject) override {
call<Rpc_resume>(subject); }
Dataspace_capability buffer(Subject_id subject) override {
return call<Rpc_buffer>(subject); }
void free(Subject_id subject) override {
call<Rpc_free>(subject); }
};
#endif /* _INCLUDE__TRACE_SESSION__CLIENT_H_ */

View File

@ -15,18 +15,36 @@
#define _INCLUDE__TRACE_SESSION__CONNECTION_H_
#include <util/retry.h>
#include <trace_session/client.h>
#include <trace_session/trace_session.h>
#include <base/rpc_client.h>
#include <base/connection.h>
#include <base/attached_dataspace.h>
namespace Genode { namespace Trace { struct Connection; } }
struct Genode::Trace::Connection : Genode::Connection<Genode::Trace::Session>,
Genode::Trace::Session_client
Genode::Rpc_client<Genode::Trace::Session>
{
/**
* Shared-memory buffer used for carrying the payload of subject infos
*/
Attached_dataspace _argument_buffer;
size_t const _max_arg_size;
template <typename ERROR>
auto _retry(auto const &fn) -> decltype(fn())
{
return retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2}, fn);
for (;;) {
bool retry = false;
auto const result = fn();
if (result == ERROR::OUT_OF_CAPS) { upgrade_caps(2); retry = true; }
if (result == ERROR::OUT_OF_RAM) { upgrade_ram(8*1024); retry = true; }
if (!retry)
return result;
}
}
/**
@ -39,31 +57,141 @@ struct Genode::Trace::Connection : Genode::Connection<Genode::Trace::Session>,
:
Genode::Connection<Session>(env, Label(), Ram_quota { 10*1024 + ram_quota },
Args("arg_buffer_size=", arg_buffer_size)),
Session_client(env.rm(), cap())
Genode::Rpc_client<Session>(cap()),
_argument_buffer(env.rm(), call<Rpc_dataspace>()),
_max_arg_size(arg_buffer_size)
{ }
Policy_id alloc_policy(size_t size) override
enum class Alloc_policy_error { INVALID };
using Alloc_policy_result = Attempt<Policy_id, Alloc_policy_error>;
/**
* Allocate policy-module backing store
*/
Alloc_policy_result alloc_policy(Policy_size size)
{
return _retry([&] () {
return Session_client::alloc_policy(size); });
if (size.num_bytes > _max_arg_size)
return Alloc_policy_error::INVALID;
Alloc_policy_rpc_result const result = _retry<Alloc_policy_rpc_error>([&] {
return call<Rpc_alloc_policy>(size); });
return result.convert<Alloc_policy_result>(
[&] (Policy_id const id) { return id; },
[&] (Alloc_policy_rpc_error) { return Alloc_policy_error::INVALID; });
}
void trace(Subject_id s, Policy_id p, size_t buffer_size) override
/**
* Request policy-module backing store
*
* \return dataspace capability, or invalid capability if ID does not
* refer to a known policy
*/
Dataspace_capability policy(Policy_id id) { return call<Rpc_policy>(id); }
/**
* Remove a policy module from the TRACE service
*/
void unload_policy(Policy_id id) { call<Rpc_unload_policy>(id); }
enum class Trace_error { FOREIGN, SOURCE_IS_DEAD, INVALID_SUBJECT, INVALID_POLICY };
using Trace_result = Attempt<Trace_ok, Trace_error>;
/**
* Start tracing of a subject
*/
Trace_result trace(Subject_id const s, Policy_id const p, Buffer_size const size)
{
_retry([&] () { Session_client::trace(s, p, buffer_size); });
Trace_rpc_result const rpc_result =
_retry<Trace_rpc_error>([&] () -> Trace_rpc_result {
return call<Rpc_trace>(s, p, size); });
return rpc_result.convert<Trace_result>(
[&] (Trace_ok ok) { return ok; },
[&] (Trace_rpc_error e) {
switch (e) {
case Trace_rpc_error::OUT_OF_RAM: /* cannot occur, handled by '_retry' above */
case Trace_rpc_error::OUT_OF_CAPS: break;
case Trace_rpc_error::FOREIGN: return Trace_error::FOREIGN;
case Trace_rpc_error::SOURCE_IS_DEAD: return Trace_error::SOURCE_IS_DEAD;
case Trace_rpc_error::INVALID_SUBJECT: return Trace_error::INVALID_SUBJECT;
case Trace_rpc_error::INVALID_POLICY: break;
}
return Trace_error::INVALID_POLICY;
});
}
size_t subjects(Subject_id *dst, size_t dst_len) override
/**
* Retrieve subject directory
*/
Num_subjects subjects(Subject_id * const dst, Num_subjects const dst_num_subjects)
{
return _retry([&] () {
return Session_client::subjects(dst, dst_len); });
Subjects_rpc_result const result = _retry<Alloc_rpc_error>([&] {
return call<Rpc_subjects>(); });
return result.convert<Num_subjects>(
[&] (Num_subjects const num_subjects) {
auto const n = min(num_subjects.value, dst_num_subjects.value);
memcpy(dst, _argument_buffer.local_addr<char>(), n*sizeof(Subject_id));
return Num_subjects { n };
},
[&] (Alloc_rpc_error) { return Num_subjects { 0 }; });
}
struct For_each_subject_info_result { unsigned count; unsigned limit; };
/**
* Call 'fn' for each trace subject with 'Subject_info' as argument
*/
For_each_subject_info_result for_each_subject_info(auto const &fn)
{
return _retry([&] () {
return Session_client::for_each_subject_info(fn); });
Infos_rpc_result const result = _retry<Alloc_rpc_error>([&] {
return call<Rpc_subject_infos>(); });
return result.convert<For_each_subject_info_result>(
[&] (Num_subjects const n) -> For_each_subject_info_result {
size_t const subject_bytes = sizeof(Subject_info) + sizeof(Subject_id);
unsigned const max_subjects = unsigned(_argument_buffer.size() / subject_bytes);
Subject_info * const infos = _argument_buffer.local_addr<Subject_info>();
Subject_id * const ids = reinterpret_cast<Subject_id *>(infos + max_subjects);
for (unsigned i = 0; i < n.value; i++)
fn(ids[i], infos[i]);
return { .count = n.value, .limit = max_subjects };
},
[&] (Alloc_rpc_error) { return For_each_subject_info_result { }; });
}
/**
* Release subject and free buffers
*
* If the source still exists, the buffers are freed but the subject
* stays intact.
*/
void free(Subject_id id) { call<Rpc_free>(id); }
/**
* Pause generation of tracing data
*/
void pause(Subject_id id) { call<Rpc_pause>(id); }
/**
* Resume generation of tracing data
*/
void resume(Subject_id id) { call<Rpc_resume>(id); }
/**
* Obtain trace buffer of given subject
*/
Dataspace_capability buffer(Subject_id id) { return call<Rpc_buffer>(id); }
};
#endif /* _INCLUDE__TRACE_SESSION__CONNECTION_H_ */

View File

@ -14,7 +14,7 @@
#ifndef _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_
#define _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_
#include <base/exception.h>
#include <util/attempt.h>
#include <base/trace/types.h>
#include <dataspace/capability.h>
#include <session/session.h>
@ -31,69 +31,17 @@ struct Genode::Trace::Session : Genode::Session
enum { CAP_QUOTA = 6 };
/**
* Allocate policy-module backing store
*
* \throw Out_of_ram
* \throw Out_of_caps
*/
virtual Policy_id alloc_policy(size_t size) = 0;
enum class Alloc_rpc_error { OUT_OF_RAM, OUT_OF_CAPS };
enum class Alloc_policy_rpc_error { OUT_OF_RAM, OUT_OF_CAPS, INVALID };
enum class Trace_rpc_error { OUT_OF_RAM, OUT_OF_CAPS, FOREIGN,
SOURCE_IS_DEAD, INVALID_SUBJECT,
INVALID_POLICY };
/**
* Request policy-module backing store
*
* \throw Nonexistent_policy
*/
virtual Dataspace_capability policy(Policy_id) = 0;
using Alloc_policy_rpc_result = Attempt<Policy_id, Alloc_policy_rpc_error>;
using Subjects_rpc_result = Attempt<Num_subjects, Alloc_rpc_error>;
using Infos_rpc_result = Attempt<Num_subjects, Alloc_rpc_error>;
using Trace_rpc_result = Attempt<Trace_ok, Trace_rpc_error>;
/**
* Remove a policy module from the TRACE service
*/
virtual void unload_policy(Policy_id) = 0;
/**
* Start tracing of a subject
*
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Source_is_dead
* \throw Nonexistent_policy
* \throw Nonexistent_subject
* \throw Traced_by_other_session
*/
virtual void trace(Subject_id, Policy_id, size_t buffer_size) = 0;
/**
* Pause generation of tracing data
*
* \throw Nonexistent_subject
*/
virtual void pause(Subject_id) = 0;
/**
* Resume generation of tracing data
*
* \throw Nonexistent_subject
* \throw Source_is_dead
*/
virtual void resume(Subject_id) = 0;
/**
* Obtain trace buffer of given subject
*
* \throw Nonexistent_subject
*/
virtual Dataspace_capability buffer(Subject_id) = 0;
/**
* Release subject and free buffers
*
* If the source still exists, the buffers are freed but the subject
* stays intact.
*
* \throw Nonexistent_subject
*/
virtual void free(Subject_id) = 0;
virtual ~Session() { }
@ -103,34 +51,16 @@ struct Genode::Trace::Session : Genode::Session
*********************/
GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace);
GENODE_RPC_THROW(Rpc_alloc_policy, Policy_id, alloc_policy,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
size_t);
GENODE_RPC_THROW(Rpc_policy, Dataspace_capability, policy,
GENODE_TYPE_LIST(Nonexistent_policy),
Policy_id);
GENODE_RPC_THROW(Rpc_unload_policy, void, unload_policy,
GENODE_TYPE_LIST(Nonexistent_policy), Policy_id);
GENODE_RPC_THROW(Rpc_trace, void, trace,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps,
Source_is_dead, Nonexistent_subject,
Nonexistent_policy,
Traced_by_other_session),
Subject_id, Policy_id, size_t);
GENODE_RPC_THROW(Rpc_pause, void, pause,
GENODE_TYPE_LIST(Nonexistent_subject), Subject_id);
GENODE_RPC_THROW(Rpc_resume, void, resume,
GENODE_TYPE_LIST(Nonexistent_subject, Source_is_dead),
Subject_id);
GENODE_RPC_THROW(Rpc_subjects, size_t, subjects,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps));
GENODE_RPC_THROW(Rpc_subject_infos, size_t, subject_infos,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps));
GENODE_RPC_THROW(Rpc_buffer, Dataspace_capability, buffer,
GENODE_TYPE_LIST(Nonexistent_subject, Subject_not_traced),
Subject_id);
GENODE_RPC_THROW(Rpc_free, void, free,
GENODE_TYPE_LIST(Nonexistent_subject), Subject_id);
GENODE_RPC(Rpc_alloc_policy, Alloc_policy_rpc_result, alloc_policy, Policy_size);
GENODE_RPC(Rpc_policy, Dataspace_capability, policy, Policy_id);
GENODE_RPC(Rpc_unload_policy, void, unload_policy, Policy_id);
GENODE_RPC(Rpc_trace, Trace_rpc_result, trace, Subject_id, Policy_id, Buffer_size);
GENODE_RPC(Rpc_pause, void, pause, Subject_id);
GENODE_RPC(Rpc_resume, void, resume, Subject_id);
GENODE_RPC(Rpc_subjects, Subjects_rpc_result, subjects);
GENODE_RPC(Rpc_subject_infos, Infos_rpc_result, subject_infos);
GENODE_RPC(Rpc_buffer, Dataspace_capability, buffer, Subject_id);
GENODE_RPC(Rpc_free, void, free, Subject_id);
GENODE_RPC_INTERFACE(Rpc_dataspace, Rpc_alloc_policy, Rpc_policy,
Rpc_unload_policy, Rpc_trace, Rpc_pause,

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);
}

View File

@ -108,7 +108,7 @@ void Trace_recorder::Monitor::start(Xml_node config)
trace_config.session_arg_buffer);
/* find matching subjects according to config and start tracing */
using SC = Genode::Trace::Session_client;
using SC = Genode::Trace::Connection;
SC::For_each_subject_info_result const info_result =
_trace->for_each_subject_info([&] (Trace::Subject_id const &id,
Trace::Subject_info const &info) {
@ -123,16 +123,28 @@ void Trace_recorder::Monitor::start(Xml_node config)
if (!session_policy.has_attribute("policy"))
return;
Number_of_bytes buffer_sz =
Trace::Buffer_size const buffer_size {
session_policy.attribute_value("buffer",
Number_of_bytes(trace_config.default_buf_sz));
Number_of_bytes(trace_config.default_buf_sz)) };
Policy::Name const policy_name = session_policy.attribute_value("policy", Policy::Name());
auto trace = [&] (Policy const &policy)
{
policy.id().with_result(
[&] (Trace::Policy_id const policy_id) {
if (_trace->trace(id, policy_id, buffer_size).failed())
warning("failed to enable tracing for policy '", policy_name, "'");
},
[&] (Trace::Connection::Alloc_policy_error) {
warning("skip tracing because of missing policy"); });
};
/* find and assign policy; create/insert if not present */
Policy::Name const policy_name = session_policy.attribute_value("policy", Policy::Name());
bool const create =
_policies.with_element(policy_name,
[&] /* match */ (Policy & policy) {
_trace->trace(id, policy.id(), buffer_sz);
trace(policy);
return false;
},
[&] /* no_match */ { return true; }
@ -141,7 +153,7 @@ void Trace_recorder::Monitor::start(Xml_node config)
/* create policy if it did not exist */
if (create) {
Policy &policy = *new (_alloc) Policy(_env, *_trace, policy_name, _policies);
_trace->trace(id, policy.id(), buffer_sz);
trace(policy);
}
log("Inserting trace policy \"", policy_name, "\" into ",
@ -197,23 +209,19 @@ void Trace_recorder::Monitor::stop()
_timer.trigger_periodic(0);
_trace_buffers.for_each([&] (Attached_buffer &buf) {
try {
/* stop tracing */
_trace->pause(buf.subject_id());
} catch (Trace::Nonexistent_subject) { }
/* stop tracing */
_trace->pause(buf.subject_id());
/* read remaining events from buffers */
buf.process_events(*_trace_directory);
/* destroy writers */
buf.writers().for_each([&] (Writer_base &writer) {
destroy(_alloc, &writer);
});
destroy(_alloc, &writer); });
try {
/* detach buffer */
_trace->free(buf.subject_id());
} catch (Trace::Nonexistent_subject) { }
/* detach buffer */
_trace->free(buf.subject_id());
/* destroy buffer */
destroy(_alloc, &buf);

View File

@ -16,18 +16,27 @@
using namespace Genode;
Trace_recorder::Policy::Policy(Env &env,
Trace::Connection &trace,
Policy::Name const &name,
Policies &policies)
:
Policies::Element(policies, name),
_env(env), _trace(trace), _rom(env, name.string())
Trace_recorder::Policy::Id Trace_recorder::Policy::_init_policy()
{
Dataspace_capability dst_ds = _trace.policy(_id);
void *dst = _env.rm().attach(dst_ds);
void *src = _env.rm().attach(_ds);
memcpy(dst, src, _size);
_env.rm().detach(dst);
_env.rm().detach(src);
Id const id = _trace.alloc_policy(_size);
id.with_result(
[&] (Trace::Policy_id const policy_id) {
Dataspace_capability dst_ds = _trace.policy(policy_id);
if (!dst_ds.valid()) {
warning("unable to obtain policy buffer");
return;
}
Attached_dataspace const src { _env.rm(), _ds };
Attached_dataspace dst { _env.rm(), dst_ds };
memcpy(dst.local_addr<char>(), src.local_addr<char const>(), _size.num_bytes);
},
[&] (Trace::Connection::Alloc_policy_error) {
warning("failed to allocate policy buffer"); });
return id;
}

View File

@ -33,6 +33,12 @@ namespace Trace_recorder {
*/
class Trace_recorder::Policy : Policies::Element
{
public:
using Id = Genode::Trace::Connection::Alloc_policy_result;
using Name = Policy_name;
using Policies::Element::name;
private:
friend class Genode::Dictionary<Policy, Policy_name>;
friend class Genode::Avl_node<Policy>;
@ -42,25 +48,27 @@ class Trace_recorder::Policy : Policies::Element
Genode::Trace::Connection &_trace;
Genode::Rom_connection _rom;
Genode::Rom_dataspace_capability const _ds { _rom.dataspace() };
Genode::size_t const _size { Genode::Dataspace_client(_ds).size() };
Genode::Trace::Policy_id const _id { _trace.alloc_policy(_size) };
Genode::Trace::Policy_size const _size { Genode::Dataspace_client(_ds).size() };
Id _init_policy();
Id const _id = _init_policy();
public:
using Name = Policy_name;
using Policies::Element::name;
Policy(Genode::Env &env,
Genode::Trace::Connection &trace,
Name const &name,
Policies &policies);
Policies &policies)
:
Policies::Element(policies, name),
_env(env), _trace(trace), _rom(env, name.string())
{ }
/***************
** Accessors **
***************/
Genode::Trace::Policy_id id() const { return _id; }
Id id() const { return _id; }
};
#endif /* _POLICY_H_ */

View File

@ -55,7 +55,7 @@ class Vfs::Trace_node : public Dictionary::Element
public:
Trace_node(Allocator &alloc, Dictionary &dict, Session_label const &label,
Trace::Subject_id const id = 0)
Trace::Subject_id const id = { })
:
Dictionary::Element(dict, Label(label)),
_alloc(alloc), _id(id)
@ -85,7 +85,7 @@ class Vfs::Trace_node : public Dictionary::Element
void xml(Xml_generator &xml) const
{
_dict.for_each([&] (Trace_node const &node) {
if (node.id() == 0)
if (node.id().id == 0)
xml.node("dir", [&] () {
xml.attribute("name", node.name);
node.xml(xml);

View File

@ -12,6 +12,7 @@
*/
#include <base/attached_rom_dataspace.h>
#include <base/attached_dataspace.h>
#include <vfs/dir_file_system.h>
#include <vfs/single_file_system.h>
#include <vfs/value_file_system.h>
@ -74,11 +75,13 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system
enum State { OFF, TRACE, PAUSED } _state { OFF };
using Policy_id = Trace::Connection::Alloc_policy_result;
Vfs::Env &_env;
Trace::Connection &_trace;
Trace::Policy_id _policy;
Policy_id _policy;
Trace::Subject_id _id;
size_t _buffer_size { 1024 * 1024 };
Trace::Buffer_size _buffer_size { 1024 * 1024 };
size_t _stat_size { 0 };
Trace_entries _entries { _env };
@ -98,12 +101,14 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system
{
_entries.flush();
try {
_trace.trace(_id, _policy, _buffer_size);
} catch (...) {
error("failed to start tracing");
return;
}
_policy.with_result(
[&] (Trace::Policy_id policy_id) {
if (_trace.trace(_id, policy_id, _buffer_size).failed())
error("failed to start tracing");
},
[&] (Trace::Connection::Alloc_policy_error) {
warning("skip tracing because of invalid policy");
});
_entries.setup(_trace.buffer(_id));
}
@ -196,9 +201,9 @@ class Vfs_trace::Trace_buffer_file_system : public Single_file_system
** FS event handlers **
***********************/
bool resize_buffer(size_t size)
bool resize_buffer(Trace::Buffer_size size)
{
if (size == 0) return false;
if (size.num_bytes == 0) return false;
_buffer_size = size;
@ -317,7 +322,7 @@ class Vfs_trace::Subject : private Subject_factory,
void _buffer_size()
{
Number_of_bytes size = _buffer_size_fs.value();
Trace::Buffer_size const size { _buffer_size_fs.value() };
if (_trace_fs.resize_buffer(size) == false) {
/* restore old value */
@ -332,7 +337,7 @@ class Vfs_trace::Subject : private Subject_factory,
Subject(Vfs::Env &env, Trace::Connection &trace,
Trace::Policy_id policy, Xml_node node)
: Subject_factory(env, trace, policy, node.attribute_value("id", 0u)),
: Subject_factory(env, trace, policy, { node.attribute_value("id", 0u) }),
Dir_file_system(env, Xml_node(_config(node).string()), *this)
{ }
@ -344,11 +349,12 @@ class Vfs_trace::Subject : private Subject_factory,
struct Vfs_trace::Local_factory : File_system_factory
{
Vfs::Env &_env;
using Policy_id = Trace::Connection::Alloc_policy_result;
Trace::Connection _trace;
Trace::Policy_id _policy_id { 0 };
Trace_directory _directory { _env.alloc() };
Vfs::Env &_env;
Trace::Connection _trace;
Policy_id _policy_id = Trace::Connection::Alloc_policy_error::INVALID;
Trace_directory _directory { _env.alloc() };
void _install_null_policy()
{
@ -357,7 +363,7 @@ struct Vfs_trace::Local_factory : File_system_factory
try {
null_policy.construct(_env.env(), "null");
_policy_id = _trace.alloc_policy(null_policy->size());
_policy_id = _trace.alloc_policy(Trace::Policy_size { null_policy->size() });
}
catch (Out_of_caps) { throw; }
catch (Out_of_ram) { throw; }
@ -368,9 +374,16 @@ struct Vfs_trace::Local_factory : File_system_factory
}
/* copy policy into trace session */
void *dst = _env.env().rm().attach(_trace.policy(_policy_id));
memcpy(dst, null_policy->local_addr<void*>(), null_policy->size());
_env.env().rm().detach(dst);
_policy_id.with_result(
[&] (Trace::Policy_id const id) {
Dataspace_capability ds_cap = _trace.policy(id);
if (ds_cap.valid()) {
Attached_dataspace dst { _env.env().rm(), ds_cap };
memcpy(dst.local_addr<char>(), null_policy->local_addr<void*>(), null_policy->size());
}
},
[&] (Trace::Connection::Alloc_policy_error) { }
);
}
size_t _config_session_ram(Xml_node config)
@ -399,10 +412,15 @@ struct Vfs_trace::Local_factory : File_system_factory
Vfs::File_system *create(Vfs::Env&, Xml_node node) override
{
if (node.has_type(Subject::type_name()))
return new (_env.alloc()) Subject(_env, _trace, _policy_id, node);
Vfs::File_system *result = nullptr;
return nullptr;
if (node.has_type(Subject::type_name()))
_policy_id.with_result(
[&] (Trace::Policy_id const id) {
result = new (_env.alloc()) Subject(_env, _trace, id, node); },
[&] (Trace::Connection::Alloc_policy_error) { });
return result;
}
};

View File

@ -162,8 +162,7 @@ class Main
if (_config.verbose)
log("destroy monitor: subject ", monitor.subject_id().id);
try { _trace.free(monitor.subject_id()); }
catch (Trace::Nonexistent_subject) { }
_trace.free(monitor.subject_id());
monitors.remove(&monitor);
destroy(_heap, &monitor);
}
@ -172,32 +171,30 @@ class Main
Trace::Subject_id const id,
Xml_node const &session_policy)
{
auto warn_msg = [] (auto reason) {
warning("Cannot activate tracing: ", reason); };
Trace::Buffer_size const buffer_size {
session_policy.attribute_value("buffer", Number_of_bytes(_config.default_buf_sz)) };
try {
Number_of_bytes const buffer_sz =
session_policy.attribute_value("buffer", Number_of_bytes(_config.default_buf_sz));
Policy_name const policy_name =
session_policy.attribute_value("policy", _config.default_policy_name);
Policy_name const policy_name =
session_policy.attribute_value("policy", _config.default_policy_name);
auto trace = [&] (Policy const &policy)
{
policy.id.with_result(
[&] (Trace::Policy_id const policy_id) {
_trace.trace(id, policy_id, buffer_size); },
[&] (auto) {
warning("skip tracing because of invalid policy '", policy_name, "'");
});
};
_policies.with_element(policy_name,
[&] (Policy const &policy) {
_trace.trace(id.id, policy.id(), buffer_sz);
},
[&] /* no match */ {
Policy &policy = *new (_heap) Policy(_env, _trace, _policies, policy_name);
_trace.trace(id.id, policy.id(), buffer_sz);
}
);
monitors.insert(new (_heap) Monitor(_trace, _env.rm(), id));
}
catch (Trace::Source_is_dead ) { warn_msg("Source_is_dead" ); return; }
catch (Trace::Nonexistent_policy ) { warn_msg("Nonexistent_policy" ); return; }
catch (Trace::Traced_by_other_session) { warn_msg("Traced_by_other_session"); return; }
catch (Trace::Nonexistent_subject ) { warn_msg("Nonexistent_subject" ); return; }
catch (Region_map::Invalid_dataspace ) { warn_msg("Loading policy failed" ); return; }
_policies.with_element(policy_name,
[&] (Policy const &policy) {
trace(policy); },
[&] /* no match */ {
Policy &policy = *new (_heap) Policy(_env, _trace, _policies, policy_name);
trace(policy); });
monitors.insert(new (_heap) Monitor(_trace, _env.rm(), id));
}
void _handle_period(Duration)

View File

@ -22,10 +22,20 @@ Policy::Policy(Env &env, Trace::Connection &trace, Policy_dict &dict,
:
Policy_dict::Element(dict, name), _env(env), _trace(trace)
{
Dataspace_capability dst_ds = _trace.policy(_id);
void *dst = _env.rm().attach(dst_ds);
void *src = _env.rm().attach(_ds);
memcpy(dst, src, _size);
_env.rm().detach(dst);
_env.rm().detach(src);
id.with_result(
[&] (Trace::Policy_id id) {
Dataspace_capability const dst_ds = _trace.policy(id);
if (dst_ds.valid()) {
void * const dst = _env.rm().attach(dst_ds);
void const * const src = _env.rm().attach(_ds);
memcpy(dst, src, _size);
_env.rm().detach(dst);
_env.rm().detach(src);
return;
}
warning("failed to obtain policy buffer for '", name, "'");
},
[&] (Trace::Connection::Alloc_policy_error) {
warning("failed to allocate policy buffer for '", name, "'");
});
}

View File

@ -38,16 +38,17 @@ class Policy : public Policy_dict::Element
Genode::Rom_connection _rom { _env, name };
Genode::Rom_dataspace_capability const _ds { _rom.dataspace() };
Genode::size_t const _size { Genode::Dataspace_client(_ds).size() };
Genode::Trace::Policy_id const _id { _trace.alloc_policy(_size) };
public:
using Id = Genode::Trace::Connection::Alloc_policy_result;
Id const id { _trace.alloc_policy({_size}) };
Policy(Genode::Env &env,
Genode::Trace::Connection &trace,
Policy_dict &dict,
Policy_name const &name);
Genode::Trace::Policy_id id() const { return _id; }
};
#endif /* _POLICY_H_ */

View File

@ -58,8 +58,9 @@ struct Trace_subject_registry
return nullptr;
}
enum { MAX_SUBJECTS = 512 };
Genode::Trace::Subject_id _subjects[MAX_SUBJECTS];
static constexpr Genode::Trace::Num_subjects MAX_SUBJECTS { 512 };
Genode::Trace::Subject_id _subjects[MAX_SUBJECTS.value];
void _sort_by_recent_execution_time()
{
@ -81,14 +82,6 @@ struct Trace_subject_registry
_entries = sorted;
}
unsigned update_subjects(Genode::Trace::Connection &trace)
{
return (unsigned)Genode::retry<Genode::Out_of_ram>(
[&] () { return trace.subjects(_subjects, MAX_SUBJECTS); },
[&] () { trace.upgrade_ram(4096); }
);
}
public:
void update(Genode::Trace::Connection &trace, Genode::Allocator &alloc)

View File

@ -39,21 +39,24 @@ void Cpu::Session::update_threads(Trace &trace, Session_label const &cpu_balance
Execution_time time { };
/* request execution time and current location */
try {
trace.retrieve(subject_id.id, [&] (Execution_time const time_current,
Affinity::Location const current_loc)
{
current = current_loc;
time = time_current;
bool subject_exists = false;
trace.retrieve(subject_id, [&] (Execution_time const time_current,
Affinity::Location const current_loc)
{
subject_exists = true;
if (_verbose)
log("[", _label, "] name='", name, "' at ",
current_loc.xpos(), "x", current_loc.ypos(),
" has ec/sc time ", time.thread_context, "/",
time.scheduling_context,
" policy=", policy.string());
});
} catch (Genode::Trace::Nonexistent_subject) {
current = current_loc;
time = time_current;
if (_verbose)
log("[", _label, "] name='", name, "' at ",
current_loc.xpos(), "x", current_loc.ypos(),
" has ec/sc time ", time.thread_context, "/",
time.scheduling_context,
" policy=", policy.string());
});
if (!subject_exists) {
/* how could that be ? */
error("[", _label, "] name='", name, "'"
" subject id invalid ?? ", subject_id.id);

View File

@ -64,9 +64,8 @@ class Cpu::Trace
* stored trace ids are not valid if used with subject_info(id)
* and we get exception thrown about unknown ids.
*/
_trace->_retry([&] () {
_trace->call<Genode::Trace::Session_client::Rpc_subjects>();
});
_trace->_retry<Genode::Trace::Session::Alloc_rpc_error>([&] {
return _trace->call<Genode::Trace::Session::Rpc_subjects>(); });
_subject_id_reread ++;
}

View File

@ -27,27 +27,27 @@ using namespace Genode;
struct Test_thread : Thread
{
Env &env;
Timer::Connection timer { env };
bool stop { false };
Env &_env;
Timer::Connection _timer { _env };
bool _stop { false };
void entry() override
{
for (unsigned i = 0; !stop; i++) {
for (unsigned i = 0; !_stop; i++) {
if (i & 0x3) {
Ram_dataspace_capability ds_cap = env.ram().alloc(1024);
env.ram().free(ds_cap);
Ram_dataspace_capability ds_cap = _env.ram().alloc(1024);
_env.ram().free(ds_cap);
}
timer.msleep(250);
_timer.msleep(250);
}
}
Test_thread(Env &env, Name &name)
: Thread(env, name, 1024 * sizeof(addr_t)), env(env) { start(); }
Test_thread(Env &env, Name const &name)
: Thread(env, name, 1024 * sizeof(addr_t)), _env(env) { start(); }
~Test_thread()
{
stop = true;
_stop = true;
this->join();
}
@ -141,7 +141,7 @@ struct Test_out_of_metadata
* error-handling procedure.
*/
enum { MAX_SUBJECT_IDS = 16 };
static constexpr unsigned MAX_SUBJECT_IDS = 16;
Trace::Subject_id subject_ids[MAX_SUBJECT_IDS];
try {
@ -169,7 +169,7 @@ struct Test_out_of_metadata
Trace::Connection trace(env, sizeof(subject_ids) + 5*4096,
sizeof(subject_ids));
trace.subjects(subject_ids, MAX_SUBJECT_IDS);
trace.subjects(subject_ids, { MAX_SUBJECT_IDS });
/* we should never arrive here */
struct Unexpectedly_got_no_exception{};
@ -185,66 +185,70 @@ struct Test_out_of_metadata
struct Test_tracing
{
Env &env;
Attached_rom_dataspace config { env, "config" };
Trace::Connection trace { env, 1024*1024, 64*1024 };
Timer::Connection timer { env };
Test_thread::Name thread_name { "test-thread" };
Test_thread thread { env, thread_name };
Trace::Policy_id policy_id { };
Constructible<Trace_buffer_monitor> test_monitor { };
using Policy_id = Trace::Connection::Alloc_policy_result;
using String = Genode::String<64>;
String policy_label { };
String policy_module { };
String policy_thread { };
Env &_env;
Attached_rom_dataspace _config { _env, "config" };
Trace::Connection _trace { _env, 1024*1024, 64*1024 };
Timer::Connection _timer { _env };
Test_thread::Name _thread_name { "test-thread" };
Test_thread _thread { _env, _thread_name };
Rom_dataspace_capability policy_module_rom_ds { };
static String _trace_policy_attr(Xml_node const &config, auto const &attr_name)
{
String result { };
config.with_optional_sub_node("trace_policy", [&] (Xml_node const &policy) {
result = policy.attribute_value(attr_name, String()); });
return result;
}
String const _policy_label = _trace_policy_attr(_config.xml(), "label");
String const _policy_module = _trace_policy_attr(_config.xml(), "module");
String const _policy_thread = _trace_policy_attr(_config.xml(), "thread");
Policy_id _init_policy()
{
log("test Tracing");
try {
log("load module: '", _policy_module, "' for label: '", _policy_label, "'");
Attached_rom_dataspace const rom { _env, _policy_module.string() };
Policy_id const policy_id = _trace.alloc_policy(Trace::Policy_size { rom.size() });
Dataspace_capability ds_cap { };
policy_id.with_result(
[&] (Trace::Policy_id id) { ds_cap = _trace.policy(id); },
[&] (Trace::Connection::Alloc_policy_error) { });
if (!ds_cap.valid()) {
error("failed to obtain policy buffer");
throw Failed();
}
Attached_dataspace dst { _env.rm(), ds_cap };
memcpy(dst.local_addr<char>(), rom.local_addr<char const>(), rom.size());
return policy_id;
} catch (...) {
error("could not load module '", _policy_module, "' for "
"label '", _policy_label, "'");
throw Failed();
}
}
Policy_id const _policy_id = _init_policy();
Constructible<Trace_buffer_monitor> _test_monitor { };
struct Failed : Genode::Exception { };
Test_tracing(Env &env) : env(env)
Test_tracing(Env &env) : _env(env)
{
enum { MAX_SUBJECTS = 128 };
log("test Tracing");
config.xml().with_optional_sub_node("trace_policy", [&] (Xml_node const &policy) {
policy_label = policy.attribute_value("label", String());
policy_module = policy.attribute_value("module", String());
policy_thread = policy.attribute_value("thread", String());
});
try {
Rom_connection policy_rom(env, policy_module.string());
policy_module_rom_ds = policy_rom.dataspace();
size_t rom_size = Dataspace_client(policy_module_rom_ds).size();
policy_id = trace.alloc_policy(rom_size);
Dataspace_capability ds_cap = trace.policy(policy_id);
if (ds_cap.valid()) {
void *ram = env.rm().attach(ds_cap);
void *rom = env.rm().attach(policy_module_rom_ds);
memcpy(ram, rom, rom_size);
env.rm().detach(ram);
env.rm().detach(rom);
}
log("load module: '", policy_module, "' for "
"label: '", policy_label, "'");
} catch (...) {
error("could not load module '", policy_module, "' for "
"label '", policy_label, "'");
throw Failed();
}
/* wait some time before querying the subjects */
timer.msleep(1500);
_timer.msleep(1500);
auto print_info = [this] (Trace::Subject_id id, Trace::Subject_info info) {
@ -259,7 +263,7 @@ struct Test_tracing
"quantum:", info.execution_time().quantum);
};
trace.for_each_subject_info(print_info);
_trace.for_each_subject_info(print_info);
auto check_unattached = [this] (Trace::Subject_id id, Trace::Subject_info info) {
@ -267,48 +271,59 @@ struct Test_tracing
error("Subject ", id.id, " is not UNATTACHED");
};
trace.for_each_subject_info(check_unattached);
_trace.for_each_subject_info(check_unattached);
/* enable tracing for test-thread */
auto enable_tracing = [this, &env] (Trace::Subject_id id,
Trace::Subject_info info) {
if (info.session_label() != policy_label
|| info.thread_name() != policy_thread) {
if (info.session_label() != _policy_label
|| info.thread_name() != _policy_thread) {
return;
}
try {
log("enable tracing for "
"thread:'", info.thread_name().string(), "' with "
"policy:", policy_id.id);
_policy_id.with_result(
[&] (Trace::Policy_id policy_id) {
log("enable tracing for "
"thread:'", info.thread_name(), "' with "
"policy:", policy_id.id);
trace.trace(id.id, policy_id, 16384U);
Trace::Connection::Trace_result const trace_result =
_trace.trace(id, policy_id, Trace::Buffer_size{16384});
Dataspace_capability ds_cap = trace.buffer(id.id);
test_monitor.construct(env.rm(), id.id, ds_cap);
trace_result.with_result(
[&] (Trace::Trace_ok) {
Dataspace_capability ds_cap = _trace.buffer(id);
_test_monitor.construct(env.rm(), id, ds_cap);
},
[&] (Trace::Connection::Trace_error e) {
if (e == Trace::Connection::Trace_error::SOURCE_IS_DEAD)
error("source is dead");
} catch (Trace::Source_is_dead) {
error("source is dead");
throw Failed();
}
throw Failed();
});
},
[&] (Trace::Connection::Alloc_policy_error) {
error("policy alloc failed");
throw Failed();
});
};
trace.for_each_subject_info(enable_tracing);
_trace.for_each_subject_info(enable_tracing);
/* give the test thread some time to run */
timer.msleep(1000);
_timer.msleep(1000);
trace.for_each_subject_info(print_info);
_trace.for_each_subject_info(print_info);
/* read events from trace buffer */
if (test_monitor.constructed()) {
test_monitor->dump();
test_monitor.destruct();
if (_test_monitor.constructed()) {
_test_monitor->dump();
_test_monitor.destruct();
log("passed Tracing test");
}
else
error("Thread '", policy_thread, "' not found for session ", policy_label);
error("Thread '", _policy_thread, "' not found for session ", _policy_label);
}
};