genode/repos/os/src/server/loader/main.cc
Christian Prochaska 64863a4b33 loader: allow to set the parent of the subsystem's view
This commit adds a 'parent_view()' function to the loader session, which
allows to set the parent view of the subsystem's Nitpicker view.

If the function is to be used, this must get done before calling
'start()'.

Fixes #1172.
2014-06-26 10:57:24 +02:00

442 lines
11 KiB
C++

/*
* \brief Loader service
* \author Norman Feske
* \date 2012-04-17
*/
/*
* Copyright (C) 2010-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/heap.h>
#include <base/rpc_server.h>
#include <base/signal.h>
#include <base/sleep.h>
#include <loader_session/loader_session.h>
#include <cap_session/connection.h>
#include <nitpicker_view/capability.h>
#include <root/component.h>
/* local includes */
#include <child.h>
#include <nitpicker.h>
#include <ram_session_client_guard.h>
#include <rom.h>
namespace Loader {
using namespace Genode;
class Session_component : public Rpc_object<Session>
{
private:
struct Local_rom_service : Service
{
Rpc_entrypoint &_ep;
Allocator &_md_alloc;
Parent_service _parent_rom_service;
Rom_module_registry &_rom_modules;
Lock _lock;
List<Rom_session_component> _rom_sessions;
void _close(Rom_session_component *rom)
{
_ep.dissolve(rom);
_rom_sessions.remove(rom);
destroy(&_md_alloc, rom);
}
Local_rom_service(Rpc_entrypoint &ep,
Allocator &md_alloc,
Rom_module_registry &rom_modules)
:
Service("virtual_rom"),
_ep(ep),
_md_alloc(md_alloc),
_parent_rom_service(Rom_session::service_name()),
_rom_modules(rom_modules)
{ }
~Local_rom_service()
{
Lock::Guard guard(_lock);
while (_rom_sessions.first()) {
_close(_rom_sessions.first()); }
}
Genode::Session_capability session(char const *args,
Affinity const &affinity)
{
/* try to find ROM module at local ROM service */
try {
Lock::Guard guard(_lock);
char name[Session::Name::MAX_SIZE];
/* extract filename from session arguments */
Arg_string::find_arg(args, "filename")
.string(name, sizeof(name), "");
Rom_module &module = _rom_modules.lookup_and_lock(name);
Rom_session_component *rom = new (&_md_alloc)
Rom_session_component(module);
_rom_sessions.insert(rom);
return _ep.manage(rom);
} catch (...) { }
/* fall back to parent_rom_service */
return _parent_rom_service.session(args, affinity);
}
void close(Session_capability session)
{
Lock::Guard guard(_lock);
Rpc_object_base *rom = _ep.lookup_and_lock(session);
Rom_session_component *component =
dynamic_cast<Rom_session_component *>(rom);
if (component) {
_close(component);
return;
}
_parent_rom_service.close(session);
}
void upgrade(Session_capability session, const char *) { }
};
/**
* Common base class of 'Local_cpu_service' and 'Local_rm_service'
*/
struct Intercepted_parent_service : Service
{
Signal_context_capability fault_sigh;
Intercepted_parent_service(char const *name) : Service(name) { }
void close(Session_capability session)
{
env()->parent()->close(session);
}
void upgrade(Session_capability session, const char *) { }
};
/**
* Intercept CPU session requests to install default exception
* handler
*/
struct Local_cpu_service : Intercepted_parent_service
{
Local_cpu_service() : Intercepted_parent_service("CPU") { }
Genode::Session_capability session(char const *args,
Affinity const &affinity)
{
Capability<Cpu_session> cap = env()->parent()->session<Cpu_session>(args, affinity);
Cpu_session_client(cap).exception_handler(Thread_capability(), fault_sigh);
return cap;
}
};
/**
* Intercept RM session requests to install default fault handler
*/
struct Local_rm_service : Intercepted_parent_service
{
Local_rm_service() : Intercepted_parent_service("RM") { }
Genode::Session_capability session(char const *args,
Affinity const &affinity)
{
Capability<Rm_session> cap = env()->parent()->session<Rm_session>(args, affinity);
Rm_session_client(cap).fault_handler(fault_sigh);
return cap;
}
};
struct Local_nitpicker_service : Service
{
Rpc_entrypoint &ep;
Allocator &_md_alloc;
int _max_width;
int _max_height;
Nitpicker::View_capability _parent_view;
Signal_context_capability view_ready_sigh;
Nitpicker::Session_component *open_session;
Local_nitpicker_service(Rpc_entrypoint &ep,
Allocator &md_alloc)
:
Service("virtual_nitpicker"),
ep(ep),
_md_alloc(md_alloc),
_max_width(-1),
_max_height(-1),
open_session(0)
{ }
~Local_nitpicker_service()
{
if (!open_session)
return;
ep.dissolve(open_session);
destroy(&_md_alloc, open_session);
}
void constrain_geometry(int width, int height)
{
_max_width = width, _max_height = height;
}
void parent_view(Nitpicker::View_capability view)
{
_parent_view = view;
}
Genode::Session_capability session(char const *args,
Affinity const &)
{
if (open_session)
throw Unavailable();
open_session = new (&_md_alloc)
Nitpicker::Session_component(ep,
_max_width,
_max_height,
_parent_view,
view_ready_sigh,
args);
return ep.manage(open_session);
}
void upgrade(Genode::Session_capability session, const char *) { }
};
enum { STACK_SIZE = 2*4096 };
size_t _ram_quota;
Ram_session_client_guard _ram_session_client;
Heap _md_alloc;
size_t _subsystem_ram_quota_limit;
Rpc_entrypoint _ep;
Service_registry _parent_services;
Rom_module_registry _rom_modules;
Local_rom_service _rom_service;
Local_cpu_service _cpu_service;
Local_rm_service _rm_service;
Local_nitpicker_service _nitpicker_service;
Signal_context_capability _fault_sigh;
Child *_child;
/**
* Return virtual nitpicker session component
*/
Nitpicker::Session_component *_virtual_nitpicker_session()
{
if (!_nitpicker_service.open_session)
throw View_does_not_exist();
return _nitpicker_service.open_session;
}
public:
/**
* Constructor
*/
Session_component(size_t quota, Ram_session &ram, Cap_session &cap)
:
_ram_quota(quota),
_ram_session_client(env()->ram_session_cap(), _ram_quota),
_md_alloc(&_ram_session_client, env()->rm_session()),
_subsystem_ram_quota_limit(0),
_ep(&cap, STACK_SIZE, "session_ep"),
_rom_modules(_ram_session_client, _md_alloc),
_rom_service(_ep, _md_alloc, _rom_modules),
_nitpicker_service(_ep, _md_alloc),
_child(0)
{ }
~Session_component()
{
if (_child)
destroy(&_md_alloc, _child);
/*
* The parent-service registry is populated by the 'Child'
* on demand. Revert those allocations.
*/
while (Service *service = _parent_services.find_by_server(0)) {
_parent_services.remove(service);
destroy(env()->heap(), service);
}
}
/******************************
** Loader session interface **
******************************/
Dataspace_capability alloc_rom_module(Name const &name, size_t size)
{
return _rom_modules.alloc_rom_module(name.string(), size);
}
void commit_rom_module(Name const &name)
{
try {
_rom_modules.commit_rom_module(name.string()); }
catch (Rom_module_registry::Lookup_failed) {
throw Rom_module_does_not_exist(); }
}
void ram_quota(size_t quantum)
{
_subsystem_ram_quota_limit = quantum;
}
void constrain_geometry(int width, int height)
{
_nitpicker_service.constrain_geometry(width, height);
}
void parent_view(Nitpicker::View_capability view)
{
_nitpicker_service.parent_view(view);
}
void view_ready_sigh(Signal_context_capability sigh)
{
_nitpicker_service.view_ready_sigh = sigh;
}
void fault_sigh(Signal_context_capability sigh)
{
/*
* CPU exception handler for CPU sessions originating from the
* subsystem.
*/
_cpu_service.fault_sigh = sigh;
/*
* RM fault handler for RM sessions originating from the
* subsystem.
*/
_rm_service.fault_sigh = sigh;
/*
* CPU exception and RM fault handler for the immediate child.
*/
_fault_sigh = sigh;
}
void start(Name const &binary_name, Name const &label,
Genode::Native_pd_args const &pd_args)
{
if (_child) {
PWRN("cannot start subsystem twice");
return;
}
size_t const ram_quota = (_subsystem_ram_quota_limit > 0) ?
min(_subsystem_ram_quota_limit, _ram_session_client.avail()) :
_ram_session_client.avail();
try {
_child = new (&_md_alloc)
Child(binary_name.string(), label.string(),
pd_args, _ep, _ram_session_client,
ram_quota, _parent_services, _rom_service,
_cpu_service, _rm_service, _nitpicker_service,
_fault_sigh);
}
catch (Genode::Parent::Service_denied) {
throw Rom_module_does_not_exist(); }
}
Nitpicker::View_capability view()
{
return _virtual_nitpicker_session()->loader_view();
}
View_geometry view_geometry()
{
return _virtual_nitpicker_session()->loader_view_geometry();
}
};
class Root : public Root_component<Session_component>
{
private:
Ram_session &_ram;
Cap_session &_cap;
protected:
Session_component *_create_session(const char *args)
{
size_t quota =
Arg_string::find_arg(args, "ram_quota").long_value(0);
return new (md_alloc()) Session_component(quota, _ram, _cap);
}
public:
/**
* Constructor
*
* \param session_ep entry point for managing ram session objects
* \param md_alloc meta-data allocator to be used by root
* component
*/
Root(Rpc_entrypoint &session_ep, Allocator &md_alloc,
Ram_session &ram, Cap_session &cap)
:
Root_component<Session_component>(&session_ep, &md_alloc),
_ram(ram), _cap(cap)
{ }
};
}
int main()
{
using namespace Genode;
enum { STACK_SIZE = 8*1024 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "loader_ep");
static Loader::Root root(ep, *env()->heap(), *env()->ram_session(), cap);
env()->parent()->announce(ep.manage(&root));
sleep_forever();
return 0;
}