core: TRACE service interface and implementation

This commit is contained in:
Norman Feske 2013-08-10 03:44:55 +02:00
parent fe4a6d7d81
commit 149356f7ab
32 changed files with 2249 additions and 86 deletions

View File

@ -23,6 +23,7 @@ SRC_CC += \
irq_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
trace_session_component.cc \
core_rm_session.cc \
core_mem_alloc.cc \
dump_alloc.cc \
@ -32,7 +33,8 @@ LIBS += core_printf base-common
INC_DIR += $(REP_DIR)/src/core/include \
$(GEN_CORE_DIR)/include \
$(REP_DIR)/include/codezero/dummies
$(REP_DIR)/include/codezero/dummies \
$(BASE_DIR)/src/base/thread
vpath main.cc $(GEN_CORE_DIR)
vpath ram_session_component.cc $(GEN_CORE_DIR)
@ -45,6 +47,7 @@ vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath platform_services.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)

View File

@ -24,13 +24,15 @@ SRC_CC += main.cc \
irq_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
trace_session_component.cc \
dump_alloc.cc \
context_area.cc \
core_printf.cc
INC_DIR += $(REP_DIR)/src/core/include \
$(GEN_CORE_DIR)/include \
$(REP_DIR)/src/base/console
$(REP_DIR)/src/base/console \
$(BASE_DIR)/src/base/thread
LIBS += base-common
@ -45,6 +47,7 @@ vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)

View File

