genode/repos/base/src/core/trace_session_component.cc
Norman Feske 5d678dba9e core: throw Trace::Out_of_metadata in subjects()
While importing trace sources as trace subjects into a TRACE session,
the session quota might become depleted. The TRACE session already keeps
track of the session quota via an allocator guard but the 'subjects' RPC
function missed to handle the out-of-memory condition. This patch
reflects the error condition as an 'Out_of_metadata' exception to the
TRACE client. It also contains an extension of the trace test to
exercise the corner case.
2015-06-22 14:43:39 +02:00

173 lines
3.8 KiB
C++

/*
* \brief TRACE session implementation
* \author Norman Feske
* \date 2013-08-12
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core-internal includes */
#include <trace/session_component.h>
#include <dataspace/capability.h>
#include <base/rpc_client.h>
using namespace Genode;
using namespace Genode::Trace;
Dataspace_capability Session_component::dataspace()
{
return _argument_buffer.ds;
}
size_t Session_component::subjects()
{
try {
_subjects.import_new_sources(_sources);
} catch (Allocator::Out_of_memory) {
PWRN("TRACE session ran out of memory");
throw Out_of_metadata();
}
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();
/*
* Using prefix incrementation makes sure a policy with id == 0 is
* invalid.
*/
Policy_id const id(++_policy_cnt);
if (!_md_alloc.withdraw(size))
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 */
_md_alloc.upgrade(size);
throw Out_of_metadata();
}
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.
*/
if (!_md_alloc.withdraw(required_ram))
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 */
_md_alloc.upgrade(required_ram);
throw Out_of_metadata();
}
}
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(_argument_buffer.size);
}
Session_component::~Session_component()
{
_policies.destroy_policies_owned_by(*this);
}