genode/repos/gems/src/app/launcher/subsystem_manager.h
Emery Hemingway f8337b511b Move Session_label from os to base
Session_label constructor now takes a bare string rather than a
serialized argument buffer.
Replace all instances of previous constructor with 'label_from_args'
function.

Issue #1787
2016-07-11 13:09:24 +02:00

266 lines
6.4 KiB
C++

/*
* \brief Management of subsystems
* \author Norman Feske
* \date 2014-10-02
*/
/*
* Copyright (C) 2014 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 _SUBSYSTEM_MANAGER_H_
#define _SUBSYSTEM_MANAGER_H_
/* Genode includes */
#include <os/server.h>
#include <decorator/xml_utils.h>
/* CLI-monitor includes */
#include <cli_monitor/child.h>
namespace Launcher {
class Subsystem_manager;
using Decorator::string_attribute;
}
/***************
** Utilities **
***************/
/*
* XXX copied from 'cli_monitor/main.cc'
*/
static Genode::size_t ram_preservation_from_config()
{
Genode::Number_of_bytes ram_preservation = 0;
try {
Genode::Xml_node node =
Genode::config()->xml_node().sub_node("preservation");
if (node.attribute("name").has_value("RAM"))
node.attribute("quantum").value(&ram_preservation);
} catch (...) { }
return ram_preservation;
}
class Launcher::Subsystem_manager
{
public:
/**
* Exception types
*/
class Invalid_config { };
private:
Server::Entrypoint &_ep;
Cap_session &_cap;
Dataspace_capability _ldso_ds;
struct Child : Child_base, List<Child>::Element
{
typedef String<128> Binary_name;
Child(Ram &ram,
Label const &label,
Binary_name const &binary,
Cap_session &cap_session,
size_t ram_quota,
size_t ram_limit,
Signal_context_capability yield_response_sig_cap,
Signal_context_capability exit_sig_cap,
Dataspace_capability ldso_ds)
:
Child_base(ram,
label.string(),
binary.string(),
cap_session,
ram_quota,
ram_limit,
yield_response_sig_cap,
exit_sig_cap,
ldso_ds)
{ }
};
List<Child> _children;
void _try_response_to_resource_request()
{
for (Child *child = _children.first(); child; child = child->next())
child->try_response_to_resource_request();
}
Genode::Signal_rpc_member<Subsystem_manager> _yield_broadcast_dispatcher =
{ _ep, *this, &Subsystem_manager::_handle_yield_broadcast };
void _handle_yield_broadcast(unsigned)
{
_try_response_to_resource_request();
/*
* XXX copied from 'cli_monitor/main.cc'
*/
/*
* Compute argument of yield request to be broadcasted to all
* processes.
*/
size_t amount = 0;
/* amount needed to reach preservation limit */
Ram::Status ram_status = _ram.status();
if (ram_status.avail < ram_status.preserve)
amount += ram_status.preserve - ram_status.avail;
/* sum of pending resource requests */
for (Child *child = _children.first(); child; child = child->next())
amount += child->requested_ram_quota();
for (Child *child = _children.first(); child; child = child->next())
child->yield(amount, true);
}
Genode::Signal_rpc_member<Subsystem_manager> _resource_avail_dispatcher =
{ _ep, *this, &Subsystem_manager::_handle_resource_avail };
void _handle_resource_avail(unsigned)
{
_try_response_to_resource_request();
}
Genode::Signal_rpc_member<Subsystem_manager> _yield_response_dispatcher =
{ _ep, *this, &Subsystem_manager::_handle_yield_response };
void _handle_yield_response(unsigned)
{
_try_response_to_resource_request();
}
Genode::Signal_context_capability _exited_child_sig_cap;
Ram _ram { ram_preservation_from_config(),
_yield_broadcast_dispatcher,
_resource_avail_dispatcher };
static Child::Binary_name _binary_name(Xml_node subsystem)
{
try {
return string_attribute(subsystem.sub_node("binary"),
"name", Child::Binary_name(""));
} catch (Xml_node::Nonexistent_sub_node) {
PERR("missing <binary> definition");
throw Invalid_config();
}
}
struct Ram_config { Number_of_bytes quantum, limit; };
static Ram_config _ram_config(Xml_node subsystem)
{
Number_of_bytes quantum = 0, limit = 0;
try {
subsystem.for_each_sub_node("resource", [&] (Xml_node rsc) {
if (rsc.attribute("name").has_value("RAM")) {
rsc.attribute("quantum").value(&quantum);
if (rsc.has_attribute("limit"))
rsc.attribute("limit").value(&limit);
}
});
} catch (...) {
PERR("invalid RAM resource declaration");
throw Invalid_config();
}
return Ram_config { quantum, limit };
}
public:
Subsystem_manager(Server::Entrypoint &ep, Cap_session &cap,
Genode::Signal_context_capability exited_child_sig_cap,
Dataspace_capability ldso_ds)
:
_ep(ep), _cap(cap), _ldso_ds(ldso_ds),
_exited_child_sig_cap(exited_child_sig_cap)
{ }
/**
* Start subsystem
*
* \throw Invalid_config
*/
void start(Xml_node subsystem)
{
Child::Binary_name const binary_name = _binary_name(subsystem);
Label const label = string_attribute(subsystem, "name",
Label(""));
Ram_config const ram_config = _ram_config(subsystem);
PINF("starting child '%s'", label.string());
try {
Child *child = new (env()->heap())
Child(_ram, label, binary_name.string(), _cap,
ram_config.quantum, ram_config.limit,
_yield_broadcast_dispatcher,
_exited_child_sig_cap, _ldso_ds);
/* configure child */
try {
Xml_node config_node = subsystem.sub_node("config");
child->configure(config_node.addr(), config_node.size());
} catch (...) { }
_children.insert(child);
child->start();
} catch (Rom_connection::Rom_connection_failed) {
PERR("binary \"%s\" is missing", binary_name.string());
throw Invalid_config();
}
}
void kill(char const *label)
{
for (Child *c = _children.first(); c; c = c->next()) {
if (c->label() == Label(label)) {
_children.remove(c);
destroy(env()->heap(), c);
return;
}
}
}
/**
* Call functor for each exited child
*
* The functor takes a 'Label' as argument.
*/
template <typename FUNC>
void for_each_exited_child(FUNC const &func)
{
Child *next = nullptr;
for (Child *child = _children.first(); child; child = next) {
next = child->next();
if (child->exited())
func(Label(child->label().string()));
}
}
};
#endif /* _SUBSYSTEM_MANAGER_H_ */