mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +00:00
core: TRACE service interface and implementation
This commit is contained in:
parent
fe4a6d7d81
commit
149356f7ab
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
119
base/include/base/trace/types.h
Normal file
119
base/include/base/trace/types.h
Normal 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_ */
|
@ -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()) { }
|
||||
};
|
||||
|
106
base/include/trace_session/client.h
Normal file
106
base/include/trace_session/client.h
Normal 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_ */
|
39
base/include/trace_session/connection.h
Normal file
39
base/include/trace_session/connection.h
Normal 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_ */
|
159
base/include/trace_session/trace_session.h
Normal file
159
base/include/trace_session/trace_session.h
Normal 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_ */
|
@ -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++;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{ }
|
||||
};
|
||||
}
|
||||
|
@ -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);
|
||||
|
98
base/src/core/include/trace/control_area.h
Normal file
98
base/src/core/include/trace/control_area.h
Normal 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_ */
|
152
base/src/core/include/trace/policy_registry.h
Normal file
152
base/src/core/include/trace/policy_registry.h
Normal 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_ */
|
76
base/src/core/include/trace/root.h
Normal file
76
base/src/core/include/trace/root.h
Normal 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_ */
|
108
base/src/core/include/trace/session_component.h
Normal file
108
base/src/core/include/trace/session_component.h
Normal 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_ */
|
164
base/src/core/include/trace/source_registry.h
Normal file
164
base/src/core/include/trace/source_registry.h
Normal 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_ */
|
425
base/src/core/include/trace/subject_registry.h
Normal file
425
base/src/core/include/trace/subject_registry.h
Normal 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 ®istry;
|
||||
|
||||
Inserter(Subject_registry ®istry) : registry(registry) { }
|
||||
|
||||
void operator () (unsigned source_id, Weak_ptr<Source> source,
|
||||
Session_label const &label, Thread_name const &name)
|
||||
{
|
||||
Subject *subject = new (®istry._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_ */
|
@ -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 */
|
||||
|
161
base/src/core/trace_session_component.cc
Normal file
161
base/src/core/trace_session_component.cc
Normal 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
70
os/run/trace.run
Normal 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
258
os/src/test/trace/main.cc
Normal 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;
|
||||
}
|
3
os/src/test/trace/target.mk
Normal file
3
os/src/test/trace/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-trace
|
||||
SRC_CC = main.cc
|
||||
LIBS += base
|
Loading…
Reference in New Issue
Block a user