mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 02:01:38 +00:00
init: service forwarding
This patch equips init with the ability to act as a server that forwards session requests to its children. Session requests can be routed depending of the requested service type and the session label originating from init's parent. The feature is configured by one or multiple <service> nodes hosted in init's <config> node. The routing policy is selected by via the regular server-side policy-selection mechanism, for example: <config> ... <service name="LOG"> <policy label="noux"> <child name="terminal_log" label="important"/> </policy> <default-policy> <child name="nitlog"/> </default-policy> </service> ... </config> Each policy node must have a <child> sub node, which denotes name of the server with the 'name' attribute. The optional 'label' attribute defines the session label presented to the server, analogous to how the rewriting of session labels works in session routes. If not specified, the client-provided label is presented to the server as is. Fixes #2247
This commit is contained in:
parent
1489791d5e
commit
1fde4d638c
@ -743,6 +743,118 @@ append config {
|
||||
</expect_init_state>
|
||||
|
||||
|
||||
<message string="forward session request to children"/>
|
||||
|
||||
<init_config>
|
||||
<report child_ram="yes"/>
|
||||
<parent-provides>
|
||||
<service name="ROM"/> <service name="RAM"/>
|
||||
<service name="CPU"/> <service name="PD"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<start name="service_init">
|
||||
<binary name="init"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<provides> <service name="LOG"/> </provides>
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/> <service name="RAM"/>
|
||||
<service name="CPU"/> <service name="PD"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<service name="LOG">
|
||||
<default-policy> <child name="server"/> </default-policy>
|
||||
</service>
|
||||
<start name="server">
|
||||
<binary name="dummy"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="LOG"/> </provides>
|
||||
<config> <log_service verbose="yes"/> </config>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
</start>
|
||||
</config>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
</start>
|
||||
<start name="test">
|
||||
<binary name="dummy"/>
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config version="initial">
|
||||
<create_log_connections count="1" ram_upgrade="3M"/>
|
||||
<destroy_log_connections/>
|
||||
</config>
|
||||
<route>
|
||||
<service name="LOG"> <child name="service_init"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</init_config>
|
||||
<expect_log string="[init -> service_init -> server] created LOG service"/>
|
||||
<expect_log string="[init -> service_init -> server] opening session with label test"/>
|
||||
<expect_log string="[init -> service_init -> server] [test] going to create 1 LOG connections"/>
|
||||
<expect_log string="[init -> service_init -> server] opening session with label test -> 0"/>
|
||||
<expect_log string="[init -> service_init -> server] [test] upgrade connection 0"/>
|
||||
<expect_log string="[init -> service_init -> server] received session quota upgrade"/>
|
||||
<expect_log string="[init -> service_init -> server] [test] created all LOG connections"/>
|
||||
<expect_log string="[init -> service_init -> server] closing session with label test -> 0"/>
|
||||
<expect_log string="[init -> service_init -> server] [test] destroyed all LOG connections"/>
|
||||
<sleep ms="150"/>
|
||||
<!-- after closing the LOG session, the session quota is returned to
|
||||
the 'test' client -->
|
||||
<expect_init_state>
|
||||
<node name="child"> <attribute name="name" value="test"/>
|
||||
<node name="ram"> <attribute name="avail" higher="3M"/> </node>
|
||||
</node>
|
||||
</expect_init_state>
|
||||
|
||||
<!-- change init service policy such that the route of the
|
||||
remaining LOG session of 'test' is no longer valid. We
|
||||
expect the 'service_init' to issue a close request to the
|
||||
embedded server -->
|
||||
|
||||
<init_config>
|
||||
<report child_ram="yes"/>
|
||||
<parent-provides>
|
||||
<service name="ROM"/> <service name="RAM"/>
|
||||
<service name="CPU"/> <service name="PD"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<start name="service_init">
|
||||
<binary name="init"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<provides> <service name="LOG"/> </provides>
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/> <service name="RAM"/>
|
||||
<service name="CPU"/> <service name="PD"/>
|
||||
<service name="LOG"/>
|
||||
</parent-provides>
|
||||
<start name="server">
|
||||
<binary name="dummy"/>
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides> <service name="LOG"/> </provides>
|
||||
<config> <log_service verbose="yes"/> </config>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
</start>
|
||||
</config>
|
||||
<route> <any-service> <parent/> </any-service> </route>
|
||||
</start>
|
||||
<start name="test">
|
||||
<binary name="dummy"/>
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<config version="initial">
|
||||
<create_log_connections count="1" ram_upgrade="3M"/>
|
||||
<destroy_log_connections/>
|
||||
</config>
|
||||
<route>
|
||||
<service name="LOG"> <child name="service_init"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</init_config>
|
||||
<expect_log string="[init -> service_init -> server] closing session with label test"/>
|
||||
<sleep ms="100"/>
|
||||
|
||||
|
||||
<message string="test complete"/>
|
||||
|
||||
</config>
|
||||
@ -786,5 +898,5 @@ build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -nographic "
|
||||
|
||||
run_genode_until {.*child "test-init" exited with exit value 0.*} 60
|
||||
run_genode_until {.*child "test-init" exited with exit value 0.*} 120
|
||||
|
||||
|
@ -37,11 +37,27 @@ struct Dummy::Log_service
|
||||
|
||||
Heap _heap { _env.ram(), _env.rm() };
|
||||
|
||||
bool const _verbose;
|
||||
|
||||
struct Session_component : Rpc_object<Log_session>
|
||||
{
|
||||
Session_label const _label;
|
||||
|
||||
Session_component(Session_label const &label) : _label(label) { }
|
||||
bool const _verbose;
|
||||
|
||||
Session_component(Session_label const &label, bool verbose)
|
||||
:
|
||||
_label(label), _verbose(verbose)
|
||||
{
|
||||
if (_verbose)
|
||||
log("opening session with label ", _label);
|
||||
}
|
||||
|
||||
~Session_component()
|
||||
{
|
||||
if (_verbose)
|
||||
log("closing session with label ", _label);
|
||||
}
|
||||
|
||||
size_t write(String const &string) override
|
||||
{
|
||||
@ -60,17 +76,33 @@ struct Dummy::Log_service
|
||||
|
||||
struct Root : Root_component<Session_component>
|
||||
{
|
||||
Root(Entrypoint &ep, Allocator &alloc) : Root_component(ep, alloc) { }
|
||||
Ram_session &_ram;
|
||||
|
||||
bool const _verbose;
|
||||
|
||||
Root(Entrypoint &ep, Allocator &alloc, Ram_session &ram, bool verbose)
|
||||
:
|
||||
Root_component(ep, alloc), _ram(ram), _verbose(verbose)
|
||||
{ }
|
||||
|
||||
Session_component *_create_session(const char *args, Affinity const &) override
|
||||
{
|
||||
return new (md_alloc()) Session_component(label_from_args(args));
|
||||
return new (md_alloc()) Session_component(label_from_args(args), _verbose);
|
||||
}
|
||||
|
||||
void _upgrade_session(Session_component *, const char *args) override
|
||||
{
|
||||
size_t const ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota").ulong_value(0);
|
||||
|
||||
if (_ram.avail() >= ram_quota)
|
||||
log("received session quota upgrade");
|
||||
}
|
||||
};
|
||||
|
||||
Root _root { _env.ep(), _heap };
|
||||
Root _root { _env.ep(), _heap, _env.ram(), _verbose };
|
||||
|
||||
Log_service(Env &env) : _env(env)
|
||||
Log_service(Env &env, bool verbose) : _env(env), _verbose(verbose)
|
||||
{
|
||||
_env.parent().announce(_env.ep().manage(_root));
|
||||
log("created LOG service");
|
||||
@ -94,10 +126,21 @@ struct Dummy::Log_connections
|
||||
{
|
||||
unsigned const count = node.attribute_value("count", 0UL);
|
||||
|
||||
Number_of_bytes const ram_upgrade =
|
||||
node.attribute_value("ram_upgrade", Number_of_bytes());
|
||||
|
||||
log("going to create ", count, " LOG connections");
|
||||
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
new (_heap) Connection(_connections, _env, Session_label { i });
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
|
||||
Connection *connection =
|
||||
new (_heap) Connection(_connections, _env, Session_label { i });
|
||||
|
||||
if (ram_upgrade > 0) {
|
||||
log("upgrade connection ", i);
|
||||
connection->upgrade_ram(ram_upgrade);
|
||||
}
|
||||
}
|
||||
|
||||
log("created all LOG connections");
|
||||
}
|
||||
@ -212,7 +255,7 @@ struct Dummy::Main
|
||||
_log_connections.destruct();
|
||||
|
||||
if (node.type() == "log_service")
|
||||
_log_service.construct(_env);
|
||||
_log_service.construct(_env, node.attribute_value("verbose", false));
|
||||
|
||||
if (node.type() == "consume_ram")
|
||||
_ram_consumer.consume(node.attribute_value("amount", Number_of_bytes()));
|
||||
|
@ -14,6 +14,9 @@
|
||||
#ifndef _SRC__INIT__BUFFERED_XML_H_
|
||||
#define _SRC__INIT__BUFFERED_XML_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/xml_node.h>
|
||||
|
||||
namespace Init { class Buffered_xml; }
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <child.h>
|
||||
#include <alias.h>
|
||||
#include <state_reporter.h>
|
||||
#include <server.h>
|
||||
|
||||
namespace Init { struct Main; }
|
||||
|
||||
@ -109,6 +110,8 @@ struct Init::Main : State_reporter::Producer, Child::Default_route_accessor,
|
||||
Signal_handler<Main> _config_handler {
|
||||
_env.ep(), *this, &Main::_handle_config };
|
||||
|
||||
Server _server { _env, _heap, _child_services, _state_reporter };
|
||||
|
||||
Main(Env &env) : _env(env)
|
||||
{
|
||||
_config.sigh(_config_handler);
|
||||
@ -358,6 +361,8 @@ void Init::Main::_handle_config()
|
||||
*/
|
||||
_children.for_each_child([&] (Child &child) { child.apply_ram_downgrade(); });
|
||||
_children.for_each_child([&] (Child &child) { child.apply_ram_upgrade(); });
|
||||
|
||||
_server.apply_config(_config.xml());
|
||||
}
|
||||
|
||||
|
||||
|
341
repos/os/src/init/server.cc
Normal file
341
repos/os/src/init/server.cc
Normal file
@ -0,0 +1,341 @@
|
||||
/*
|
||||
* \brief Server role of init, forwarding session requests to children
|
||||
* \author Norman Feske
|
||||
* \date 2017-03-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/session_policy.h>
|
||||
|
||||
/* local includes */
|
||||
#include <server.h>
|
||||
|
||||
|
||||
/***************************
|
||||
** Init::Server::Service **
|
||||
***************************/
|
||||
|
||||
struct Init::Server::Service
|
||||
{
|
||||
Registry<Service>::Element _registry_element;
|
||||
|
||||
Buffered_xml _service_node;
|
||||
|
||||
typedef Genode::Service::Name Name;
|
||||
|
||||
Registry<Routed_service> &_child_services;
|
||||
|
||||
Name const _name { _service_node.xml().attribute_value("name", Name()) };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param alloc allocator used for buffering the 'service_node'
|
||||
*/
|
||||
Service(Registry<Service> &services,
|
||||
Allocator &alloc,
|
||||
Xml_node service_node,
|
||||
Registry<Routed_service> &child_services)
|
||||
:
|
||||
_registry_element(services, *this),
|
||||
_service_node(alloc, service_node),
|
||||
_child_services(child_services)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Determine route to child service for a given label according
|
||||
* to the <service> node policy
|
||||
*
|
||||
* \throw Parent::Service_denied
|
||||
*/
|
||||
Route resolve_session_request(Session_label const &);
|
||||
|
||||
Name name() const { return _name; }
|
||||
};
|
||||
|
||||
|
||||
Init::Server::Route
|
||||
Init::Server::Service::resolve_session_request(Session_label const &label)
|
||||
{
|
||||
try {
|
||||
Session_policy policy(label, _service_node.xml());
|
||||
|
||||
if (!policy.has_sub_node("child"))
|
||||
throw Parent::Service_denied();
|
||||
|
||||
Xml_node target_node = policy.sub_node("child");
|
||||
|
||||
Child_policy::Name const child_name =
|
||||
target_node.attribute_value("name", Child_policy::Name());
|
||||
|
||||
typedef String<Session_label::capacity()> Label;
|
||||
Label const target_label =
|
||||
target_node.attribute_value("label", Label(label.string()));
|
||||
|
||||
Routed_service *match = nullptr;
|
||||
_child_services.for_each([&] (Routed_service &service) {
|
||||
if (service.child_name() == child_name)
|
||||
match = &service; });
|
||||
|
||||
if (!match || match->abandoned())
|
||||
throw Parent::Service_denied();
|
||||
|
||||
return Route { *match, target_label };
|
||||
}
|
||||
catch (Session_policy::No_policy_defined) {
|
||||
throw Parent::Service_denied(); }
|
||||
}
|
||||
|
||||
|
||||
/******************
|
||||
** Init::Server **
|
||||
******************/
|
||||
|
||||
Init::Server::Route
|
||||
Init::Server::_resolve_session_request(Service::Name const &service_name,
|
||||
Session_label const &label)
|
||||
{
|
||||
Service *matching_service = nullptr;
|
||||
_services.for_each([&] (Service &service) {
|
||||
if (service.name() == service_name)
|
||||
matching_service = &service; });
|
||||
|
||||
if (!matching_service)
|
||||
throw Parent::Service_denied();
|
||||
|
||||
return matching_service->resolve_session_request(label);
|
||||
}
|
||||
|
||||
|
||||
static void close_session(Genode::Session_state &session)
|
||||
{
|
||||
session.phase = Genode::Session_state::CLOSE_REQUESTED;
|
||||
session.service().initiate_request(session);
|
||||
session.service().wakeup();
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::session_ready(Session_state &session)
|
||||
{
|
||||
_report_update_trigger.trigger_report_update();
|
||||
|
||||
/*
|
||||
* If 'session_ready' is called as response to a session-quota upgrade,
|
||||
* the 'phase' is set to 'CAP_HANDED_OUT' by 'Child::session_response'.
|
||||
* We just need to forward the state change to our parent.
|
||||
*/
|
||||
if (session.phase == Session_state::CAP_HANDED_OUT) {
|
||||
Parent::Server::Id id { session.id_at_client().value };
|
||||
_env.parent().session_response(id, Parent::SESSION_OK);
|
||||
}
|
||||
|
||||
if (session.phase == Session_state::AVAILABLE) {
|
||||
Parent::Server::Id id { session.id_at_client().value };
|
||||
_env.parent().deliver_session_cap(id, session.cap);
|
||||
session.phase = Session_state::CAP_HANDED_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::session_closed(Session_state &session)
|
||||
{
|
||||
_report_update_trigger.trigger_report_update();
|
||||
|
||||
Parent::Server::Id id { session.id_at_client().value };
|
||||
_env.parent().session_response(id, Parent::SESSION_CLOSED);
|
||||
|
||||
Ram_session_client(session.service().ram())
|
||||
.transfer_quota(_env.ram_session_cap(), session.donated_ram_quota());
|
||||
|
||||
session.destroy();
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_create_session_request(Xml_node request,
|
||||
Parent::Client::Id id)
|
||||
{
|
||||
if (!request.has_sub_node("args"))
|
||||
return;
|
||||
|
||||
typedef Session_state::Args Args;
|
||||
Args const args = request.sub_node("args").decoded_content<Args>();
|
||||
|
||||
Service::Name const name = request.attribute_value("service", Service::Name());
|
||||
|
||||
Session_label const label = label_from_args(args.string());
|
||||
|
||||
try {
|
||||
Route const route = _resolve_session_request(name, label);
|
||||
|
||||
/*
|
||||
* Reduce session quota by local session costs
|
||||
*/
|
||||
char argbuf[Parent::Session_args::MAX_SIZE];
|
||||
strncpy(argbuf, args.string(), sizeof(argbuf));
|
||||
|
||||
size_t const ram_quota = Arg_string::find_arg(argbuf, "ram_quota").ulong_value(0);
|
||||
size_t const keep_quota = route.service.factory().session_costs();
|
||||
|
||||
if (ram_quota < keep_quota)
|
||||
throw Genode::Service::Quota_exceeded();
|
||||
|
||||
size_t const forward_ram_quota = ram_quota - keep_quota;
|
||||
|
||||
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", forward_ram_quota);
|
||||
|
||||
Session_state &session =
|
||||
route.service.create_session(route.service.factory(),
|
||||
_client_id_space, id,
|
||||
route.label, argbuf, Affinity());
|
||||
|
||||
/* transfer session quota */
|
||||
if (_env.ram().transfer_quota(route.service.ram(), ram_quota)) {
|
||||
|
||||
/*
|
||||
* This should never happen unless our parent missed to
|
||||
* transfor the session quota to us prior issuing the session
|
||||
* request.
|
||||
*/
|
||||
warning("unable to transfer session quota (", ram_quota, " bytes) "
|
||||
"of forwarded ", name, " session");
|
||||
session.destroy();
|
||||
throw Parent::Service_denied();
|
||||
}
|
||||
|
||||
session.ready_callback = this;
|
||||
session.closed_callback = this;
|
||||
|
||||
/* initiate request */
|
||||
route.service.initiate_request(session);
|
||||
|
||||
/* if request was not handled synchronously, kick off async operation */
|
||||
if (session.phase == Session_state::CREATE_REQUESTED)
|
||||
route.service.wakeup();
|
||||
|
||||
if (session.phase == Session_state::INVALID_ARGS)
|
||||
throw Parent::Service_denied();
|
||||
|
||||
if (session.phase == Session_state::QUOTA_EXCEEDED)
|
||||
throw Genode::Service::Quota_exceeded();
|
||||
}
|
||||
catch (Parent::Service_denied) {
|
||||
_env.parent().session_response(Parent::Server::Id { id.value }, Parent::INVALID_ARGS); }
|
||||
catch (Genode::Service::Quota_exceeded) {
|
||||
_env.parent().session_response(Parent::Server::Id { id.value }, Parent::QUOTA_EXCEEDED); }
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_upgrade_session_request(Xml_node request,
|
||||
Parent::Client::Id id)
|
||||
{
|
||||
_client_id_space.apply<Session_state>(id, [&] (Session_state &session) {
|
||||
|
||||
size_t const ram_quota = request.attribute_value("ram_quota", 0UL);
|
||||
|
||||
session.phase = Session_state::UPGRADE_REQUESTED;
|
||||
|
||||
if (_env.ram().transfer_quota(session.service().ram(), ram_quota)) {
|
||||
warning("unable to upgrade session quota (", ram_quota, " bytes) "
|
||||
"of forwarded ", session.service().name(), " session");
|
||||
return;
|
||||
}
|
||||
|
||||
session.increase_donated_quota(ram_quota);
|
||||
session.service().initiate_request(session);
|
||||
session.service().wakeup();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_close_session_request(Xml_node request,
|
||||
Parent::Client::Id id)
|
||||
{
|
||||
_client_id_space.apply<Session_state>(id, [&] (Session_state &session) {
|
||||
close_session(session); });
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_session_request(Xml_node request)
|
||||
{
|
||||
if (!request.has_attribute("id"))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We use the 'Parent::Server::Id' of the incoming request as the
|
||||
* 'Parent::Client::Id' of the forwarded request.
|
||||
*/
|
||||
Parent::Client::Id const id { request.attribute_value("id", 0UL) };
|
||||
|
||||
if (request.has_type("create"))
|
||||
_handle_create_session_request(request, id);
|
||||
|
||||
if (request.has_type("upgrade"))
|
||||
_handle_upgrade_session_request(request, id);
|
||||
|
||||
if (request.has_type("close"))
|
||||
_handle_close_session_request(request, id);
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::_handle_session_requests()
|
||||
{
|
||||
_session_requests->update();
|
||||
|
||||
Xml_node const requests = _session_requests->xml();
|
||||
|
||||
requests.for_each_sub_node([&] (Xml_node request) {
|
||||
_handle_session_request(request); });
|
||||
|
||||
_report_update_trigger.trigger_report_update();
|
||||
}
|
||||
|
||||
|
||||
void Init::Server::apply_config(Xml_node config)
|
||||
{
|
||||
_services.for_each([&] (Service &service) { destroy(_alloc, &service); });
|
||||
|
||||
config.for_each_sub_node("service", [&] (Xml_node node) {
|
||||
new (_alloc) Service(_services, _alloc, node, _child_services); });
|
||||
|
||||
/*
|
||||
* Construct mechanics for responding to our parent's session requests
|
||||
* on demand.
|
||||
*/
|
||||
bool services_provided = false;
|
||||
_services.for_each([&] (Service const &) { services_provided = true; });
|
||||
|
||||
if (services_provided && !_session_requests.constructed()) {
|
||||
_session_requests.construct(_env, "session_requests");
|
||||
_session_request_handler.construct(_env.ep(), *this,
|
||||
&Server::_handle_session_requests);
|
||||
_session_requests->sigh(*_session_request_handler);
|
||||
|
||||
if (_session_requests.constructed())
|
||||
_handle_session_requests();
|
||||
}
|
||||
|
||||
/*
|
||||
* Re-validate routes of existing sessions, close sessions whose routes
|
||||
* changed.
|
||||
*/
|
||||
_client_id_space.for_each<Session_state>([&] (Session_state &session) {
|
||||
try {
|
||||
Route const route = _resolve_session_request(session.service().name(),
|
||||
session.client_label());
|
||||
|
||||
bool const route_unchanged = (route.service == session.service())
|
||||
&& (route.label == session.label());
|
||||
if (!route_unchanged)
|
||||
throw Parent::Service_denied();
|
||||
}
|
||||
catch (Parent::Service_denied) {
|
||||
close_session(session); }
|
||||
});
|
||||
}
|
112
repos/os/src/init/server.h
Normal file
112
repos/os/src/init/server.h
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* \brief Server role of init, forwarding session requests to children
|
||||
* \author Norman Feske
|
||||
* \date 2017-03-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__INIT__SERVER_H_
|
||||
#define _SRC__INIT__SERVER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/attached_rom_dataspace.h>
|
||||
|
||||
/* local includes */
|
||||
#include <types.h>
|
||||
#include <service.h>
|
||||
#include <buffered_xml.h>
|
||||
#include <state_reporter.h>
|
||||
|
||||
namespace Init { class Server; }
|
||||
|
||||
|
||||
class Init::Server : Session_state::Ready_callback,
|
||||
Session_state::Closed_callback
|
||||
{
|
||||
private:
|
||||
|
||||
struct Route
|
||||
{
|
||||
Routed_service &service;
|
||||
Session_label label;
|
||||
};
|
||||
|
||||
Env &_env;
|
||||
|
||||
Allocator &_alloc;
|
||||
|
||||
/*
|
||||
* ID space of requests originating from the parent
|
||||
*/
|
||||
Id_space<Parent::Server> _server_id_space;
|
||||
|
||||
/*
|
||||
* ID space of requests issued to the children of init
|
||||
*/
|
||||
Id_space<Parent::Client> _client_id_space;
|
||||
|
||||
/**
|
||||
* Meta data of service provided to our parent
|
||||
*/
|
||||
struct Service;
|
||||
|
||||
Registry<Service> _services;
|
||||
|
||||
/**
|
||||
* Services provided by our children
|
||||
*/
|
||||
Registry<Routed_service> &_child_services;
|
||||
|
||||
Report_update_trigger &_report_update_trigger;
|
||||
|
||||
Constructible<Attached_rom_dataspace> _session_requests;
|
||||
Constructible<Signal_handler<Server> > _session_request_handler;
|
||||
|
||||
/**
|
||||
* \throw Parent::Service_denied
|
||||
*/
|
||||
Route _resolve_session_request(Genode::Service::Name const &,
|
||||
Session_label const &);
|
||||
|
||||
void _handle_create_session_request (Xml_node, Parent::Client::Id);
|
||||
void _handle_upgrade_session_request(Xml_node, Parent::Client::Id);
|
||||
void _handle_close_session_request (Xml_node, Parent::Client::Id);
|
||||
|
||||
void _handle_session_request(Xml_node);
|
||||
void _handle_session_requests();
|
||||
|
||||
/**
|
||||
* Session_state::Closed_callback interface
|
||||
*/
|
||||
void session_closed(Session_state &) override;
|
||||
|
||||
/**
|
||||
* Session_state::Ready_callback interface
|
||||
*/
|
||||
void session_ready(Session_state &) override;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param alloc allocator used for buffering XML config data and
|
||||
* for allocating per-service meta data
|
||||
*/
|
||||
Server(Env &env, Allocator &alloc, Registry<Routed_service> &services,
|
||||
Report_update_trigger &report_update_trigger)
|
||||
:
|
||||
_env(env), _alloc(alloc), _child_services(services),
|
||||
_report_update_trigger(report_update_trigger)
|
||||
{ }
|
||||
|
||||
void apply_config(Xml_node);
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__SERVER_H_ */
|
@ -14,10 +14,15 @@
|
||||
#ifndef _SRC__INIT__SERVICE_H_
|
||||
#define _SRC__INIT__SERVICE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/service.h>
|
||||
#include <base/child.h>
|
||||
|
||||
namespace Init {
|
||||
class Abandonable;
|
||||
class Parent_service;
|
||||
class Routed_service;
|
||||
class Forwarded_service;
|
||||
}
|
||||
|
||||
|
||||
@ -68,6 +73,8 @@ class Init::Routed_service : public Child_service, public Abandonable
|
||||
|
||||
Ram_accessor &_ram_accessor;
|
||||
|
||||
Session_state::Factory &_factory;
|
||||
|
||||
Registry<Routed_service>::Element _registry_element;
|
||||
|
||||
public:
|
||||
@ -91,12 +98,21 @@ class Init::Routed_service : public Child_service, public Abandonable
|
||||
Child_service(server_id_space, factory, name,
|
||||
Ram_session_capability(), wakeup),
|
||||
_child_name(child_name), _ram_accessor(ram_accessor),
|
||||
_registry_element(services, *this)
|
||||
_factory(factory), _registry_element(services, *this)
|
||||
{ }
|
||||
|
||||
Child_name const &child_name() const { return _child_name; }
|
||||
|
||||
Ram_session_capability ram() const { return _ram_accessor.ram(); }
|
||||
|
||||
/**
|
||||
* Return factory for creating/destroying session-state objects
|
||||
*
|
||||
* This accessor is solely meant to be used by 'Forwarded_service' to
|
||||
* allocate session-state objects for sessions requested by init's
|
||||
* parent.
|
||||
*/
|
||||
Session_state::Factory &factory() { return _factory; }
|
||||
};
|
||||
|
||||
#endif /* _SRC__INIT__SERVICE_H_ */
|
||||
|
@ -14,9 +14,13 @@
|
||||
#ifndef _SRC__INIT__STATE_REPORTER_H_
|
||||
#define _SRC__INIT__STATE_REPORTER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/reporter.h>
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <report.h>
|
||||
|
||||
namespace Init { class State_reporter; }
|
||||
|
||||
class Init::State_reporter : public Report_update_trigger
|
||||
|
@ -1,4 +1,4 @@
|
||||
TARGET = init
|
||||
SRC_CC = main.cc child.cc
|
||||
SRC_CC = main.cc child.cc server.cc
|
||||
LIBS = base
|
||||
INC_DIR += $(PRG_DIR)
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define _SRC__INIT__TYPES_H_
|
||||
|
||||
#include <util/string.h>
|
||||
#include <util/list.h>
|
||||
|
||||
namespace Init {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user