@ -1,6 +1,7 @@
/*
* \brief Core-specific instance of the CPU session/thread interfaces
* \author Christian Helmuth
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2006-07-17
*/
@ -26,6 +27,8 @@
/* core includes */
#include <platform_thread.h>
#include <trace/control_area.h>
#include <trace/source_registry.h>
namespace Genode {
@ -45,18 +48,33 @@ namespace Genode {
class Cpu_thread_component : public Rpc_object<Cpu_thread>,
public List<Cpu_thread_component>::Element
{
public:
typedef Trace::Session_label Session_label;
typedef Trace::Thread_name Thread_name;
private:
Thread_name const _name;
Platform_thread _platform_thread;
bool _bound; /* pd binding flag */
Signal_context_capability _sigh; /* exception handler */
unsigned const _trace_control_index;
Trace::Source _trace_source;
public:
Cpu_thread_component(const char *name, unsigned priority, addr_t utcb,
Signal_context_capability sigh)
Cpu_thread_component(Session_label const &label,
Thread_name const &name,
unsigned priority, addr_t utcb,
Signal_context_capability sigh,
unsigned trace_control_index,
Trace::Control &trace_control)
:
_platform_thread(name, priority), _bound(false), _sigh(sigh)
_name(name),
_platform_thread(name.string(), priority, utcb), _bound(false),
_sigh(sigh), _trace_control_index(trace_control_index),
_trace_source(label, _name, trace_control)
{
update_exception_sigh();
}
@ -66,9 +84,10 @@ namespace Genode {
** Accessor functions **
************************/
inline Platform_thread * platform_thread() { return &_platform_thread; }
inline bool bound() const { return _bound; }
inline void bound(bool b) { _bound = b; }
Platform_thread *platform_thread() { return &_platform_thread; }
bool bound() const { return _bound; }
void bound(bool b) { _bound = b; }
Trace::Source *trace_source() { return &_trace_source; }
void sigh(Signal_context_capability sigh)
{
@ -80,11 +99,20 @@ namespace Genode {
* Propagate exception handler to platform thread
*/
void update_exception_sigh();
/**
* Return index within the CPU-session's trace control area
*/
unsigned trace_control_index() const { return _trace_control_index; }
};
class Cpu_session_component : public Rpc_object<Foc_cpu_session>
{
public:
typedef Cpu_thread_component::Session_label Session_label;
private:
/**
@ -93,11 +121,12 @@ namespace Genode {
*/
typedef Tslab<Cpu_thread_component, 1024> Cpu_thread_allocator;
Session_label _label;
Rpc_entrypoint *_thread_ep;
Pager_entrypoint *_pager_ep;
Allocator_guard _md_alloc; /* guarded meta-data allocator */
Cpu_thread_allocator _thread_alloc; /* meta-data allocator */
Lock _thread_alloc_lock; /* protect alloc access */
Lock _thread_alloc_lock; /* protect allocator access */
List<Cpu_thread_component> _thread_list;
Lock _thread_list_lock; /* protect thread list */
unsigned _priority; /* priority of threads
@ -105,6 +134,8 @@ namespace Genode {
session */
Affinity::Location _location; /* CPU affinity of this
session */
Trace::Source_registry &_trace_sources;
Trace::Control_area _trace_control_area;
/**
* Exception handler that will be invoked unless overridden by a
@ -127,10 +158,11 @@ namespace Genode {
/**
* Constructor
*/
Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc, const char *args,
Affinity const &affinity);
Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc,
Trace::Source_registry &trace_sources,
const char *args, Affinity const &affinity);
/**
* Destructor

View File

@ -65,7 +65,7 @@ namespace Genode {
/**
* Constructor for non-core threads
*/
Platform_thread(const char *name, unsigned priority);
Platform_thread(const char *name, unsigned priority, addr_t);
/**
* Constructor for core main-thread

View File

@ -261,8 +261,7 @@ Weak_ptr<Address_space> Platform_thread::address_space()
}
Platform_thread::Platform_thread(const char *name,
unsigned prio)
Platform_thread::Platform_thread(const char *name, unsigned prio, addr_t)
: _state(DEAD),
_core_thread(false),
_thread(true),

View File

@ -31,6 +31,7 @@ SRC_CC = cap_session_component.cc \
rom_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
trace_session_component.cc \
thread_start.cc \
thread_context_area.cc \
core_printf.cc
@ -39,6 +40,7 @@ INC_DIR += $(REP_DIR)/src/core/include \
$(GEN_CORE_DIR)/include \
$(REP_DIR)/src/base/lock \
$(BASE_DIR)/src/base/lock \
$(BASE_DIR)/src/base/thread \
$(REP_DIR)/src/base/console
vpath context_area.cc $(GEN_CORE_DIR)
@ -54,6 +56,7 @@ vpath ram_session_component.cc $(GEN_CORE_DIR)
vpath rm_session_component.cc $(GEN_CORE_DIR)
vpath rom_session_component.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath %.cc $(REP_DIR)/src/core
vpath %.cc $(REP_DIR)/src/base/thread

View File

@ -24,7 +24,8 @@ INC_DIR += $(REP_DIR)/src/core \
$(REP_DIR)/src/base \
$(BASE_DIR)/src/core/include \
$(BASE_DIR)/include \
$(BASE_DIR)/src/platform
$(BASE_DIR)/src/platform \
$(BASE_DIR)/src/base/thread
# add C++ sources
SRC_CC += console.cc \
@ -46,6 +47,7 @@ SRC_CC += console.cc \
rm_session_component.cc \
rom_session_component.cc \
signal_session_component.cc \
trace_session_component.cc \
thread.cc \
kernel.cc \
rm_session_support.cc \
@ -65,6 +67,7 @@ vpath pd_session_component.cc $(BASE_DIR)/src/core
vpath ram_session_component.cc $(BASE_DIR)/src/core
vpath rm_session_component.cc $(BASE_DIR)/src/core
vpath rom_session_component.cc $(BASE_DIR)/src/core
vpath trace_session_component.cc $(BASE_DIR)/src/core
vpath dump_alloc.cc $(BASE_DIR)/src/core
vpath console.cc $(REP_DIR)/src/base
vpath pager.cc $(REP_DIR)/src/base

View File

@ -26,6 +26,8 @@
/* core includes */
#include <cpu_thread_allocator.h>
#include <platform_thread.h>
#include <trace/control_area.h>
#include <trace/source_registry.h>
namespace Genode {
@ -45,18 +47,33 @@ namespace Genode {
class Cpu_thread_component : public Rpc_object<Cpu_thread>,
public List<Cpu_thread_component>::Element
{
public:
typedef Trace::Session_label Session_label;
typedef Trace::Thread_name Thread_name;
private:
Thread_name const _name;
Platform_thread _platform_thread;
bool _bound; /* pd binding flag */
Signal_context_capability _sigh; /* exception handler */
unsigned const _trace_control_index;
Trace::Source _trace_source;
public:
Cpu_thread_component(const char *name, unsigned priority, addr_t utcb,
Signal_context_capability sigh)
Cpu_thread_component(Session_label const &label,
Thread_name const &name,
unsigned priority, addr_t utcb,
Signal_context_capability sigh,
unsigned trace_control_index,
Trace::Control &trace_control)
:
_platform_thread(name, priority, utcb), _bound(false), _sigh(sigh)
_name(name),
_platform_thread(name.string(), priority, utcb), _bound(false),
_sigh(sigh), _trace_control_index(trace_control_index),
_trace_source(label, _name, trace_control)
{
update_exception_sigh();
}
@ -66,9 +83,10 @@ namespace Genode {
** Accessor functions **
************************/
inline Platform_thread * platform_thread() { return &_platform_thread; }
inline bool bound() const { return _bound; }
inline void bound(bool b) { _bound = b; }
Platform_thread *platform_thread() { return &_platform_thread; }
bool bound() const { return _bound; }
void bound(bool b) { _bound = b; }
Trace::Source *trace_source() { return &_trace_source; }
void sigh(Signal_context_capability sigh)
{
@ -80,13 +98,23 @@ namespace Genode {
* Propagate exception handler to platform thread
*/
void update_exception_sigh();
/**
* Return index within the CPU-session's trace control area
*/
unsigned trace_control_index() const { return _trace_control_index; }
};
class Cpu_session_component : public Rpc_object<Linux_cpu_session>
{
public:
typedef Cpu_thread_component::Session_label Session_label;
private:
Session_label _label;
Rpc_entrypoint *_thread_ep;
Pager_entrypoint *_pager_ep;
Allocator_guard _md_alloc; /* guarded meta-data allocator */
@ -99,6 +127,8 @@ namespace Genode {
session */
Affinity::Location _location; /* CPU affinity of this
session */
Trace::Source_registry &_trace_sources;
Trace::Control_area _trace_control_area;
/**
* Exception handler that will be invoked unless overridden by a
@ -121,10 +151,11 @@ namespace Genode {
/**
* Constructor
*/
Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc, const char *args,
Affinity const &affinity);
Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc,
Trace::Source_registry &trace_sources,
const char *args, Affinity const &affinity);
/**
* Destructor

View File

@ -18,6 +18,7 @@ SRC_CC = main.cc \
io_mem_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
trace_session_component.cc \
thread_linux.cc \
context_area.cc \
core_printf.cc \
@ -29,6 +30,7 @@ INC_DIR += $(REP_DIR)/src/core/include \
$(REP_DIR)/src/base/ipc \
$(REP_DIR)/src/base/env \
$(REP_DIR)/src/base/console \
$(BASE_DIR)/src/base/thread \
HOST_INC_DIR += /usr/include
@ -48,6 +50,7 @@ vpath cpu_session_component.cc $(GEN_CORE_DIR)
vpath platform_services.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/base/console
vpath thread.cc $(BASE_DIR)/src/base/thread
vpath trace.cc $(BASE_DIR)/src/base/thread

View File

@ -1,6 +1,7 @@
/*
* \brief Core-specific instance of the CPU session/thread interfaces
* \author Christian Helmuth
\author Norman Feske
* \author Alexander Boettcher
* \date 2006-07-17
*/
@ -26,6 +27,8 @@
/* core includes */
#include <platform_thread.h>
#include <trace/control_area.h>
#include <trace/source_registry.h>
namespace Genode {
@ -45,18 +48,33 @@ namespace Genode {
class Cpu_thread_component : public Rpc_object<Cpu_thread>,
public List<Cpu_thread_component>::Element
{
public:
typedef Trace::Session_label Session_label;
typedef Trace::Thread_name Thread_name;
private:
Thread_name const _name;
Platform_thread _platform_thread;
bool _bound; /* pd binding flag */
Signal_context_capability _sigh; /* exception handler */
unsigned const _trace_control_index;
Trace::Source _trace_source;
public:
Cpu_thread_component(const char *name, unsigned priority, addr_t utcb,
Signal_context_capability sigh)
Cpu_thread_component(Session_label const &label,
Thread_name const &name,
unsigned priority, addr_t utcb,
Signal_context_capability sigh,
unsigned trace_control_index,
Trace::Control &trace_control)
:
_platform_thread(name, priority, utcb), _bound(false), _sigh(sigh)
_name(name),
_platform_thread(name.string(), priority, utcb), _bound(false),
_sigh(sigh), _trace_control_index(trace_control_index),
_trace_source(label, _name, trace_control)
{
update_exception_sigh();
}
@ -66,9 +84,10 @@ namespace Genode {
** Accessor functions **
************************/
inline Platform_thread * platform_thread() { return &_platform_thread; }
inline bool bound() const { return _bound; }
inline void bound(bool b) { _bound = b; }
Platform_thread *platform_thread() { return &_platform_thread; }
bool bound() const { return _bound; }
void bound(bool b) { _bound = b; }
Trace::Source *trace_source() { return &_trace_source; }
void sigh(Signal_context_capability sigh)
{
@ -80,11 +99,20 @@ namespace Genode {
* Propagate exception handler to platform thread
*/
void update_exception_sigh();
/**
* Return index within the CPU-session's trace control area
*/
unsigned trace_control_index() const { return _trace_control_index; }
};
class Cpu_session_component : public Rpc_object<Nova_cpu_session>
{
public:
typedef Cpu_thread_component::Session_label Session_label;
private:
/**
@ -93,11 +121,12 @@ namespace Genode {
*/
typedef Tslab<Cpu_thread_component, 1024> Cpu_thread_allocator;
Session_label _label;
Rpc_entrypoint *_thread_ep;
Pager_entrypoint *_pager_ep;
Allocator_guard _md_alloc; /* guarded meta-data allocator */
Cpu_thread_allocator _thread_alloc; /* meta-data allocator */
Lock _thread_alloc_lock; /* protect alloc access */
Lock _thread_alloc_lock; /* protect allocator access */
List<Cpu_thread_component> _thread_list;
Lock _thread_list_lock; /* protect thread list */
unsigned _priority; /* priority of threads
@ -105,6 +134,9 @@ namespace Genode {
session */
Affinity::Location _location; /* CPU affinity of this
session */
Trace::Source_registry &_trace_sources;
Trace::Control_area _trace_control_area;
/**
* Exception handler that will be invoked unless overridden by a
* call of 'Cpu_session::exception_handler'.
@ -126,10 +158,11 @@ namespace Genode {
/**
* Constructor
*/
Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc, const char *args,
Affinity const &affinity);
Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc,
Trace::Source_registry &trace_sources,
const char *args, Affinity const &affinity);
/**
* Destructor

View File

@ -25,6 +25,7 @@ SRC_CC = main.cc \
irq_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
trace_session_component.cc \
core_rm_session.cc \
cap_sel_alloc.cc \
main_thread.cc \
@ -38,6 +39,7 @@ SRC_CC = main.cc \
INC_DIR = $(REP_DIR)/src/core/include \
$(REP_DIR)/src/base/console \
$(BASE_DIR)/src/base/thread \
$(GEN_CORE_DIR)/include
vpath main.cc $(GEN_CORE_DIR)
@ -47,6 +49,7 @@ vpath cpu_session_component.cc $(GEN_CORE_DIR)
vpath pd_session_component.cc $(GEN_CORE_DIR)
vpath rm_session_component.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath io_port_session_component.cc $(GEN_CORE_DIR)/x86
vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)

View File

@ -25,6 +25,7 @@ SRC_CC += main.cc \
irq_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
trace_session_component.cc \
core_rm_session.cc \
core_mem_alloc.cc \
core_printf.cc \
@ -34,6 +35,7 @@ SRC_CC += main.cc \
INC_DIR += $(REP_DIR)/src/core/include \
$(GEN_CORE_DIR)/include \
$(REP_DIR)/src/base/console \
$(BASE_DIR)/src/base/thread \
$(BASE_DIR)/src/platform \
$(REP_DIR)/src/platform
@ -47,6 +49,7 @@ vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)

View File

@ -25,6 +25,7 @@ SRC_CC = main.cc \
irq_session_component.cc \
signal_session_component.cc \
signal_source_component.cc \
trace_session_component.cc \
dump_alloc.cc \
context_area.cc \
core_printf.cc \
@ -32,6 +33,7 @@ SRC_CC = main.cc \
INC_DIR += $(REP_DIR)/src/core/include \
$(REP_DIR)/src/base/console \
$(BASE_DIR)/src/base/thread \
$(GEN_CORE_DIR)/include
vpath main.cc $(GEN_CORE_DIR)
@ -44,6 +46,7 @@ vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath signal_session_component.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)

View File

@ -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_ */

View File

@ -35,7 +35,7 @@ namespace Genode {
Affinity const &affinity = Affinity())
:
Connection<Cpu_session>(
session(affinity, "priority=0x%lx, ram_quota=32K, label=\"%s\"",
session(affinity, "priority=0x%lx, ram_quota=36K, label=\"%s\"",
priority, label)),
Cpu_session_client(cap()) { }
};

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -32,15 +32,27 @@ void Cpu_thread_component::update_exception_sigh()
};
Thread_capability Cpu_session_component::create_thread(Name const &name,
addr_t utcb)
Thread_capability Cpu_session_component::create_thread(Name const &name,
addr_t utcb)
{
unsigned trace_control_index = 0;
if (!_trace_control_area.alloc(trace_control_index))
throw Out_of_metadata();
Trace::Control * const trace_control =
_trace_control_area.at(trace_control_index);
Trace::Thread_name thread_name(name.string());
Cpu_thread_component *thread = 0;
try {
Lock::Guard slab_lock_guard(_thread_alloc_lock);
thread = new(&_thread_alloc) Cpu_thread_component(name.string(),
thread = new(&_thread_alloc) Cpu_thread_component(_label,
thread_name,
_priority, utcb,
_default_exception_handler);
_default_exception_handler,
trace_control_index,
*trace_control);
} catch (Allocator::Out_of_memory) {
throw Out_of_metadata();
}
@ -48,6 +60,8 @@ Thread_capability Cpu_session_component::create_thread(Name const &name,
Lock::Guard thread_list_lock_guard(_thread_list_lock);
_thread_list.insert(thread);
_trace_sources.insert(thread->trace_source());
return _thread_ep->manage(thread);
}
@ -57,8 +71,14 @@ void Cpu_session_component::_unsynchronized_kill_thread(Cpu_thread_component *th
_thread_ep->dissolve(thread);
_thread_list.remove(thread);
_trace_sources.remove(thread->trace_source());
unsigned const trace_control_index = thread->trace_control_index();
Lock::Guard lock_guard(_thread_alloc_lock);
destroy(&_thread_alloc, thread);
_trace_control_area.free(trace_control_index);
}
@ -199,8 +219,8 @@ void Cpu_session_component::affinity(Thread_capability thread_cap,
/* convert session-local location to physical location */
int const x1 = location.xpos() + _location.xpos(),
y1 = location.ypos() + _location.ypos(),
x2 = location.xpos() + location.width(),
y2 = location.ypos() + location.height();
x2 = location.xpos() + location.width(),
y2 = location.ypos() + location.height();
int const clipped_x1 = max(_location.xpos(), x1),
clipped_y1 = max(_location.ypos(), y1),
@ -215,45 +235,69 @@ void Cpu_session_component::affinity(Thread_capability thread_cap,
Dataspace_capability Cpu_session_component::trace_control()
{
/* not implemented */
return Dataspace_capability();
return _trace_control_area.dataspace();
}
unsigned Cpu_session_component::trace_control_index(Thread_capability thread)
unsigned Cpu_session_component::trace_control_index(Thread_capability thread_cap)
{
/* not implemented */
return 0;
Object_pool<Cpu_thread_component>::Guard thread(_thread_ep->lookup_and_lock(thread_cap));
if (!thread) return 0;
return thread->trace_control_index();
}
Dataspace_capability Cpu_session_component::trace_buffer(Thread_capability thread)
Dataspace_capability Cpu_session_component::trace_buffer(Thread_capability thread_cap)
{
/* not implemented */
return Dataspace_capability();
Object_pool<Cpu_thread_component>::Guard thread(_thread_ep->lookup_and_lock(thread_cap));
if (!thread) return Dataspace_capability();
return thread->trace_source()->buffer();
}
Dataspace_capability Cpu_session_component::trace_policy(Thread_capability thread)
Dataspace_capability Cpu_session_component::trace_policy(Thread_capability thread_cap)
{
/* not implemented */
return Dataspace_capability();
Object_pool<Cpu_thread_component>::Guard thread(_thread_ep->lookup_and_lock(thread_cap));
if (!thread) return Dataspace_capability();
return thread->trace_source()->policy();
}
Cpu_session_component::Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc,
char const *args,
Affinity const &affinity)
static size_t remaining_session_ram_quota(char const *args)
{
/*
* We don't need to consider an underflow here because
* 'Cpu_root::_create_session' already checks for the condition.
*/
return Arg_string::find_arg(args, "ram_quota").long_value(0)
- Trace::Control_area::SIZE;
}
Cpu_session_component::Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc,
Trace::Source_registry &trace_sources,
char const *args,
Affinity const &affinity)
:
_thread_ep(thread_ep), _pager_ep(pager_ep),
_md_alloc(md_alloc, Arg_string::find_arg(args, "ram_quota").long_value(0)),
_md_alloc(md_alloc, remaining_session_ram_quota(args)),
_thread_alloc(&_md_alloc), _priority(0),
/* map affinity to a location within the physical affinity space */
_location(affinity.scale_to(platform()->affinity_space()))
_location(affinity.scale_to(platform()->affinity_space())),
_trace_sources(trace_sources)
{
/* remember session label */
char buf[Session_label::MAX_SIZE];
Arg_string::find_arg(args, "label").string(buf, sizeof(buf), "");
_label = Session_label(buf);
Arg a = Arg_string::find_arg(args, "priority");
if (a.valid()) {
_priority = a.ulong_value(0);
@ -277,3 +321,17 @@ Cpu_session_component::~Cpu_session_component()
for (Cpu_thread_component *thread; (thread = _thread_list.first()); )
_unsynchronized_kill_thread(thread);
}
/****************************
** Trace::Source_registry **
****************************/
unsigned Trace::Source::_alloc_unique_id()
{
static Lock lock;
static unsigned cnt;
Lock::Guard guard(lock);
return cnt++;
}

View File

@ -26,17 +26,25 @@ namespace Genode {
{
private:
Rpc_entrypoint *_thread_ep;
Pager_entrypoint *_pager_ep;
Allocator *_md_alloc;
Rpc_entrypoint *_thread_ep;
Pager_entrypoint *_pager_ep;
Allocator *_md_alloc;
Trace::Source_registry &_trace_sources;
protected:
Cpu_session_component *_create_session(char const *args,
Affinity const &affinity) {
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota").long_value(0);
if (ram_quota < Trace::Control_area::SIZE)
throw Root::Quota_exceeded();
return new (md_alloc())
Cpu_session_component(_thread_ep, _pager_ep, _md_alloc,
args, affinity); }
_trace_sources, args, affinity); }
void _upgrade_session(Cpu_session_component *cpu, const char *args)
{
@ -53,13 +61,15 @@ namespace Genode {
* \param thread_ep entry point for managing threads
* \param md_alloc meta data allocator to be used by root component
*/
Cpu_root(Rpc_entrypoint *session_ep,
Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc)
Cpu_root(Rpc_entrypoint *session_ep,
Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc,
Trace::Source_registry &trace_sources)
:
Root_component<Cpu_session_component>(session_ep, md_alloc),
_thread_ep(thread_ep), _pager_ep(pager_ep), _md_alloc(md_alloc)
_thread_ep(thread_ep), _pager_ep(pager_ep), _md_alloc(md_alloc),
_trace_sources(trace_sources)
{ }
};
}

View File

@ -22,9 +22,11 @@
#include <base/rpc_server.h>
#include <cpu_session/cpu_session.h>
/* Core includes */
/* core includes */
#include <cpu_thread_allocator.h>
#include <platform_thread.h>
#include <trace/control_area.h>
#include <trace/source_registry.h>
namespace Genode {
@ -44,18 +46,33 @@ namespace Genode {
class Cpu_thread_component : public Rpc_object<Cpu_thread>,
public List<Cpu_thread_component>::Element
{
public:
typedef Trace::Session_label Session_label;
typedef Trace::Thread_name Thread_name;
private:
Thread_name const _name;
Platform_thread _platform_thread;
bool _bound; /* pd binding flag */
Signal_context_capability _sigh; /* exception handler */
unsigned const _trace_control_index;
Trace::Source _trace_source;
public:
Cpu_thread_component(const char *name, unsigned priority, addr_t utcb,
Signal_context_capability sigh)
Cpu_thread_component(Session_label const &label,
Thread_name const &name,
unsigned priority, addr_t utcb,
Signal_context_capability sigh,
unsigned trace_control_index,
Trace::Control &trace_control)
:
_platform_thread(name, priority, utcb), _bound(false), _sigh(sigh)
_name(name),
_platform_thread(name.string(), priority, utcb), _bound(false),
_sigh(sigh), _trace_control_index(trace_control_index),
_trace_source(label, _name, trace_control)
{
update_exception_sigh();
}
@ -65,9 +82,10 @@ namespace Genode {
** Accessor functions **
************************/
inline Platform_thread * platform_thread() { return &_platform_thread; }
inline bool bound() const { return _bound; }
inline void bound(bool b) { _bound = b; }
Platform_thread *platform_thread() { return &_platform_thread; }
bool bound() const { return _bound; }
void bound(bool b) { _bound = b; }
Trace::Source *trace_source() { return &_trace_source; }
void sigh(Signal_context_capability sigh)
{
@ -79,13 +97,23 @@ namespace Genode {
* Propagate exception handler to platform thread
*/
void update_exception_sigh();
/**
* Return index within the CPU-session's trace control area
*/
unsigned trace_control_index() const { return _trace_control_index; }
};
class Cpu_session_component : public Rpc_object<Cpu_session>
{
public:
typedef Cpu_thread_component::Session_label Session_label;
private:
Session_label _label;
Rpc_entrypoint *_thread_ep;
Pager_entrypoint *_pager_ep;
Allocator_guard _md_alloc; /* guarded meta-data allocator */
@ -98,6 +126,8 @@ namespace Genode {
session */
Affinity::Location _location; /* CPU affinity of this
session */
Trace::Source_registry &_trace_sources;
Trace::Control_area _trace_control_area;
/**
* Exception handler that will be invoked unless overridden by a
@ -120,10 +150,11 @@ namespace Genode {
/**
* Constructor
*/
Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc, const char *args,
Affinity const &);
Cpu_session_component(Rpc_entrypoint *thread_ep,
Pager_entrypoint *pager_ep,
Allocator *md_alloc,
Trace::Source_registry &trace_sources,
const char *args, Affinity const &affinity);
/**
* Destructor
@ -140,7 +171,7 @@ namespace Genode {
** CPU session interface **
***************************/
Thread_capability create_thread(Name const &, addr_t utcb);
Thread_capability create_thread(Name const &, addr_t);
Ram_dataspace_capability utcb(Thread_capability thread);
void kill_thread(Thread_capability);
int set_pager(Thread_capability, Pager_capability);

View File

@ -0,0 +1,98 @@
/*
* \brief Trace control area
* \author Norman Feske
* \date 2013-08-10
*/
/*
* Copyright (C) 2006-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 _CORE__INCLUDE__TRACE__CONTROL_AREA_H_
#define _CORE__INCLUDE__TRACE__CONTROL_AREA_H_
#include <base/env.h>
#include <dataspace/capability.h>
/* base-internal includes */
#include <trace/control.h>
namespace Genode { namespace Trace { class Control_area; } }
class Genode::Trace::Control_area
{
public:
enum { SIZE = 1024*sizeof(long) };
private:
Ram_dataspace_capability _ds;
Trace::Control *_local_base;
static Ram_dataspace_capability _try_alloc(size_t size)
{
try { return env()->ram_session()->alloc(size); }
catch (...) { return Ram_dataspace_capability(); }
}
static Trace::Control *_try_attach(Dataspace_capability ds)
{
try { return env()->rm_session()->attach(ds); }
catch (...) { return 0; }
}
bool _index_valid(int index) const
{
return (index + 1)*sizeof(Trace::Control) < SIZE;
}
public:
Control_area()
:
_ds(_try_alloc(SIZE)),
_local_base(_try_attach(_ds))
{ }
~Control_area()
{
if (_local_base) env()->rm_session()->detach(_local_base);
if (_ds.valid()) env()->ram_session()->free(_ds);
}
Dataspace_capability dataspace() const { return _ds; }
bool alloc(unsigned &index_out)
{
for (unsigned index = 0; _index_valid(index); index++) {
if (!_local_base[index].is_free()) {
continue;
}
_local_base[index].alloc();
index_out = index;
return true;
}
PERR("trace-control allocaton failed");
return false;
}
void free(unsigned index)
{
if (_index_valid(index))
_local_base[index].reset();
}
Trace::Control *at(unsigned index)
{
return _index_valid(index) ? &_local_base[index] : 0;
}
};
#endif /* _CORE__INCLUDE__TRACE__CONTROL_AREA_H_ */

View File

@ -0,0 +1,152 @@
/*
* \brief Registry containing tracing policy modules
* \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 _CORE__INCLUDE__TRACE__POLICY_REGISTRY_H_
#define _CORE__INCLUDE__TRACE__POLICY_REGISTRY_H_
/* Genode includes */
#include <base/lock.h>
#include <util/list.h>
namespace Genode { namespace Trace {
class Policy_owner;
class Policy;
class Policy_registry;
} }
class Genode::Trace::Policy_owner { };
class Genode::Trace::Policy : public Genode::List<Genode::Trace::Policy>::Element
{
friend class Policy_registry;
private:
Policy_owner const &_owner;
Allocator &_md_alloc;
Policy_id const _id;
Dataspace_capability _ds;
size_t const _size;
/**
* Constructor
*
* \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)
:
_owner(owner), _md_alloc(md_alloc), _id(id), _ds(ds), _size(size)
{ }
Allocator &md_alloc() { return _md_alloc; }
bool is_owned_by(Policy_owner const &owner) const
{
return &_owner == &owner;
}
bool has_id(Policy_id id) const { return id == _id; }
public:
Dataspace_capability dataspace() const { return _ds; }
size_t size() const { return _size; }
};
/**
* Global policy registry
*/
class Genode::Trace::Policy_registry
{
private:
Lock _lock;
List<Policy> _policies;
Policy *_unsynchronized_lookup(Policy_owner const &owner, Policy_id id)
{
for (Policy *p = _policies.first(); p; p++)
if (p->is_owned_by(owner) && p->has_id(id))
return p;
throw Nonexistent_policy();
}
Policy *_any_policy_owned_by(Policy_owner const &owner)
{
for (Policy *p = _policies.first(); p; p++)
if (p->is_owned_by(owner))
return p;
return 0;
}
public:
~Policy_registry()
{
Lock::Guard guard(_lock);
while (Policy *p = _policies.first())
_policies.remove(p);
}
void insert(Policy_owner const &owner, Policy_id const id,
Allocator &md_alloc, Dataspace_capability ds, size_t size)
{
Lock::Guard guard(_lock);
Policy *policy = new (&md_alloc) Policy(owner, id, md_alloc, ds, size);
_policies.insert(policy);
}
void remove(Policy_owner &owner, Policy_id id)
{
Lock::Guard guard(_lock);
for (Policy *p = _policies.first(); p; p++)
if (p->is_owned_by(owner) && p->has_id(id))
destroy(&p->md_alloc(), p);
}
void destroy_policies_owned_by(Policy_owner const &owner)
{
Lock::Guard guard(_lock);
while (Policy *p = _any_policy_owned_by(owner)) {
_policies.remove(p);
destroy(&p->md_alloc(), p);
}
}
Dataspace_capability dataspace(Policy_owner &owner, Policy_id id)
{
Lock::Guard guard(_lock);
return _unsynchronized_lookup(owner, id)->dataspace();
}
size_t size(Policy_owner &owner, Policy_id id)
{
Lock::Guard guard(_lock);
return _unsynchronized_lookup(owner, id)->size();
}
};
#endif /* _CORE__INCLUDE__TRACE__POLICY_REGISTRY_H_ */

View File

@ -0,0 +1,76 @@
/*
* \brief TRACE root 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 _CORE__INCLUDE__TRACE__ROOT_H_
#define _CORE__INCLUDE__TRACE__ROOT_H_
/* Genode includes */
#include <root/component.h>
/* core-internal includes */
#include <trace/session_component.h>
namespace Genode { namespace Trace { class Root; } }
class Genode::Trace::Root : public Genode::Root_component<Session_component>
{
private:
Source_registry &_sources;
Policy_registry &_policies;
protected:
Session_component *_create_session(const char *args)
{
size_t ram_quota = Arg_string::find_arg(args, "ram_quota").long_value(0);
size_t arg_buffer_size = Arg_string::find_arg(args, "arg_buffer_size").ulong_value(0);
unsigned parent_levels = Arg_string::find_arg(args, "parent_levels").ulong_value(0);
char label[Trace::Session_label::MAX_SIZE];
Arg_string::find_arg(args, "label").string(label, sizeof(label), "");
if (arg_buffer_size > ram_quota)
throw Root::Invalid_args();
return new (md_alloc())
Session_component(*md_alloc(), ram_quota, arg_buffer_size,
parent_levels, label, _sources, _policies);
}
void _upgrade_session(Session_component *s, const char *args)
{
size_t ram_quota = Arg_string::find_arg(args, "ram_quota").long_value(0);
s->upgrade_ram_quota(ram_quota);
}
public:
/**
* Constructor
*
* \param session_ep entry point for managing session objects
* \param md_alloc meta data allocator used by root component
* \param ram_quota RAM for tracing purposes of this session
* \param arg_buffer_size session argument-buffer size
*/
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
Source_registry &sources, Policy_registry &policies)
:
Root_component<Session_component>(session_ep, md_alloc),
_sources(sources), _policies(policies)
{ }
};
#endif /* _CORE__INCLUDE__TRACE__ROOT_H_ */

View File

@ -0,0 +1,108 @@
/*
* \brief TRACE session implementation
* \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 _CORE__INCLUDE__TRACE__SESSION_COMPONENT_H_
#define _CORE__INCLUDE__TRACE__SESSION_COMPONENT_H_
/* Genode includes */
#include <base/allocator_guard.h>
#include <base/rpc_server.h>
#include <base/tslab.h>
#include <trace_session/trace_session.h>
/* core-local includes */
#include <trace/subject_registry.h>
#include <trace/policy_registry.h>
namespace Genode { namespace Trace { class Session_component; } }
class Genode::Trace::Session_component
:
public Genode::Rpc_object<Genode::Trace::Session,
Genode::Trace::Session_component>,
public Genode::Trace::Policy_owner
{
private:
Ram_session &_ram;
Allocator_guard _md_alloc;
Tslab<Subject, 4096> _subjects_slab;
Tslab<Policy, 4096> _policies_slab;
unsigned _parent_levels;
Session_label _label;
Source_registry &_sources;
Policy_registry &_policies;
Subject_registry _subjects;
unsigned _policy_cnt;
struct Argument_buffer
{
Ram_session &ram;
Ram_dataspace_capability ds;
char *base;
size_t size;
Argument_buffer(Ram_session &ram, size_t size)
:
ram(ram),
ds(ram.alloc(size)),
base(env()->rm_session()->attach(ds)),
size(ds.call<Dataspace::Rpc_size>())
{ }
~Argument_buffer()
{
env()->rm_session()->detach(base);
ram.free(ds);
}
} _argument_buffer;
public:
/**
* Constructor
*/
Session_component(Allocator &md_alloc, size_t ram_quota,
size_t arg_buffer_size, unsigned parent_levels,
char const *label, Source_registry &sources,
Policy_registry &policies);
~Session_component();
/**
* Register quota donation at allocator guard
*/
void upgrade_ram_quota(size_t ram_quota) { _md_alloc.upgrade(ram_quota); }
/***********************
** Session interface **
***********************/
Dataspace_capability dataspace();
size_t subjects();
Policy_id alloc_policy(size_t);
Dataspace_capability policy(Policy_id);
void unload_policy(Policy_id);
void trace(Subject_id, Policy_id, size_t);
void rule(Session_label const &, Thread_name const &, Policy_id, size_t);
void pause(Subject_id);
void resume(Subject_id);
Subject_info subject_info(Subject_id);
Dataspace_capability buffer(Subject_id);
void free(Subject_id);
};
#endif /* _CORE__INCLUDE__TRACE__SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,164 @@
/*
* \brief Registry containing possible sources of tracing data
* \author Norman Feske
* \date 2013-08-09
*/
/*
* 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 _CORE__INCLUDE__TRACE__SOURCE_REGISTRY_H_
#define _CORE__INCLUDE__TRACE__SOURCE_REGISTRY_H_
#include <util/list.h>
#include <util/string.h>
#include <base/lock.h>
#include <base/trace/types.h>
/* core includes */
#include <lifetime.h>
/* base-internal include */
#include <trace/control.h>
namespace Genode { namespace Trace {
class Source;
class Source_owner;
class Source_registry;
} }
struct Genode::Trace::Source_owner { };
/**
* Source of tracing data
*
* There is one instance per thread.
*/
class Genode::Trace::Source
:
public Genode::Volatile_object<Genode::Trace::Source>,
public Genode::List<Genode::Trace::Source>::Element
{
private:
unsigned const _unique_id;
Session_label const &_label;
Thread_name const _name;
Control &_control;
Dataspace_capability _policy;
Dataspace_capability _buffer;
Source_owner const *_owner;
static unsigned _alloc_unique_id();
public:
Source(Session_label const &label, Thread_name const &name,
Control &control)
:
_unique_id(_alloc_unique_id()),
_label(label), _name(name), _control(control), _owner(0)
{ }
/*************************************
** Interface used by TRACE service **
*************************************/
Session_label const &label() const { return _label; }
Thread_name const &name() const { return _name; }
void trace(Dataspace_capability policy, Dataspace_capability buffer)
{
_buffer = buffer;
_policy = policy;
_control.trace();
}
void enable() { _control.enable(); }
void disable() { _control.disable(); }
bool try_acquire(Source_owner const *new_owner)
{
if (_owner && _owner != new_owner)
return false;
_owner = new_owner;
return true;
}
bool is_owned_by(Source_owner const *owner) { return owner == _owner; }
void release_ownership(Source_owner const *owner)
{
if (is_owned_by(owner))
_owner = 0;
}
bool error() const { return _control.has_error(); }
bool enabled() const { return _control.is_enabled(); }
/***********************************
** Interface used by CPU service **
***********************************/
Dataspace_capability buffer() const { return _buffer; }
Dataspace_capability policy() const { return _policy; }
unsigned unique_id() const { return _unique_id; }
};
/**
* Registry to tracing sources
*
* There is a single instance within core.
*/
class Genode::Trace::Source_registry
{
private:
Lock _lock;
List<Source> _entries;
public:
/***********************************
** Interface used by CPU service **
***********************************/
void insert(Source *entry)
{
Lock::Guard guard(_lock);
_entries.insert(entry);
}
void remove(Source *entry)
{
Lock::Guard guard(_lock);
_entries.remove(entry);
}
/*************************************
** Interface used by TRACE service **
*************************************/
template <typename TEST, typename INSERT>
void export_sources(TEST &test, INSERT &insert)
{
for (Source *s = _entries.first(); s; s = s->next())
if (!test(s->unique_id()))
insert(s->unique_id(), s->weak_ptr(), s->label(), s->name());
}
};
#endif /* _CORE__INCLUDE__TRACE__SOURCE_REGISTRY_H_ */

View File

@ -0,0 +1,425 @@
/*
* \brief Registry containing possible tracing subjects
* \author Norman Feske
* \date 2013-08-09
*
* Tracing subjects represent living or previously living tracing sources
* that can have trace buffers attached. Each 'Trace::Subject' belongs to
* a TRACE session and may point to a 'Trace::Source' (which is owned by
* a CPU session).
*/
/*
* 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 _CORE__INCLUDE__TRACE__SUBJECT_REGISTRY_H_
#define _CORE__INCLUDE__TRACE__SUBJECT_REGISTRY_H_
/* Genode includes */
#include <util/list.h>
#include <util/string.h>
#include <base/lock.h>
#include <base/trace/types.h>
#include <base/env.h>
#include <dataspace/client.h>
/* core includes */
#include <lifetime.h>
#include <trace/source_registry.h>
/* base-internal include */
#include <trace/control.h>
namespace Genode { namespace Trace {
class Subject;
class Subject_registry;
} }
/**
* Subject of tracing data
*/
class Genode::Trace::Subject
:
public Genode::List<Genode::Trace::Subject>::Element,
public Genode::Trace::Source_owner
{
private:
class Ram_dataspace
{
private:
Ram_session *_ram;
size_t _size;
Ram_dataspace_capability _ds;
void _reset()
{
_ram = 0;
_size = 0;
_ds = Ram_dataspace_capability();
}
public:
Ram_dataspace() { _reset(); }
~Ram_dataspace() { flush(); }
/**
* Allocate new dataspace
*
* \return true on success, false on the attempt to call setup
* twice.
*/
bool setup(Ram_session &ram, size_t size)
{
if (_size)
return false;
_ram = &ram;
_size = size;
_ds = ram.alloc(size);
return true;
}
/**
* Clone dataspace into newly allocated dataspace
*/
bool setup(Ram_session &ram, Dataspace_capability &from_ds,
size_t size)
{
if (!from_ds.valid())
return false;
_ram = &ram;
_size = size;
_ds = ram.alloc(_size);
/* copy content */
void *src = env()->rm_session()->attach(from_ds),
*dst = env()->rm_session()->attach(_ds);
memcpy(dst, src, _size);
env()->rm_session()->detach(src);
env()->rm_session()->detach(dst);
return true;
}
/**
* Release dataspace
*/
size_t flush()
{
if (_ram)
_ram->free(_ds);
_reset();
return 0;
}
Dataspace_capability dataspace() const { return _ds; }
};
friend class Subject_registry;
Subject_id const _id;
unsigned const _source_id;
Weak_ptr<Source> _source;
Session_label const _label;
Thread_name const _name;
Ram_dataspace _buffer;
Ram_dataspace _policy;
Policy_id _policy_id;
Subject_info::State _state()
{
Locked_ptr<Source> source(_source);
/* source vanished */
if (!source.is_valid())
return Subject_info::DEAD;
if (source->enabled())
return source->is_owned_by(this) ? Subject_info::TRACED
: Subject_info::FOREIGN;
if (source->error())
return Subject_info::ERROR;
return Subject_info::UNTRACED;
}
public:
/**
* Constructor, called from 'Subject_registry' only
*/
Subject(Subject_id id, unsigned source_id, Weak_ptr<Source> &source,
Session_label const &label, Thread_name const &name)
:
_id(id), _source_id(source_id), _source(source),
_label(label), _name(name)
{ }
/**
* Return registry-local ID
*/
Subject_id id() const { return _id; }
/**
* Test if subject belongs to the specified unique source ID
*/
bool has_source_id(unsigned id) const { return id == _source_id; }
/**
* Start tracing
*
* \param size trace buffer size
*
* \throw Out_of_metadata
* \throw Already_traced
* \throw Source_is_dead
* \throw Traced_by_other_session
*/
void trace(Policy_id policy_id, Dataspace_capability policy_ds,
size_t policy_size, Ram_session &ram, size_t size)
{
_policy_id = policy_id;
if (!_buffer.setup(ram, size)
|| !_policy.setup(ram, policy_ds, policy_size))
throw Already_traced();
/* inform trace source about the new buffer */
Locked_ptr<Source> source(_source);
if (!source.is_valid())
throw Source_is_dead();
if (!source->try_acquire(this))
throw Traced_by_other_session();
source->trace(_policy.dataspace(), _buffer.dataspace());
}
void pause()
{
/* inform trace source about the new buffer */
Locked_ptr<Source> source(_source);
if (!source.is_valid())
source->disable();
}
/**
* Resume tracing of paused source
*
* \throw Source_is_dead
*/
void resume()
{
/* inform trace source about the new buffer */
Locked_ptr<Source> source(_source);
if (!source.is_valid())
throw Source_is_dead();
source->enable();
}
Subject_info info()
{
return Subject_info(_label, _name, _state(), _policy_id);
}
Dataspace_capability buffer() const { return _buffer.dataspace(); }
size_t release()
{
/* inform trace source about the new buffer */
Locked_ptr<Source> source(_source);
/* source vanished */
if (!source.is_valid())
return 0;
return _buffer.flush() + _policy.flush();
}
};
/**
* Registry to tracing subjects
*
* There exists one instance for each TRACE session.
*/
class Genode::Trace::Subject_registry
{
private:
typedef List<Subject> Subjects;
Allocator &_md_alloc;
Ram_session &_ram;
Source_registry &_sources;
unsigned _id_cnt;
Lock _lock;
Subjects _entries;
/**
* Functor for testing the existance of subjects for a given source
*
* This functor is invoked by 'Source_registry::export'.
*/
struct Tester
{
Subjects &subjects;
Tester(Subjects &subjects) : subjects(subjects) { }
bool operator () (unsigned source_id)
{
for (Subject *s = subjects.first(); s; s = s->next())
if (s->has_source_id(source_id))
return true;
return false;
}
} _tester;
/**
* Functor for inserting new subjects into the registry
*
* This functor is invoked by 'Source_registry::export'.
*/
struct Inserter
{
Subject_registry &registry;
Inserter(Subject_registry &registry) : registry(registry) { }
void operator () (unsigned source_id, Weak_ptr<Source> source,
Session_label const &label, Thread_name const &name)
{
Subject *subject = new (&registry._md_alloc)
Subject(Subject_id(registry._id_cnt++), source_id, source, label, name);
registry._entries.insert(subject);
}
} _inserter;
/**
* Destroy subject, and release policy and trace buffers
*
* \return RAM resources released during destruction
*/
size_t _unsynchronized_destroy(Subject *s)
{
_entries.remove(s);
size_t const released_ram = s->release();
destroy(&_md_alloc, s);
return released_ram;
};
/**
* Obtain subject from given session-local ID
*
* \throw Nonexistent_subject
*/
Subject *_unsynchronized_lookup_by_id(Subject_id id)
{
for (Subject *s = _entries.first(); s; s = s->next())
if (s->id() == id)
return s;
throw Nonexistent_subject();
}
public:
/**
* Constructor
*
* \param md_alloc meta-data allocator used for allocating 'Subject'
* objects.
* \param ram RAM session used for the allocation of trace
* buffers and policy dataspaces.
*/
Subject_registry(Allocator &md_alloc, Ram_session &ram,
Source_registry &sources)
:
_md_alloc(md_alloc), _ram(ram), _sources(sources), _id_cnt(0),
_tester(_entries), _inserter(*this)
{ }
/**
* Destructor
*/
~Subject_registry()
{
Lock guard(_lock);
while (Subject *s = _entries.first())
_unsynchronized_destroy(s);
}
/**
* \throw Ram_session::Quota_exceeded
*/
void import_new_sources(Source_registry &sources)
{
Lock guard(_lock);
_sources.export_sources(_tester, _inserter);
}
/**
* Retrieve existing subject IDs
*/
size_t subjects(Subject_id *dst, size_t dst_len)
{
Lock guard(_lock);
unsigned i = 0;
for (Subject *s = _entries.first(); s && i < dst_len; s = s->next())
dst[i++] = s->id();
return i;
}
/**
* Remove subject and release resources
*
* \return RAM resources released as a side effect for removing the
* subject (i.e., if the subject held a trace buffer or
* policy dataspace). The value does not account for
* memory allocated from the metadata allocator.
*/
size_t release(Subject_id subject_id)
{
Lock guard(_lock);
Subject *subject = _unsynchronized_lookup_by_id(subject_id);
if (subject)
return _unsynchronized_destroy(subject);
return 0;
}
Subject *lookup_by_id(Subject_id id)
{
Lock guard(_lock);
return _unsynchronized_lookup_by_id(id);
}
};
#endif /* _CORE__INCLUDE__TRACE__SUBJECT_REGISTRY_H_ */

View File

@ -32,6 +32,7 @@
#include <io_mem_root.h>
#include <irq_root.h>
#include <signal_root.h>
#include <trace/root.h>
#include <platform_services.h>
using namespace Genode;
@ -182,6 +183,9 @@ int main()
PDBG("--- create local services ---");
static Trace::Source_registry trace_sources;
static Trace::Policy_registry trace_policies;
/*
* Initialize root interfaces for our services
*/
@ -198,7 +202,8 @@ int main()
static Rom_root rom_root (e, e, platform()->rom_fs(), &sliced_heap);
static Rm_root rm_root (e, e, e, &sliced_heap, core_env()->cap_session(),
platform()->vm_start(), platform()->vm_size());
static Cpu_root cpu_root (e, e, rm_root.pager_ep(), &sliced_heap);
static Cpu_root cpu_root (e, e, rm_root.pager_ep(), &sliced_heap,
trace_sources);
static Pd_root pd_root (e, e, &sliced_heap);
static Log_root log_root (e, &sliced_heap);
static Io_mem_root io_mem_root (e, e, platform()->io_mem_alloc(),
@ -206,6 +211,7 @@ int main()
static Irq_root irq_root (core_env()->cap_session(),
platform()->irq_alloc(), &sliced_heap);
static Signal_root signal_root (&sliced_heap, core_env()->cap_session());
static Trace::Root trace_root (e, &sliced_heap, trace_sources, trace_policies);
/*
* Play our role as parent of init and declare our services.
@ -221,7 +227,8 @@ int main()
Local_service(Log_session::service_name(), &log_root),
Local_service(Io_mem_session::service_name(), &io_mem_root),
Local_service(Irq_session::service_name(), &irq_root),
Local_service(Signal_session::service_name(), &signal_root)
Local_service(Signal_session::service_name(), &signal_root),
Local_service(Trace::Session::service_name(), &trace_root)
};
/* make our local services known to service pool */

View File

@ -0,0 +1,161 @@
/*
* \brief TRACE session implementation
* \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.
*/
/* core-internal includes */
#include <trace/session_component.h>
#include <dataspace/capability.h>
#include <base/rpc_client.h>
using namespace Genode;
using namespace Genode::Trace;
Dataspace_capability Session_component::dataspace()
{
return _argument_buffer.ds;
}
size_t Session_component::subjects()
{
_subjects.import_new_sources(_sources);
return _subjects.subjects((Subject_id *)_argument_buffer.base,
_argument_buffer.size/sizeof(Subject_id));
}
Policy_id Session_component::alloc_policy(size_t size)
{
if (size > _argument_buffer.size)
throw Policy_too_large();
Policy_id const id(_policy_cnt++);
try { _md_alloc.withdraw(size); }
catch (...) { throw Out_of_metadata(); }
try {
Ram_dataspace_capability ds = _ram.alloc(size);
_policies.insert(*this, id, _policies_slab, ds, size);
} catch (...) {
/* revert withdrawal or quota and re-throw exception */
_md_alloc.upgrade(size);
throw;
}
return id;
}
Dataspace_capability Session_component::policy(Policy_id id)
{
return _policies.dataspace(*this, id);
}
void Session_component::unload_policy(Policy_id id)
{
_policies.remove(*this, id);
}
void Session_component::trace(Subject_id subject_id, Policy_id policy_id,
size_t buffer_size)
{
size_t const policy_size = _policies.size(*this, policy_id);
size_t const required_ram = buffer_size + policy_size;
/*
* Account RAM needed for trace buffer and policy buffer to the trace
* session.
*/
try { _md_alloc.withdraw(required_ram); }
catch (...) { throw Out_of_metadata(); }
try {
Trace::Subject *subject = _subjects.lookup_by_id(subject_id);
subject->trace(policy_id, _policies.dataspace(*this, policy_id),
policy_size, _ram, buffer_size);
} catch (...) {
/* revert withdrawal or quota and re-throw exception */
_md_alloc.upgrade(required_ram);
throw;
}
}
void Session_component::rule(Session_label const &, Thread_name const &,
Policy_id, size_t)
{
/* not implemented yet */
}
void Session_component::pause(Subject_id subject_id)
{
_subjects.lookup_by_id(subject_id)->pause();
}
void Session_component::resume(Subject_id subject_id)
{
_subjects.lookup_by_id(subject_id)->resume();
}
Subject_info Session_component::subject_info(Subject_id subject_id)
{
return _subjects.lookup_by_id(subject_id)->info();
}
Dataspace_capability Session_component::buffer(Subject_id subject_id)
{
return _subjects.lookup_by_id(subject_id)->buffer();
}
void Session_component::free(Subject_id subject_id)
{
size_t released_ram = _subjects.lookup_by_id(subject_id)->release();
_md_alloc.upgrade(released_ram);
}
Session_component::Session_component(Allocator &md_alloc, size_t ram_quota,
size_t arg_buffer_size, unsigned parent_levels,
char const *label, Source_registry &sources,
Policy_registry &policies)
:
_ram(*env()->ram_session()),
_md_alloc(&md_alloc, ram_quota),
_subjects_slab(&_md_alloc),
_policies_slab(&_md_alloc),
_parent_levels(parent_levels),
_label(label),
_sources(sources),
_policies(policies),
_subjects(_subjects_slab, _ram, _sources),
_argument_buffer(_ram, arg_buffer_size)
{
_md_alloc.withdraw(arg_buffer_size);
}
Session_component::~Session_component()
{
_policies.destroy_policies_owned_by(*this);
}

70
os/run/trace.run Normal file
View File

@ -0,0 +1,70 @@
#
# Build
#
set build_components {
core init
drivers/timer
test/trace
lib/trace/policy/rpc_name
}
build $build_components
create_boot_directory
#
# Generate config
#
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="TRACE"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="test-trace">
<resource name="RAM" quantum="10M"/>
<config>
<trace_policy label="init -> test-trace" module="rpc_name" />
</config>
</start>
</config>}
install_config $config
#
# Boot modules
#
# generic modules
set boot_modules {
core init
timer
test-trace
rpc_name
}
build_boot_image $boot_modules
append qemu_args " -nographic -serial mon:stdio -m 256 "
run_genode_until forever
#{.*child exited with exit value 0.* } 60

258
os/src/test/trace/main.cc Normal file
View File

@ -0,0 +1,258 @@
/*
* \brief Low-level test for TRACE service
* \author Norman Feske
* \author Josef Soentgen
* \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.
*/
/* Genode includes */
#include <trace_session/connection.h>
#include <timer_session/connection.h>
#include <os/config.h>
static char const *state_name(Genode::Trace::Subject_info::State state)
{
switch (state) {
case Genode::Trace::Subject_info::INVALID: return "INVALID";
case Genode::Trace::Subject_info::UNTRACED: return "UNTRACED";
case Genode::Trace::Subject_info::TRACED: return "TRACED";
case Genode::Trace::Subject_info::FOREIGN: return "FOREIGN";
case Genode::Trace::Subject_info::ERROR: return "ERROR";
case Genode::Trace::Subject_info::DEAD: return "DEAD";
}
return "undefined";
}
struct Test_thread : Genode::Thread<1024 * sizeof (unsigned long)>
{
Timer::Connection _timer;
void entry()
{
using namespace Genode;
for (size_t i = 0; ; i++) {
if (i & 0x3) {
Ram_dataspace_capability ds_cap = env()->ram_session()->alloc(1024);
env()->ram_session()->free(ds_cap);
}
_timer.msleep(250);
}
}
Test_thread(const char *name)
: Thread(name) { start(); }
};
using namespace Genode;
class Trace_buffer_monitor
{
private:
enum { MAX_ENTRY_BUF = 256 };
Trace::Subject_id _id;
Trace::Buffer *_buffer;
addr_t _read_head;
addr_t _write_head;
size_t _overflow;
char _entry_buf[MAX_ENTRY_BUF];
const char * _next_entry()
{
size_t len = *(addr_t*) _read_head;
char *p = (char*) _read_head;
char tmp[len + 1];
p += sizeof(size_t);
if (len > 0)
memcpy(tmp, (void *)(p), len); tmp[len] = '\0';
_read_head = (addr_t)(p + len);
snprintf(_entry_buf, MAX_ENTRY_BUF, "0x%lx '%s'",
_read_head, tmp);
return _entry_buf;
}
void _update_heads()
{
_write_head = _buffer->entries();
_write_head += _buffer->head_offset();
if (_write_head < _read_head) {
_overflow++;
/* XXX read missing entries before resetting */
_read_head = _buffer->entries();
}
}
public:
Trace_buffer_monitor(Trace::Subject_id id, Dataspace_capability ds_cap)
:
_id(id),
_buffer(env()->rm_session()->attach(ds_cap)),
_read_head(_buffer->entries()),
_write_head(_buffer->entries() + _buffer->head_offset()),
_overflow(0)
{
PLOG("monitor subject:%d buffer:0x%lx start:0x%lx",
_id.id, (addr_t)_buffer, _buffer->entries());
}
~Trace_buffer_monitor()
{
if (_buffer)
env()->rm_session()->detach(_buffer);
}
Trace::Subject_id id() { return _id; };
void dump(unsigned limit)
{
_update_heads();
PLOG("overflows: %zu", _overflow);
if (limit) {
PLOG("read up-to %u events", limit);
for (unsigned i = 0; i < limit; i++) {
const char *s = _next_entry();
if (s)
PLOG("%s", s);
}
} else {
PLOG("read all remaining events");
while (_read_head < _write_head) {
const char *s = _next_entry();
if (s)
PLOG("%s", s);
}
}
}
};
int main(int argc, char **argv)
{
using namespace Genode;
printf("--- test-trace started ---\n");
static Genode::Trace::Connection trace(1024*1024, 64*1024, 0);
static Timer::Connection timer;
static Test_thread test("test-thread");
static Trace_buffer_monitor *test_monitor = 0;
Genode::Trace::Policy_id policy_id;
bool policy_set = false;
char policy_label[64];
char policy_module[64];
Rom_dataspace_capability policy_module_rom_ds;
try {
Xml_node policy = config()->xml_node().sub_node("trace_policy");
for (;; policy = policy.next("trace_policy")) {
try {
policy.attribute("label").value(policy_label, sizeof (policy_label));
policy.attribute("module").value(policy_module, sizeof (policy_module));
static Rom_connection policy_rom(policy_module);
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_session()->attach(ds_cap);
void *rom = env()->rm_session()->attach(policy_module_rom_ds);
memcpy(ram, rom, rom_size);
env()->rm_session()->detach(ram);
env()->rm_session()->detach(rom);
}
} catch (...) {
PERR("could not load module '%s' for label '%s'", policy_module, policy_label);
}
PINF("load module: '%s' for label: '%s'", policy_module, policy_label);
if (policy.is_last("trace_policy")) break;
}
} catch (...) { }
for (size_t cnt = 0; cnt < 5; cnt++) {
timer.msleep(3000);
Trace::Subject_id subjects[32];
size_t num_subjects = trace.subjects(subjects, 32);
printf("%zd tracing subjects present\n", num_subjects);
for (size_t i = 0; i < num_subjects; i++) {
Trace::Subject_info info = trace.subject_info(subjects[i]);
printf("ID:%d label:\"%s\" name:\"%s\" state:%s policy:%d\n",
subjects[i].id,
info.session_label().string(),
info.thread_name().string(),
state_name(info.state()),
info.policy_id().id);
/* enable tracing */
if (!policy_set
&& strcmp(info.session_label().string(), policy_label) == 0
&& strcmp(info.thread_name().string(), "test-thread") == 0) {
try {
PINF("enable tracing for thread:'%s' with policy:%d",
info.thread_name().string(), policy_id.id);
trace.trace(subjects[i].id, policy_id, 16384U);
Dataspace_capability ds_cap = trace.buffer(subjects[i].id);
test_monitor = new (env()->heap()) Trace_buffer_monitor(subjects[i].id, ds_cap);
} catch (Trace::Source_is_dead) { PERR("source is dead"); }
policy_set = true;
}
/* read events from trace buffer */
if (test_monitor) {
if (subjects[i].id == test_monitor->id().id)
test_monitor->dump(0);
}
}
}
if (test_monitor)
destroy(env()->heap(), test_monitor);
printf("--- test-trace finished ---\n");
return 0;
}

View File

@ -0,0 +1,3 @@
TARGET = test-trace
SRC_CC = main.cc
LIBS += base