mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 21:57:55 +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:
parent
7de2f57ef2
commit
a52c2ce141
@ -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; }
|
||||
};
|
||||
|
@ -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_ */
|
@ -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_ */
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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, "'");
|
||||
});
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 ++;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user