From 149356f7abbb7c34eb4c3c2b537e346867f43654 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Sat, 10 Aug 2013 03:44:55 +0200 Subject: [PATCH] core: TRACE service interface and implementation --- base-codezero/src/core/target.inc | 5 +- base-fiasco/src/core/target.inc | 5 +- .../src/core/include/cpu_session_component.h | 54 ++- base-foc/src/core/include/platform_thread.h | 2 +- base-foc/src/core/platform_thread.cc | 3 +- base-foc/src/core/target.inc | 3 + base-hw/src/core/target.inc | 5 +- .../src/core/include/cpu_session_component.h | 51 ++- base-linux/src/core/target.mk | 3 + .../src/core/include/cpu_session_component.h | 55 ++- base-nova/src/core/target.inc | 3 + base-okl4/src/core/target.inc | 3 + base-pistachio/src/core/target.inc | 3 + base/include/base/trace/types.h | 119 +++++ base/include/cpu_session/connection.h | 2 +- base/include/trace_session/client.h | 106 +++++ base/include/trace_session/connection.h | 39 ++ base/include/trace_session/trace_session.h | 159 +++++++ base/src/core/cpu_session_component.cc | 106 ++++- base/src/core/include/cpu_root.h | 28 +- base/src/core/include/cpu_session_component.h | 55 ++- base/src/core/include/trace/control_area.h | 98 ++++ base/src/core/include/trace/policy_registry.h | 152 +++++++ base/src/core/include/trace/root.h | 76 ++++ .../core/include/trace/session_component.h | 108 +++++ base/src/core/include/trace/source_registry.h | 164 +++++++ .../src/core/include/trace/subject_registry.h | 425 ++++++++++++++++++ base/src/core/main.cc | 11 +- base/src/core/trace_session_component.cc | 161 +++++++ os/run/trace.run | 70 +++ os/src/test/trace/main.cc | 258 +++++++++++ os/src/test/trace/target.mk | 3 + 32 files changed, 2249 insertions(+), 86 deletions(-) create mode 100644 base/include/base/trace/types.h create mode 100644 base/include/trace_session/client.h create mode 100644 base/include/trace_session/connection.h create mode 100644 base/include/trace_session/trace_session.h create mode 100644 base/src/core/include/trace/control_area.h create mode 100644 base/src/core/include/trace/policy_registry.h create mode 100644 base/src/core/include/trace/root.h create mode 100644 base/src/core/include/trace/session_component.h create mode 100644 base/src/core/include/trace/source_registry.h create mode 100644 base/src/core/include/trace/subject_registry.h create mode 100644 base/src/core/trace_session_component.cc create mode 100644 os/run/trace.run create mode 100644 os/src/test/trace/main.cc create mode 100644 os/src/test/trace/target.mk diff --git a/base-codezero/src/core/target.inc b/base-codezero/src/core/target.inc index e39d4f4e4..efcdc655f 100644 --- a/base-codezero/src/core/target.inc +++ b/base-codezero/src/core/target.inc @@ -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) diff --git a/base-fiasco/src/core/target.inc b/base-fiasco/src/core/target.inc index 789c72401..5c52fe575 100644 --- a/base-fiasco/src/core/target.inc +++ b/base-fiasco/src/core/target.inc @@ -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) diff --git a/base-foc/src/core/include/cpu_session_component.h b/base-foc/src/core/include/cpu_session_component.h index 6f38006a7..588b972b4 100644 --- a/base-foc/src/core/include/cpu_session_component.h +++ b/base-foc/src/core/include/cpu_session_component.h @@ -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 +#include +#include namespace Genode { @@ -45,18 +48,33 @@ namespace Genode { class Cpu_thread_component : public Rpc_object, public List::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 { + public: + + typedef Cpu_thread_component::Session_label Session_label; + private: /** @@ -93,11 +121,12 @@ namespace Genode { */ typedef Tslab 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 _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 diff --git a/base-foc/src/core/include/platform_thread.h b/base-foc/src/core/include/platform_thread.h index a4e407417..316637ad6 100644 --- a/base-foc/src/core/include/platform_thread.h +++ b/base-foc/src/core/include/platform_thread.h @@ -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 diff --git a/base-foc/src/core/platform_thread.cc b/base-foc/src/core/platform_thread.cc index ae7cc527e..ab64cc9e6 100644 --- a/base-foc/src/core/platform_thread.cc +++ b/base-foc/src/core/platform_thread.cc @@ -261,8 +261,7 @@ Weak_ptr 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), diff --git a/base-foc/src/core/target.inc b/base-foc/src/core/target.inc index 8767aadc2..dacf93940 100644 --- a/base-foc/src/core/target.inc +++ b/base-foc/src/core/target.inc @@ -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 diff --git a/base-hw/src/core/target.inc b/base-hw/src/core/target.inc index b10dd597b..92172f217 100644 --- a/base-hw/src/core/target.inc +++ b/base-hw/src/core/target.inc @@ -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 diff --git a/base-linux/src/core/include/cpu_session_component.h b/base-linux/src/core/include/cpu_session_component.h index 02ddee441..a3973c477 100644 --- a/base-linux/src/core/include/cpu_session_component.h +++ b/base-linux/src/core/include/cpu_session_component.h @@ -26,6 +26,8 @@ /* core includes */ #include #include +#include +#include namespace Genode { @@ -45,18 +47,33 @@ namespace Genode { class Cpu_thread_component : public Rpc_object, public List::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 { + 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 diff --git a/base-linux/src/core/target.mk b/base-linux/src/core/target.mk index d2b9741d4..d9fc4a30e 100644 --- a/base-linux/src/core/target.mk +++ b/base-linux/src/core/target.mk @@ -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 diff --git a/base-nova/src/core/include/cpu_session_component.h b/base-nova/src/core/include/cpu_session_component.h index ca4ee2879..79f54a7ec 100644 --- a/base-nova/src/core/include/cpu_session_component.h +++ b/base-nova/src/core/include/cpu_session_component.h @@ -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 +#include +#include namespace Genode { @@ -45,18 +48,33 @@ namespace Genode { class Cpu_thread_component : public Rpc_object, public List::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 { + public: + + typedef Cpu_thread_component::Session_label Session_label; + private: /** @@ -93,11 +121,12 @@ namespace Genode { */ typedef Tslab 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 _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 diff --git a/base-nova/src/core/target.inc b/base-nova/src/core/target.inc index cf721f485..898f5449a 100644 --- a/base-nova/src/core/target.inc +++ b/base-nova/src/core/target.inc @@ -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) diff --git a/base-okl4/src/core/target.inc b/base-okl4/src/core/target.inc index c0891cf38..1a79e751d 100644 --- a/base-okl4/src/core/target.inc +++ b/base-okl4/src/core/target.inc @@ -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) diff --git a/base-pistachio/src/core/target.inc b/base-pistachio/src/core/target.inc index 4b146b8fe..5505bcfe3 100644 --- a/base-pistachio/src/core/target.inc +++ b/base-pistachio/src/core/target.inc @@ -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) diff --git a/base/include/base/trace/types.h b/base/include/base/trace/types.h new file mode 100644 index 000000000..670a105e8 --- /dev/null +++ b/base/include/base/trace/types.h @@ -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 + +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 + 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_ */ diff --git a/base/include/cpu_session/connection.h b/base/include/cpu_session/connection.h index 464d3f1a7..320a33e54 100644 --- a/base/include/cpu_session/connection.h +++ b/base/include/cpu_session/connection.h @@ -35,7 +35,7 @@ namespace Genode { Affinity const &affinity = Affinity()) : Connection( - 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()) { } }; diff --git a/base/include/trace_session/client.h b/base/include/trace_session/client.h new file mode 100644 index 000000000..a37b45b5f --- /dev/null +++ b/base/include/trace_session/client.h @@ -0,0 +1,106 @@ +/* + * \brief Client-side TRACE session interface + * \author Norman Feske + * \date 2013-08-12 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__TRACE_SESSION__CLIENT_H_ +#define _INCLUDE__TRACE_SESSION__CLIENT_H_ + +#include +#include +#include + +namespace Genode { namespace Trace { struct Session_client; } } + + +struct Genode::Trace::Session_client : Genode::Rpc_client +{ + 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()) + { } + + ~Argument_buffer() + { + env()->rm_session()->detach(base); + } + }; + + Argument_buffer _argument_buffer; + + public: + + /** + * Constructor + */ + explicit Session_client(Capability session) + : + Rpc_client(session), + _argument_buffer(call()) + { } + + /** + * Retrieve subject directory + */ + size_t subjects(Subject_id *dst, size_t dst_len) + { + size_t const num_subjects = min(call(), dst_len); + + memcpy(dst, _argument_buffer.base, dst_len*sizeof(Subject_id)); + + return num_subjects; + } + + Policy_id alloc_policy(size_t size) { + return call(size); } + + Dataspace_capability policy(Policy_id policy_id) { + return call(policy_id); } + + void unload_policy(Policy_id policy_id) { + call(policy_id); } + + void trace(Subject_id s, Policy_id p, size_t buffer_size) { + call(s, p, buffer_size); } + + void rule(Session_label const &label, Thread_name const &thread, + Policy_id policy, size_t buffer_size) { + call(label, thread, policy, buffer_size); } + + void pause(Subject_id subject) { + call(subject); } + + void resume(Subject_id subject) { + call(subject); } + + Subject_info subject_info(Subject_id subject) { + return call(subject); } + + Dataspace_capability buffer(Subject_id subject) { + return call(subject); } + + void free(Subject_id subject) { + call(subject); } +}; + +#endif /* _INCLUDE__TRACE_SESSION__CLIENT_H_ */ diff --git a/base/include/trace_session/connection.h b/base/include/trace_session/connection.h new file mode 100644 index 000000000..7ce1d570a --- /dev/null +++ b/base/include/trace_session/connection.h @@ -0,0 +1,39 @@ +/* + * \brief Connection to TRACE service + * \author Norman Feske + * \date 2013-08-11 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__TRACE_SESSION__CONNECTION_H_ +#define _INCLUDE__TRACE_SESSION__CONNECTION_H_ + +#include +#include + +namespace Genode { namespace Trace { struct Connection; } } + +struct Genode::Trace::Connection : Genode::Connection, + 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("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_ */ diff --git a/base/include/trace_session/trace_session.h b/base/include/trace_session/trace_session.h new file mode 100644 index 000000000..42a4550c6 --- /dev/null +++ b/base/include/trace_session/trace_session.h @@ -0,0 +1,159 @@ +/* + * \brief TRACE session interface + * \author Norman Feske + * \date 2013-08-11 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_ +#define _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_ + +#include +#include +#include +#include + +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_functions; +}; + +#endif /* _INCLUDE__TRACE_SESSION__TRACE_SESSION_H_ */ diff --git a/base/src/core/cpu_session_component.cc b/base/src/core/cpu_session_component.cc index 7cd975230..c194dc609 100644 --- a/base/src/core/cpu_session_component.cc +++ b/base/src/core/cpu_session_component.cc @@ -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::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::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::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++; +} + diff --git a/base/src/core/include/cpu_root.h b/base/src/core/include/cpu_root.h index 4b687ce2f..279507fb7 100644 --- a/base/src/core/include/cpu_root.h +++ b/base/src/core/include/cpu_root.h @@ -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(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) { } }; } diff --git a/base/src/core/include/cpu_session_component.h b/base/src/core/include/cpu_session_component.h index 66b70e887..8232c4e36 100644 --- a/base/src/core/include/cpu_session_component.h +++ b/base/src/core/include/cpu_session_component.h @@ -22,9 +22,11 @@ #include #include -/* Core includes */ +/* core includes */ #include #include +#include +#include namespace Genode { @@ -44,18 +46,33 @@ namespace Genode { class Cpu_thread_component : public Rpc_object, public List::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 { + 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); diff --git a/base/src/core/include/trace/control_area.h b/base/src/core/include/trace/control_area.h new file mode 100644 index 000000000..fb2d1aacc --- /dev/null +++ b/base/src/core/include/trace/control_area.h @@ -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 +#include + +/* base-internal includes */ +#include + +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_ */ diff --git a/base/src/core/include/trace/policy_registry.h b/base/src/core/include/trace/policy_registry.h new file mode 100644 index 000000000..4a5b9f4f4 --- /dev/null +++ b/base/src/core/include/trace/policy_registry.h @@ -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 +#include + +namespace Genode { namespace Trace { + class Policy_owner; + class Policy; + class Policy_registry; +} } + + +class Genode::Trace::Policy_owner { }; + + +class Genode::Trace::Policy : public Genode::List::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 _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_ */ diff --git a/base/src/core/include/trace/root.h b/base/src/core/include/trace/root.h new file mode 100644 index 000000000..c3a69d052 --- /dev/null +++ b/base/src/core/include/trace/root.h @@ -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 + +/* core-internal includes */ +#include + +namespace Genode { namespace Trace { class Root; } } + + +class Genode::Trace::Root : public Genode::Root_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_ep, md_alloc), + _sources(sources), _policies(policies) + { } +}; + +#endif /* _CORE__INCLUDE__TRACE__ROOT_H_ */ diff --git a/base/src/core/include/trace/session_component.h b/base/src/core/include/trace/session_component.h new file mode 100644 index 000000000..9d2ab28a1 --- /dev/null +++ b/base/src/core/include/trace/session_component.h @@ -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 +#include +#include +#include + +/* core-local includes */ +#include +#include + +namespace Genode { namespace Trace { class Session_component; } } + + +class Genode::Trace::Session_component +: + public Genode::Rpc_object, + public Genode::Trace::Policy_owner +{ + private: + + Ram_session &_ram; + Allocator_guard _md_alloc; + Tslab _subjects_slab; + Tslab _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()) + { } + + ~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_ */ diff --git a/base/src/core/include/trace/source_registry.h b/base/src/core/include/trace/source_registry.h new file mode 100644 index 000000000..217bf150f --- /dev/null +++ b/base/src/core/include/trace/source_registry.h @@ -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 +#include +#include +#include + +/* core includes */ +#include + +/* base-internal include */ +#include + +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, + public Genode::List::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 _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 + 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_ */ diff --git a/base/src/core/include/trace/subject_registry.h b/base/src/core/include/trace/subject_registry.h new file mode 100644 index 000000000..e548d2343 --- /dev/null +++ b/base/src/core/include/trace/subject_registry.h @@ -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 +#include +#include +#include +#include +#include + +/* core includes */ +#include +#include + +/* base-internal include */ +#include + +namespace Genode { namespace Trace { + class Subject; + class Subject_registry; +} } + + +/** + * Subject of tracing data + */ +class Genode::Trace::Subject +: + public Genode::List::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; + 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 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, + 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); + + 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); + + 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); + + 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 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 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, + 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_ */ diff --git a/base/src/core/main.cc b/base/src/core/main.cc index ef82d1611..d43e58eed 100644 --- a/base/src/core/main.cc +++ b/base/src/core/main.cc @@ -32,6 +32,7 @@ #include #include #include +#include #include 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 */ diff --git a/base/src/core/trace_session_component.cc b/base/src/core/trace_session_component.cc new file mode 100644 index 000000000..343a99b9c --- /dev/null +++ b/base/src/core/trace_session_component.cc @@ -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 +#include +#include + + +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); +} diff --git a/os/run/trace.run b/os/run/trace.run new file mode 100644 index 000000000..99c2d96c7 --- /dev/null +++ b/os/run/trace.run @@ -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 { + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +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 diff --git a/os/src/test/trace/main.cc b/os/src/test/trace/main.cc new file mode 100644 index 000000000..085b4a634 --- /dev/null +++ b/os/src/test/trace/main.cc @@ -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 +#include +#include + +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; +} diff --git a/os/src/test/trace/target.mk b/os/src/test/trace/target.mk new file mode 100644 index 000000000..a5a6abb45 --- /dev/null +++ b/os/src/test/trace/target.mk @@ -0,0 +1,3 @@ +TARGET = test-trace +SRC_CC = main.cc +LIBS += base