core: TRACE service interface and implementation
parent
fe4a6d7d81
commit
149356f7ab
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* \brief Basic types used by the tracing infrastructure
|
||||
* \author Norman Feske
|
||||
* \date 2013-08-12
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__BASE__TRACE__TYPES_H_
|
||||
#define _INCLUDE__BASE__TRACE__TYPES_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/string.h>
|
||||
|
||||
namespace Genode { namespace Trace {
|
||||
|
||||
/*********************
|
||||
** Exception types **
|
||||
*********************/
|
||||
|
||||
struct Policy_too_large : Exception { };
|
||||
struct Out_of_metadata : Exception { };
|
||||
struct Nonexistent_subject : Exception { };
|
||||
struct Already_traced : Exception { };
|
||||
struct Source_is_dead : Exception { };
|
||||
struct Nonexistent_policy : Exception { };
|
||||
struct Traced_by_other_session : Exception { };
|
||||
struct Subject_not_traced : Exception { };
|
||||
|
||||
template <size_t MAX>
|
||||
struct String
|
||||
{
|
||||
enum { MAX_SIZE = MAX };
|
||||
char buf[MAX];
|
||||
size_t length;
|
||||
|
||||
String() : length(0) { }
|
||||
|
||||
String(char const *str) : length(min(strlen(str) + 1, MAX))
|
||||
{
|
||||
strncpy(buf, str, length);
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return (length < MAX) && (length > 0) && (buf[length - 1] == '\0'); }
|
||||
|
||||
char const *string() const { return valid() ? buf : ""; }
|
||||
};
|
||||
|
||||
typedef String<160> Session_label;
|
||||
typedef String<64> Thread_name;
|
||||
|
||||
struct Policy_id;
|
||||
struct Subject_id;
|
||||
struct Subject_info;
|
||||
} }
|
||||
|
||||
|
||||
/**
|
||||
* Session-local policy identifier
|
||||
*/
|
||||
struct Genode::Trace::Policy_id
|
||||
{
|
||||
unsigned id;
|
||||
|
||||
Policy_id() : id(0) { }
|
||||
Policy_id(unsigned id) : id(id) { }
|
||||
|
||||
bool operator == (Policy_id const &other) { return id == other.id; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Session-local trace-subject identifier
|
||||
*/
|
||||
struct Genode::Trace::Subject_id
|
||||
{
|
||||
unsigned id;
|
||||
|
||||
Subject_id() : id(0) { }
|
||||
Subject_id(unsigned id) : id(id) { }
|
||||
|
||||
bool operator == (Subject_id const &other) { return id == other.id; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Subject information
|
||||
*/
|
||||
class Genode::Trace::Subject_info
|
||||
{
|
||||
public:
|
||||
|
||||
enum State { INVALID, UNTRACED, TRACED, FOREIGN, ERROR, DEAD };
|
||||
|
||||
private:
|
||||
|
||||
Session_label _session_label;
|
||||
Thread_name _thread_name;
|
||||
State _state;
|
||||
Policy_id _policy_id;
|
||||
|
||||
public:
|
||||
|
||||
Subject_info() : _state(INVALID) { }
|
||||
|
||||
Subject_info(Session_label const &session_label,
|
||||
Thread_name const &thread_name,
|
||||
State state, Policy_id policy_id)
|
||||
:
|
||||
_session_label(session_label), _thread_name(thread_name),
|
||||
_state(state), _policy_id(policy_id)
|
||||
{ }
|
||||
|
||||
Session_label const &session_label() const { return _session_label; }
|
||||
Thread_name const &thread_name() const { return _thread_name; }
|
||||
State state() const { return _state; }
|
||||
Policy_id policy_id() const { return _policy_id; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__TRACE__TYPES_H_ */
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* \brief Client-side TRACE session interface
|
||||
* \author Norman Feske
|
||||
* \date 2013-08-12
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#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.
|
||||
*/
|
||||
struct Argument_buffer
|
||||
{
|
||||
char *base;
|
||||
size_t size;
|
||||
|
||||
Argument_buffer(Dataspace_capability ds)
|
||||
:
|
||||
base(env()->rm_session()->attach(ds)),
|
||||
size(ds.call<Dataspace::Rpc_size>())
|
||||
{ }
|
||||
|
||||
~Argument_buffer()
|
||||
{
|
||||
env()->rm_session()->detach(base);
|
||||
}
|
||||
};
|
||||
|
||||
Argument_buffer _argument_buffer;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
explicit Session_client(Capability<Trace::Session> session)
|
||||
:
|
||||
Rpc_client<Trace::Session>(session),
|
||||
_argument_buffer(call<Rpc_dataspace>())
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Retrieve subject directory
|
||||
*/
|
||||
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, dst_len*sizeof(Subject_id));
|
||||
|
||||
return num_subjects;
|
||||
}
|
||||
|
||||
Policy_id alloc_policy(size_t size) {
|
||||
return call<Rpc_alloc_policy>(size); }
|
||||
|
||||
Dataspace_capability policy(Policy_id policy_id) {
|
||||
return call<Rpc_policy>(policy_id); }
|
||||
|
||||
void unload_policy(Policy_id policy_id) {
|
||||
call<Rpc_unload_policy>(policy_id); }
|
||||
|
||||
void trace(Subject_id s, Policy_id p, size_t buffer_size) {
|
||||
call<Rpc_trace>(s, p, buffer_size); }
|
||||
|
||||
void rule(Session_label const &label, Thread_name const &thread,
|
||||
Policy_id policy, size_t buffer_size) {
|
||||
call<Rpc_rule>(label, thread, policy, buffer_size); }
|
||||
|
||||
void pause(Subject_id subject) {
|
||||
call<Rpc_pause>(subject); }
|
||||
|
||||
void resume(Subject_id subject) {
|
||||
call<Rpc_resume>(subject); }
|
||||
|
||||
Subject_info subject_info(Subject_id subject) {
|
||||
return call<Rpc_subject_info>(subject); }
|
||||
|
||||
Dataspace_capability buffer(Subject_id subject) {
|
||||
return call<Rpc_buffer>(subject); }
|
||||
|
||||
void free(Subject_id subject) {
|
||||
call<Rpc_free>(subject); }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__TRACE_SESSION__CLIENT_H_ */
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* \brief Connection to TRACE service
|
||||
* \author Norman Feske
|
||||
* \date 2013-08-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__TRACE_SESSION__CONNECTION_H_
|
||||
#define _INCLUDE__TRACE_SESSION__CONNECTION_H_
|
||||
|
||||
#include <trace_session/client.h>
|
||||
#include <base/connection.h>
|
||||
|
||||
namespace Genode { namespace Trace { struct Connection; } }
|
||||
|
||||
struct Genode::Trace::Connection : Genode::Connection<Genode::Trace::Session>,
|
||||
Genode::Trace::Session_client
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param ram_quota RAM donated for tracing purposes
|
||||
* \param arg_buffer_size session argument-buffer size
|
||||
* \param parent_levels number of parent levels to trace
|
||||
*/
|
||||
Connection(size_t ram_quota, size_t arg_buffer_size, unsigned parent_levels) :
|
||||
Genode::Connection<Session>(
|
||||
session("ram_quota=%zd, arg_buffer_size=%zd, parent_levels=%u",
|
||||
ram_quota, arg_buffer_size, parent_levels)),
|
||||
Session_client(cap()) { }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__TRACE_SESSION__CONNECTION_H_ */
|
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* \brief TRACE session interface
|
||||
* \author Norman Feske
|
||||
* \date 2013-08-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_
|
||||
#define _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_
|
||||
|
||||
#include <base/exception.h>
|
||||
#include <base/trace/types.h>
|
||||
#include <dataspace/capability.h>
|
||||
#include <session/session.h>
|
||||
|
||||
namespace Genode { namespace Trace { struct Session; } }
|
||||
|
||||
|
||||
struct Genode::Trace::Session : Genode::Session
|
||||
{
|
||||
static const char *service_name() { return "TRACE"; }
|
||||
|
||||
/**
|
||||
* Allocate policy-module backing store
|
||||
*
|
||||
* \throw Out_of_metadata
|
||||
*/
|
||||
virtual Policy_id alloc_policy(size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Request policy-module backing store
|
||||
*
|
||||
* \throw Nonexistent_policy
|
||||
*/
|
||||
virtual Dataspace_capability policy(Policy_id) = 0;
|
||||
|
||||
/**
|
||||
* Remove a policy module from the TRACE service
|
||||
*/
|
||||
virtual void unload_policy(Policy_id) = 0;
|
||||
|
||||
/**
|
||||
* Start tracing of a subject
|
||||
*
|
||||
* \throw Out_of_metadata
|
||||
* \throw Already_traced
|
||||
* \throw Source_is_dead
|
||||
* \throw Nonexistent_policy
|
||||
* \throw Traced_by_other_session
|
||||
*/
|
||||
virtual void trace(Subject_id, Policy_id, size_t buffer_size) = 0;
|
||||
|
||||
/**
|
||||
* Install a matching rule for automatically tracing new threads
|
||||
*/
|
||||
virtual void rule(Session_label const &, Thread_name const &,
|
||||
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 details about tracing subject
|
||||
*
|
||||
* \throw Nonexistent_subject
|
||||
*/
|
||||
virtual Subject_info subject_info(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() { }
|
||||
|
||||
|
||||
/*********************
|
||||
** RPC declaration **
|
||||
*********************/
|
||||
|
||||
GENODE_RPC(Rpc_dataspace, Dataspace_capability, dataspace);
|
||||
GENODE_RPC_THROW(Rpc_alloc_policy, Policy_id, alloc_policy,
|
||||
GENODE_TYPE_LIST(Out_of_metadata),
|
||||
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_metadata, Already_traced,
|
||||
Source_is_dead, Nonexistent_policy,
|
||||
Traced_by_other_session),
|
||||
Subject_id, Policy_id, size_t);
|
||||
GENODE_RPC_THROW(Rpc_rule, void, rule,
|
||||
GENODE_TYPE_LIST(Out_of_metadata),
|
||||
Session_label const &, Thread_name const &,
|
||||
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(Rpc_subjects, size_t, subjects);
|
||||
GENODE_RPC_THROW(Rpc_subject_info, Subject_info, subject_info,
|
||||
GENODE_TYPE_LIST(Nonexistent_subject), Subject_id);
|
||||
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);
|
||||
|
||||
typedef Meta::Type_tuple<Rpc_dataspace,
|
||||
Meta::Type_tuple<Rpc_alloc_policy,
|
||||
Meta::Type_tuple<Rpc_policy,
|
||||
Meta::Type_tuple<Rpc_unload_policy,
|
||||
Meta::Type_tuple<Rpc_trace,
|
||||
Meta::Type_tuple<Rpc_rule,
|
||||
Meta::Type_tuple<Rpc_pause,
|
||||
Meta::Type_tuple<Rpc_resume,
|
||||
Meta::Type_tuple<Rpc_subjects,
|
||||
Meta::Type_tuple<Rpc_subject_info,
|
||||
Meta::Type_tuple<Rpc_buffer,
|
||||
Meta::Type_tuple<Rpc_free,
|
||||
Meta::Empty>
|
||||
> > > > > > > > > > > Rpc_functions;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_ */
|