mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
base: User-level tracing support
This commit is contained in:
parent
a2b15349fd
commit
fe4a6d7d81
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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<Thread_base*>(l4_utcb_tcr()->user[UTCB_TCR_THREAD_OBJ]);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <base/exception.h>
|
||||
#include <base/lock.h>
|
||||
#include <base/native_types.h>
|
||||
#include <base/trace/logger.h>
|
||||
#include <util/list.h>
|
||||
#include <ram_session/ram_session.h> /* for 'Ram_dataspace_capability' type */
|
||||
#include <cpu_session/cpu_session.h> /* 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 <typename EVENT>
|
||||
static void trace(EVENT const *event) { _logger()->log(event); }
|
||||
};
|
||||
|
||||
|
||||
|
96
base/include/base/trace/buffer.h
Normal file
96
base/include/base/trace/buffer.h
Normal file
@ -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 <base/stdint.h>
|
||||
#include <base/thread.h>
|
||||
#include <cpu_session/cpu_session.h>
|
||||
|
||||
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_ */
|
124
base/include/base/trace/events.h
Normal file
124
base/include/base/trace/events.h
Normal file
@ -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 <base/thread.h>
|
||||
#include <base/trace/policy.h>
|
||||
|
||||
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_ */
|
76
base/include/base/trace/logger.h
Normal file
76
base/include/base/trace/logger.h
Normal file
@ -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 <base/trace/buffer.h>
|
||||
#include <cpu_session/cpu_session.h>
|
||||
|
||||
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 <typename EVENT>
|
||||
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_ */
|
43
base/include/base/trace/policy.h
Normal file
43
base/include/base/trace/policy.h
Normal file
@ -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 <base/stdint.h>
|
||||
|
||||
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_ */
|
231
base/src/base/thread/trace.cc
Normal file
231
base/src/base/thread/trace.cc
Normal file
@ -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 <base/env.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/trace/policy.h>
|
||||
#include <dataspace/client.h>
|
||||
|
||||
/* local includes */
|
||||
#include <trace/control.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
167
base/src/base/thread/trace/control.h
Normal file
167
base/src/base/thread/trace/control.h
Normal file
@ -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_ */
|
@ -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 ---");
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user