diff --git a/base-codezero/lib/mk/base-common.mk b/base-codezero/lib/mk/base-common.mk index b3ab3b7c8..3c9fabf93 100644 --- a/base-codezero/lib/mk/base-common.mk +++ b/base-codezero/lib/mk/base-common.mk @@ -20,12 +20,13 @@ SRC_CC += elf/elf_binary.cc SRC_CC += lock/lock.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc server/common.cc -SRC_CC += thread/thread.cc thread/thread_bootstrap.cc +SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc SRC_CC += env/utcb.cc SRC_CC += lock/cmpxchg.cc -INC_DIR += $(REP_DIR)/src/base/lock -INC_DIR += $(REP_DIR)/include/codezero/dummies +INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/thread +INC_DIR += $(REP_DIR)/include/codezero/dummies vpath cap_copy.cc $(BASE_DIR)/src/platform vpath %.cc $(REP_DIR)/src/base diff --git a/base-fiasco/lib/mk/base-common.mk b/base-fiasco/lib/mk/base-common.mk index a0857e969..35859aa5f 100644 --- a/base-fiasco/lib/mk/base-common.mk +++ b/base-fiasco/lib/mk/base-common.mk @@ -20,9 +20,10 @@ SRC_CC += elf/elf_binary.cc SRC_CC += lock/lock.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc server/common.cc -SRC_CC += thread/thread.cc thread/thread_bootstrap_empty.cc +SRC_CC += thread/thread.cc thread/thread_bootstrap_empty.cc thread/trace.cc -INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/thread vpath cap_copy.cc $(BASE_DIR)/src/platform vpath %.cc $(REP_DIR)/src/base diff --git a/base-foc/lib/mk/base-common.inc b/base-foc/lib/mk/base-common.inc index 2c172864b..87e12dbc2 100644 --- a/base-foc/lib/mk/base-common.inc +++ b/base-foc/lib/mk/base-common.inc @@ -20,9 +20,11 @@ SRC_CC += lock/lock.cc SRC_CC += env/spin_lock.cc env/cap_map.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc server/common.cc -SRC_CC += thread/thread.cc thread/thread_bootstrap.cc +SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc -INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock +INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/thread vpath %.cc $(REP_DIR)/src/base vpath %.cc $(BASE_DIR)/src/base diff --git a/base-foc/src/base/thread/thread.cc b/base-foc/src/base/thread/thread.cc index 8b93927be..6f8dcef83 100644 --- a/base-foc/src/base/thread/thread.cc +++ b/base-foc/src/base/thread/thread.cc @@ -182,7 +182,8 @@ void Thread_base::name(char *dst, size_t dst_len) } -Thread_base *Thread_base::myself() { +Thread_base *Thread_base::myself() +{ using namespace Fiasco; return reinterpret_cast(l4_utcb_tcr()->user[UTCB_TCR_THREAD_OBJ]); diff --git a/base-hw/lib/mk/base-common.mk b/base-hw/lib/mk/base-common.mk index bee58c662..0c9b37f85 100644 --- a/base-hw/lib/mk/base-common.mk +++ b/base-hw/lib/mk/base-common.mk @@ -18,9 +18,11 @@ SRC_CC += console/console.cc SRC_CC += lock/lock.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc server/common.cc -SRC_CC += thread/thread_bootstrap.cc +SRC_CC += thread/thread_bootstrap.cc thread/trace.cc -INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock +INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/thread vpath %.cc $(REP_DIR)/src/base vpath %.cc $(BASE_DIR)/src/base diff --git a/base-linux/lib/mk/base-common.mk b/base-linux/lib/mk/base-common.mk index a394adf7e..1754058da 100644 --- a/base-linux/lib/mk/base-common.mk +++ b/base-linux/lib/mk/base-common.mk @@ -19,11 +19,13 @@ SRC_CC += lock/lock.cc SRC_CC += env/rm_session_mmap.cc env/debug.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc server/common.cc +SRC_CC += thread/trace.cc -INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock -INC_DIR += $(REP_DIR)/src/base/ipc -INC_DIR += $(REP_DIR)/src/base/env -INC_DIR += $(REP_DIR)/src/platform $(BASE_DIR)/src/platform +INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock +INC_DIR += $(REP_DIR)/src/base/ipc +INC_DIR += $(REP_DIR)/src/base/env +INC_DIR += $(REP_DIR)/src/platform $(BASE_DIR)/src/platform +INC_DIR += $(BASE_DIR)/src/base/thread vpath %.cc $(REP_DIR)/src/base vpath %.cc $(BASE_DIR)/src/base diff --git a/base-linux/src/core/target.mk b/base-linux/src/core/target.mk index 097a8a9b3..d2b9741d4 100644 --- a/base-linux/src/core/target.mk +++ b/base-linux/src/core/target.mk @@ -28,7 +28,7 @@ INC_DIR += $(REP_DIR)/src/core/include \ $(REP_DIR)/src/platform \ $(REP_DIR)/src/base/ipc \ $(REP_DIR)/src/base/env \ - $(REP_DIR)/src/base/console + $(REP_DIR)/src/base/console \ HOST_INC_DIR += /usr/include @@ -50,4 +50,5 @@ vpath signal_session_component.cc $(GEN_CORE_DIR) vpath signal_source_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 vpath %.cc $(PRG_DIR) diff --git a/base-nova/lib/mk/base-common.inc b/base-nova/lib/mk/base-common.inc index 13fe0c5d1..d492d4511 100644 --- a/base-nova/lib/mk/base-common.inc +++ b/base-nova/lib/mk/base-common.inc @@ -18,9 +18,11 @@ SRC_CC += elf/elf_binary.cc SRC_CC += lock/lock.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc -SRC_CC += thread/thread.cc thread/thread_context.cc +SRC_CC += thread/thread.cc thread/thread_context.cc thread/trace.cc -INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock +INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/thread vpath %.cc $(REP_DIR)/src/base vpath %.cc $(BASE_DIR)/src/base diff --git a/base-okl4/lib/mk/base-common.mk b/base-okl4/lib/mk/base-common.mk index cad7a55a9..c6a9ccc65 100644 --- a/base-okl4/lib/mk/base-common.mk +++ b/base-okl4/lib/mk/base-common.mk @@ -20,9 +20,10 @@ SRC_CC += elf/elf_binary.cc SRC_CC += lock/lock.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc server/common.cc -SRC_CC += thread/thread.cc thread/thread_bootstrap.cc +SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc -INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/thread vpath cap_copy.cc $(BASE_DIR)/src/platform vpath %.cc $(REP_DIR)/src/base diff --git a/base-pistachio/lib/mk/base-common.mk b/base-pistachio/lib/mk/base-common.mk index cad7a55a9..38fe95088 100644 --- a/base-pistachio/lib/mk/base-common.mk +++ b/base-pistachio/lib/mk/base-common.mk @@ -20,9 +20,10 @@ SRC_CC += elf/elf_binary.cc SRC_CC += lock/lock.cc SRC_CC += signal/signal.cc signal/common.cc SRC_CC += server/server.cc server/common.cc -SRC_CC += thread/thread.cc thread/thread_bootstrap.cc +SRC_CC += thread/thread.cc thread/trace.cc thread/thread_bootstrap.cc -INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(REP_DIR)/src/base/lock +INC_DIR += $(BASE_DIR)/src/base/thread vpath cap_copy.cc $(BASE_DIR)/src/platform vpath %.cc $(REP_DIR)/src/base diff --git a/base/include/base/thread.h b/base/include/base/thread.h index fd510d74d..a982d3335 100644 --- a/base/include/base/thread.h +++ b/base/include/base/thread.h @@ -55,6 +55,7 @@ #include #include #include +#include #include #include /* for 'Ram_dataspace_capability' type */ #include /* for 'Thread_capability' type */ @@ -259,6 +260,17 @@ namespace Genode { */ Genode::Lock _join_lock; + private: + + Trace::Logger _trace_logger; + + /** + * Return 'Trace::Logger' instance of calling thread + * + * This function is used by the tracing framework internally. + */ + static Trace::Logger *_logger(); + public: /** @@ -355,6 +367,22 @@ namespace Genode { * undefined behaviour. */ void join(); + + /** + * Log null-terminated string as trace event + */ + static void trace(char const *); + + /** + * Log binary data as trace event + */ + static void trace(char const *, size_t len); + + /** + * Log trace event as defined in base/trace.h + */ + template + static void trace(EVENT const *event) { _logger()->log(event); } }; diff --git a/base/include/base/trace/buffer.h b/base/include/base/trace/buffer.h new file mode 100644 index 000000000..a11bbb76e --- /dev/null +++ b/base/include/base/trace/buffer.h @@ -0,0 +1,96 @@ +/* + * \brief Event tracing infrastructure + * \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 _INCLUDE__BASE__TRACE__BUFFER_H_ +#define _INCLUDE__BASE__TRACE__BUFFER_H_ + +#include +#include +#include + +namespace Genode { namespace Trace { class Buffer; } } + + +/** + * Buffer shared between CPU client thread and TRACE client + */ +class Genode::Trace::Buffer +{ + private: + + unsigned volatile _head_offset; /* in bytes, relative to 'entries' */ + unsigned volatile _size; /* in bytes */ + + struct Entry + { + size_t len; + char data[0]; + }; + + Entry _entries[0]; + + Entry *_head_entry() { return (Entry *)((addr_t)_entries + _head_offset); } + + /* + * The 'entries' member marks the beginning of the trace buffer + * entries. No other member variables must follow. + */ + + public: + + /****************************************** + ** Functions called from the CPU client ** + ******************************************/ + + void init(size_t size) + { + _head_offset = 0; + + /* compute number of bytes available for tracing data */ + size_t const header_size = (addr_t)&_entries - (addr_t)this; + + _size = size - header_size; + } + + char *reserve(size_t len) + { + if (_head_offset + sizeof(Entry) + len <= _size) + return _head_entry()->data; + + /* mark last entry with len 0 and wrap */ + _head_entry()->len = 0; + _head_offset = 0; + + return _head_entry()->data; + } + + void commit(size_t len) + { + _head_entry()->len = len; + + /* advance head offset, wrap when reaching buffer boundary */ + _head_offset += sizeof(Entry) + len; + if (_head_offset == _size) + _head_offset = 0; + } + + + /******************************************** + ** Functions called from the TRACE client ** + ********************************************/ + + addr_t entries() const { return (addr_t)_entries; } + addr_t head_offset() const { return (addr_t)_head_offset; } +}; + +#endif /* _INCLUDE__BASE__TRACE__BUFFER_H_ */ diff --git a/base/include/base/trace/events.h b/base/include/base/trace/events.h new file mode 100644 index 000000000..4d9703ad1 --- /dev/null +++ b/base/include/base/trace/events.h @@ -0,0 +1,124 @@ +/* + * \brief Trace-event definitions + * \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 _INCLUDE__BASE__TRACE__EVENTS_H_ +#define _INCLUDE__BASE__TRACE__EVENTS_H_ + +#include +#include + +namespace Genode { namespace Trace { + struct Rpc_call; + struct Rpc_returned; + struct Rpc_dispatch; + struct Rpc_reply; + struct Signal_submit; + struct Signal_received; +} } + + +struct Genode::Trace::Rpc_call +{ + char const *rpc_name; + Msgbuf_base const &msg; + + Rpc_call(char const *rpc_name, Msgbuf_base const &msg) + : rpc_name(rpc_name), msg(msg) + { + Thread_base::trace(this); + } + + size_t generate(Policy_module &policy, char *dst) const { + return policy.rpc_call(dst, rpc_name, msg); } +}; + + +struct Genode::Trace::Rpc_returned +{ + char const *rpc_name; + Msgbuf_base const &msg; + + Rpc_returned(char const *rpc_name, Msgbuf_base const &msg) + : rpc_name(rpc_name), msg(msg) + { + Thread_base::trace(this); + } + + size_t generate(Policy_module &policy, char *dst) const { + return policy.rpc_returned(dst, rpc_name, msg); } +}; + + +struct Genode::Trace::Rpc_dispatch +{ + char const *rpc_name; + Rpc_object_base const &obj; + Msgbuf_base const &msg; + + Rpc_dispatch(char const *rpc_name, Rpc_object_base const &obj, + Msgbuf_base const &msg) + : + rpc_name(rpc_name), obj(obj), msg(msg) + { + Thread_base::trace(this); + } + + size_t generate(Policy_module &policy, char *dst) const { + return policy.rpc_dispatch(dst, rpc_name, obj, msg); } +}; + + +struct Genode::Trace::Rpc_reply +{ + char const *rpc_name; + Rpc_object_base const &obj; + Msgbuf_base const &msg; + + Rpc_reply(char const *rpc_name, Rpc_object_base const &obj, + Msgbuf_base const &msg) + : + rpc_name(rpc_name), obj(obj), msg(msg) + { + Thread_base::trace(this); + } + + size_t generate(Policy_module &policy, char *dst) const { + return policy.rpc_reply(dst, rpc_name, obj, msg); } +}; + + +struct Genode::Trace::Signal_submit +{ + unsigned const num; + + Signal_submit(unsigned const num) : num(num) + { Thread_base::trace(this); } + + size_t generate(Policy_module &policy, char *dst) const { + return policy.signal_submit(dst, num); } +}; + + +struct Genode::Trace::Signal_received +{ + Signal const &signal;; + + Signal_received(Signal const &signal) : signal(signal) + { Thread_base::trace(this); } + + size_t generate(Policy_module &policy, char *dst) const { + return policy.signal_received(dst, signal); } +}; + + +#endif /* _INCLUDE__BASE__TRACE__EVENTS_H_ */ diff --git a/base/include/base/trace/logger.h b/base/include/base/trace/logger.h new file mode 100644 index 000000000..ea803c241 --- /dev/null +++ b/base/include/base/trace/logger.h @@ -0,0 +1,76 @@ +/* + * \brief Event tracing infrastructure + * \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 _INCLUDE__BASE__TRACE__LOGGER_H_ +#define _INCLUDE__BASE__TRACE__LOGGER_H_ + +#include +#include + +namespace Genode { namespace Trace { + + class Control; + class Policy_module; + class Logger; +} } + + +/** + * Facility for logging events to a thread-specific buffer + */ +struct Genode::Trace::Logger +{ + private: + + Thread_capability thread_cap; + Control *control; + bool enabled; + unsigned policy_version; + Policy_module *policy_module; + Buffer *buffer; + size_t max_event_size; + + bool pending_init; + + bool _evaluate_control(); + + public: + + Logger(); + + bool is_initialized() { return control != 0; } + + bool is_init_pending() { return pending_init; } + + void init_pending(bool val) { pending_init = val; } + + void init(Thread_capability); + + /** + * Log binary data to trace buffer + */ + void log(char const *, size_t); + + /** + * Log event to trace buffer + */ + template + void log(EVENT const *event) + { + if (!this || !_evaluate_control()) return; + + buffer->commit(event->generate(*policy_module, buffer->reserve(max_event_size))); + } +}; + +#endif /* _INCLUDE__BASE__TRACE__LOGGER_H_ */ diff --git a/base/include/base/trace/policy.h b/base/include/base/trace/policy.h new file mode 100644 index 000000000..847cc6c51 --- /dev/null +++ b/base/include/base/trace/policy.h @@ -0,0 +1,43 @@ +/* + * \brief Event tracing infrastructure + * \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 _INCLUDE__BASE__TRACE__POLICY_H_ +#define _INCLUDE__BASE__TRACE__POLICY_H_ + +#include + +namespace Genode { + + class Msgbuf_base; + class Signal; + class Rpc_object_base; + + namespace Trace { class Policy_module; } +} + + +/** + * Header of tracing policy + */ +struct Genode::Trace::Policy_module +{ + size_t (*max_event_size) (); + size_t (*rpc_call) (char *, char const *, Msgbuf_base const &); + size_t (*rpc_returned) (char *, char const *, Msgbuf_base const &); + size_t (*rpc_dispatch) (char *, char const *); + size_t (*rpc_reply) (char *, char const *); + size_t (*signal_submit) (char *, unsigned const); + size_t (*signal_received) (char *, Signal const &); +}; + +#endif /* _INCLUDE__BASE__TRACE__POLICY_H_ */ diff --git a/base/src/base/thread/trace.cc b/base/src/base/thread/trace.cc new file mode 100644 index 000000000..42ad9a623 --- /dev/null +++ b/base/src/base/thread/trace.cc @@ -0,0 +1,231 @@ +/* + * \brief Event-tracing support + * \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. + */ + +/* Genode includes */ +#include +#include +#include +#include + +/* local includes */ +#include + +using namespace Genode; + + +namespace Genode { bool inhibit_tracing = true; /* cleared by '_main' */ } + + +/** + * Return trace-control structure for specified thread + */ +static Trace::Control *trace_control(Cpu_session *cpu, Rm_session *rm, + Thread_capability thread_cap) +{ + struct Area + { + Cpu_session &cpu; + Rm_session &rm; + Dataspace_capability ds; + size_t const size; + Trace::Control * const base; + + Area(Cpu_session &cpu, Rm_session &rm) + : + cpu(cpu), rm(rm), + ds(cpu.trace_control()), + size(ds.valid() ? Dataspace_client(ds).size() : 0), + base(ds.valid() ? (Trace::Control * const)rm.attach(ds) : 0) + { } + + Trace::Control *slot(Thread_capability thread) + { + if (!thread.valid() || base == 0) + return 0; + + unsigned const index = cpu.trace_control_index(thread); + + if ((index + 1)*sizeof(Trace::Control) > size) { + PERR("thread control index is out of range"); + return 0; + } + + return base + index; + } + }; + + static Area area(*cpu, *rm); + return area.slot(thread_cap); +} + + +/******************* + ** Trace::Logger ** + *******************/ + +bool Trace::Logger::_evaluate_control() +{ + /* check process-global and thread-specific tracing condition */ + if (inhibit_tracing || !control || control->tracing_inhibited()) + return false; + + if (control->state_changed()) { + + /* suppress tracing during initialization */ + Control::Inhibit_guard guard(*control); + + if (control->to_be_disabled()) { + + /* unload policy */ + if (policy_module) { + env()->rm_session()->detach(policy_module); + policy_module = 0; + } + + /* unmap trace buffer */ + if (buffer) { + env()->rm_session()->detach(buffer); + buffer = 0; + } + + /* inhibit generation of trace events */ + enabled = false; + control->acknowledge_disabled(); + } + + else if (control->to_be_enabled()) { + + control->acknowledge_enabled(); + enabled = true; + } + } + + if (enabled && (policy_version != control->policy_version())) { + + /* suppress tracing during policy change */ + Control::Inhibit_guard guard(*control); + + /* obtain policy */ + Dataspace_capability policy_ds = env()->cpu_session()->trace_policy(thread_cap); + + if (!policy_ds.valid()) { + PWRN("could not obtain trace policy"); + control->error(); + enabled = false; + return false; + } + + try { + max_event_size = 0; + policy_module = 0; + + policy_module = env()->rm_session()->attach(policy_ds); + + /* relocate function pointers of policy callback table */ + for (unsigned i = 0; i < sizeof(Trace::Policy_module)/sizeof(void *); i++) { + ((addr_t *)policy_module)[i] += (addr_t)(policy_module); + } + + max_event_size = policy_module->max_event_size(); + + } catch (...) { } + + /* obtain buffer */ + buffer = 0; + Dataspace_capability buffer_ds = env()->cpu_session()->trace_buffer(thread_cap); + + if (!buffer_ds.valid()) { + PWRN("could not obtain trace buffer"); + control->error(); + enabled = false; + return false; + } + + try { + buffer = env()->rm_session()->attach(buffer_ds); + buffer->init(Dataspace_client(buffer_ds).size()); + } catch (...) { } + + policy_version = control->policy_version(); + } + + return enabled && policy_module; +} + + +void Trace::Logger::log(char const *msg, size_t len) +{ + if (!this || !_evaluate_control()) return; + + memcpy(buffer->reserve(len), msg, len); + buffer->commit(len); +} + + +void Trace::Logger::init(Thread_capability thread) +{ + thread_cap = thread; + + control = trace_control(env()->cpu_session(), env()->rm_session(), thread); +} + + +Trace::Logger::Logger() +: + thread_cap(thread_cap), + control(0), + enabled(false), + policy_version(0), + policy_module(0), + max_event_size(0), + pending_init(false) +{ } + + +/***************** + ** Thread_base ** + *****************/ + +/** + * return logger instance for the main thread ** + */ +static Trace::Logger *main_trace_logger() +{ + static Trace::Logger logger; + return &logger; +} + + +Trace::Logger *Thread_base::_logger() +{ + if (inhibit_tracing) + return 0; + + Thread_base * const myself = Thread_base::myself(); + + Trace::Logger * const logger = myself ? &myself->_trace_logger + : main_trace_logger(); + + /* logger is already being initialized */ + if (logger->is_init_pending()) + return logger; + + /* lazily initialize trace object */ + if (!logger->is_initialized()) { + logger->init_pending(true); + logger->init(myself ? myself->_thread_cap : env()->parent()->main_thread_cap()); + } + + return logger; +} + diff --git a/base/src/base/thread/trace/control.h b/base/src/base/thread/trace/control.h new file mode 100644 index 000000000..4ffa46cbd --- /dev/null +++ b/base/src/base/thread/trace/control.h @@ -0,0 +1,167 @@ +/* + * \brief Event tracing control interface between CPU client and CPU server + * \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 _TRACE_CONTROL_H_ +#define _TRACE_CONTROL_H_ + +namespace Genode { namespace Trace { class Control; } } + + +/** + * Structure shared between core and CPU session client + * + * The 'Trace_control' structure allows core to propagate control + * information to the threads of a process in an asynchronous way, + * for example to enable/disable tracing or setting the tracing + * policy. + */ +class Genode::Trace::Control +{ + private: + + enum State { FREE, DISABLED, ENABLED, ERROR }; + + unsigned volatile _policy_version; + + State volatile _designated_state; + State volatile _acknowledged_state; + + bool volatile _inhibit; + + public: + + /************************************************* + ** Interface used by by the CPU session client ** + *************************************************/ + + /** + * Facility to temporarily inhibit tracing + * + * This utility is used by a thread during the initialization of its + * 'Trace::Logger' to prevent recursion. During initialiation, the + * logger performs a few RPCs (e.g., to obtain the trace-control + * index). Because an RPC is a trace point, this would result in the + * re-entering the logger initialization. + */ + struct Inhibit_guard + { + Control &_control; + Inhibit_guard(Control &control) : _control(control) + { + _control._inhibit = true; + } + + ~Inhibit_guard() { _control._inhibit = false; } + }; + + /** + * Request current policy version + * + * To be compared to the version currently installed at the + * client. + */ + unsigned policy_version() const { return _policy_version; } + + /** + * Called after having updated the policy + */ + void acknowledge_policy_version(unsigned version) { _policy_version = version; } + + /** + * Detect state change + */ + bool state_changed() const { return _designated_state != _acknowledged_state; } + + /** + * Return true if CPU client thread should stop tracing + */ + bool to_be_disabled() const + { + return state_changed() && (_designated_state == DISABLED); + } + + /** + * Return true if CPU client thread should start tracing + */ + bool to_be_enabled() const + { + return state_changed() && (_designated_state == ENABLED); + } + + /** + * Confirm that the CPU client has enabled the tracing + */ + void acknowledge_enabled() { _acknowledged_state = ENABLED; }; + + /** + * Confirm that the CPU client has disabled the tracing + * + * After acknowledging that we disabled the policy, core is + * safe to free the policy dataspace. + */ + void acknowledge_disabled() { _acknowledged_state = DISABLED; }; + + /** + * State set when trace buffer or policy could not be successfully + * obtained. + */ + void error() { _acknowledged_state = ERROR; } + + /** + * Return true if the corresponding thread should suppress trace events + */ + bool tracing_inhibited() const { return _inhibit; } + + + /***************************************** + ** Accessors called by the CPU service ** + *****************************************/ + + bool is_free() const { return _designated_state == FREE; } + + void alloc() + { + _policy_version = 0; + _designated_state = DISABLED; + _acknowledged_state = DISABLED; + } + + void reset() + { + _policy_version = 0; + _designated_state = FREE; + _acknowledged_state = FREE; + } + + void trace() + { + _policy_version++; + enable(); + } + + void enable() + { + _designated_state = ENABLED; + } + + void disable() + { + _designated_state = DISABLED; + } + + bool has_error() const { return _acknowledged_state == ERROR; } + + bool is_enabled() const { return _acknowledged_state == ENABLED; } +}; + +#endif /* _TRACE_CONTROL_H_ */ diff --git a/base/src/core/main.cc b/base/src/core/main.cc index 4bb5ae7a5..ef82d1611 100644 --- a/base/src/core/main.cc +++ b/base/src/core/main.cc @@ -171,8 +171,15 @@ class Core_child : public Child_policy ** Core main ** ***************/ +namespace Genode { extern bool inhibit_tracing; } + int main() { + /** + * Disable tracing within core because it is currently not fully implemented. + */ + inhibit_tracing = true; + PDBG("--- create local services ---"); /* diff --git a/base/src/platform/_main.cc b/base/src/platform/_main.cc index 45e5f5f4f..82527ab64 100644 --- a/base/src/platform/_main.cc +++ b/base/src/platform/_main.cc @@ -220,6 +220,9 @@ int genode_argc = 1; char **genode_envp = 0; +namespace Genode { extern bool inhibit_tracing; } + + /** * C entry function called by the crt0 startup code */ @@ -227,6 +230,9 @@ extern "C" int _main() { main_thread_bootstrap(); + /* call env() explicitly to setup the environment */ + (void*)env(); + /* initialize exception handling */ init_exception_handling(); @@ -258,6 +264,9 @@ extern "C" int _main() /* create the thread context area RM session */ env_context_area_rm_session(); + /* enable tracing support */ + inhibit_tracing = false; + /* call real main function */ int ret = main(genode_argc, genode_argv, genode_envp);