Adapt high-level components to new parent API

This patch adjusts the various users of the 'Child' API to the changes
on the account of the new non-blocking parent interface. It also removes
the use of the no-longer-available 'Connection::KEEP_OPEN' feature.

With the adjustment, we took the opportunity to redesign several
components to fit the non-blocking execution model much better, in
particular the demo applications.

Issue #2120
This commit is contained in:
Norman Feske
2016-11-23 17:07:49 +01:00
committed by Christian Helmuth
parent 8bafb9d41b
commit b44f0554bd
146 changed files with 3026 additions and 3484 deletions

View File

@ -26,65 +26,138 @@
#include <cap_session/connection.h>
#include <timer_session/timer_session.h>
#include <pd_session/client.h>
#include <init/child.h>
class Launchpad_child_policy : public Genode::Child_policy,
public Genode::Client
class Launchpad;
class Launchpad_child : public Genode::Child_policy,
public Genode::List<Launchpad_child>::Element,
public Genode::Child_service::Wakeup
{
public:
typedef Genode::Child_policy::Name Name;
typedef Genode::Registered<Genode::Child_service> Child_service;
typedef Genode::Registered<Genode::Parent_service> Parent_service;
typedef Genode::Registry<Child_service> Child_services;
typedef Genode::Registry<Parent_service> Parent_services;
private:
typedef Genode::String<64> Name;
Name const _name;
Genode::Server *_server;
Genode::Service_registry *_parent_services;
Genode::Service_registry *_child_services;
Genode::Dataspace_capability _config_ds;
Genode::Rpc_entrypoint *_parent_entrypoint;
Init::Child_policy_enforce_labeling _labeling_policy;
Init::Child_policy_provide_rom_file _config_policy;
Init::Child_policy_provide_rom_file _binary_policy;
Genode::Env &_env;
Genode::Ram_session_capability _ref_ram_cap;
Genode::Ram_session_client _ref_ram { _ref_ram_cap };
Genode::size_t const _ram_quota;
Parent_services &_parent_services;
Child_services &_child_services;
Genode::Dataspace_capability _config_ds;
Genode::Session_requester _session_requester;
Init::Child_policy_enforce_labeling _labeling_policy { _name.string() };
Init::Child_policy_provide_rom_file _config_policy;
Genode::Child _child;
/**
* Child_service::Wakeup callback
*/
void wakeup_child_service() override
{
_session_requester.trigger_update();
}
template <typename T>
static Genode::Service *_find_service(Genode::Registry<T> &services,
Genode::Service::Name const &name)
{
Genode::Service *service = nullptr;
services.for_each([&] (T &s) {
if (!service && (s.name() == name))
service = &s; });
return service;
}
public:
Launchpad_child_policy(const char *name,
Genode::Server *server,
Genode::Service_registry *parent_services,
Genode::Service_registry *child_services,
Genode::Dataspace_capability config_ds,
Genode::Dataspace_capability binary_ds,
Genode::Rpc_entrypoint *parent_entrypoint)
Launchpad_child(Genode::Env &env,
Genode::Session_label const &label,
Name const &elf_name,
Genode::size_t ram_quota,
Parent_services &parent_services,
Child_services &child_services,
Genode::Dataspace_capability config_ds)
:
_name(name),
_server(server),
_name(label),
_env(env), _ref_ram_cap(env.ram_session_cap()), _ram_quota(ram_quota),
_parent_services(parent_services),
_child_services(child_services),
_config_ds(config_ds),
_parent_entrypoint(parent_entrypoint),
_labeling_policy(_name.string()),
_config_policy("config", config_ds, _parent_entrypoint),
_binary_policy("binary", binary_ds, _parent_entrypoint)
_session_requester(env.ep().rpc_ep(), _env.ram(), _env.rm()),
_config_policy("config", config_ds, &_env.ep().rpc_ep()),
_child(_env.rm(), _env.ep().rpc_ep(), *this)
{ }
const char *name() const { return _name.string(); }
Genode::Service *resolve_session_request(const char *service_name,
const char *args)
~Launchpad_child()
{
Genode::Service *service;
using namespace Genode;
/* unregister services */
_child_services.for_each(
[&] (Child_service &service) {
if (service.has_id_space(_session_requester.id_space()))
Genode::destroy(_child.heap(), &service); });
}
Genode::Allocator &heap() { return _child.heap(); }
/****************************
** Child_policy interface **
****************************/
Name name() const override { return _name; }
Genode::Ram_session &ref_ram() override { return _ref_ram; }
Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
void init(Genode::Ram_session &session,
Genode::Ram_session_capability cap) override
{
session.ref_account(_ref_ram_cap);
_ref_ram.transfer_quota(cap, _ram_quota);
}
Genode::Id_space<Genode::Parent::Server> &server_id_space() override {
return _session_requester.id_space(); }
Genode::Service &resolve_session_request(Genode::Service::Name const &service_name,
Genode::Session_state::Args const &args) override
{
Genode::Service *service = nullptr;
/* check for config file request */
if ((service = _config_policy.resolve_session_request(service_name, args)))
return service;
if ((service = _config_policy
.resolve_session_request(service_name.string(), args.string())))
return *service;
/* check for binary file request */
if ((service = _binary_policy.resolve_session_request(service_name, args)))
return service;
/* check for "session_requests" ROM request */
Genode::Session_label const label(Genode::label_from_args(args.string()));
if (service_name == Genode::Rom_session::service_name()
&& label.last_element() == Genode::Session_requester::rom_name())
return _session_requester.service();
/* if service is provided by one of our children, use it */
if ((service = _child_services->find(service_name)))
return service;
if ((service = _find_service(_child_services, service_name)))
return *service;
/*
* Handle special case of the demo scenario when the user uses
@ -100,130 +173,33 @@ class Launchpad_child_policy : public Genode::Child_policy,
* interacted, however, would block at the parent interface
* until this condition gets satisfied.
*/
if (Genode::strcmp(service_name, "Input") != 0
&& Genode::strcmp(service_name, "Framebuffer") != 0
&& (service = _parent_services->find(service_name)))
return service;
if (service_name != "Input"
&& service_name != "Framebuffer"
&& ((service = _find_service(_parent_services, service_name))))
return *service;
/* wait for the service to become available */
Genode::Client client;
return _child_services->wait_for_service(service_name,
&client, name());
Genode::warning(name(), ": service ", service_name, " not available");
throw Genode::Parent::Service_denied();
}
void filter_session_args(const char *service, char *args,
Genode::size_t args_len)
void filter_session_args(Genode::Service::Name const &service,
char *args, Genode::size_t args_len) override
{
_labeling_policy.filter_session_args(service, args, args_len);
_labeling_policy.filter_session_args(service.string(), args, args_len);
}
bool announce_service(const char *service_name,
Genode::Root_capability root,
Genode::Allocator *alloc,
Genode::Server * /*server*/)
void announce_service(Genode::Service::Name const &service_name) override
{
if (_child_services->find(service_name)) {
PWRN("%s: service %s is already registered",
name(), service_name);
return false;
if (_find_service(_child_services, service_name)) {
Genode::warning(name(), ": service ", service_name, " is already registered");
return;
}
/* XXX remove potential race between checking for and inserting service */
_child_services->insert(new (alloc)
Genode::Child_service(service_name, root, _server));
Genode::printf("%s registered service %s\n", name(), service_name);
return true;
new (_child.heap())
Child_service(_child_services, _session_requester.id_space(),
_child.session_factory(), service_name,
_child.ram_session_cap(), *this);
}
void unregister_services()
{
Genode::Service *rs;
while ((rs = _child_services->find_by_server(_server)))
_child_services->remove(rs);
}
};
class Launchpad;
class Launchpad_child : public Genode::List<Launchpad_child>::Element
{
private:
static Genode::Dataspace_capability _ldso_ds();
Launchpad *_launchpad;
/*
* Entry point used for serving the parent interface and the
* locally provided ROM sessions for the 'config' and 'binary'
* files.
*/
enum { ENTRYPOINT_STACK_SIZE = 12*1024 };
Genode::Rpc_entrypoint _entrypoint;
Genode::Region_map_client _address_space;
Genode::Rom_session_client _rom;
Genode::Pd_session_client _pd;
Genode::Ram_session_client _ram;
Genode::Cpu_session_client _cpu;
Genode::Child::Initial_thread _initial_thread;
Genode::Server _server;
Launchpad_child_policy _policy;
Genode::Child _child;
public:
Launchpad_child(const char *name,
Genode::Dataspace_capability elf_ds,
Genode::Pd_session_capability pd,
Genode::Ram_session_capability ram,
Genode::Cpu_session_capability cpu,
Genode::Rom_session_capability rom,
Genode::Cap_session *cap_session,
Genode::Service_registry *parent_services,
Genode::Service_registry *child_services,
Genode::Dataspace_capability config_ds,
Launchpad *launchpad)
:
_launchpad(launchpad),
_entrypoint(cap_session, ENTRYPOINT_STACK_SIZE, name, false),
_address_space(Genode::Pd_session_client(pd).address_space()),
_rom(rom), _pd(pd), _ram(ram), _cpu(cpu),
_initial_thread(_cpu, _pd, name), _server(_ram),
_policy(name, &_server, parent_services, child_services,
config_ds, elf_ds, &_entrypoint),
_child(elf_ds, _ldso_ds(), _pd, _pd, _ram, _ram, _cpu,
_initial_thread, *Genode::env()->rm_session(),
_address_space, _entrypoint, _policy)
{
_entrypoint.activate();
}
/**
* Required to forcefully kill client which blocks on a session
* opening quest where the service is not up yet.
*/
void cancel_blocking() { _entrypoint.cancel_blocking(); }
Genode::Rom_session_capability rom_session_cap() { return _rom; }
Genode::Ram_session_capability ram_session_cap() { return _ram; }
Genode::Cpu_session_capability cpu_session_cap() { return _cpu; }
const char *name() const { return _policy.name(); }
const Genode::Server *server() const { return &_server; }
Genode::Allocator *heap() { return _child.heap(); }
void revoke_server(const Genode::Server *server) {
_child.revoke_server(server); }
};
@ -231,31 +207,31 @@ class Launchpad
{
private:
Genode::Env &_env;
Genode::Heap _heap { _env.ram(), _env.rm() };
unsigned long _initial_quota;
Genode::Service_registry _parent_services;
Genode::Service_registry _child_services;
Launchpad_child::Parent_services _parent_services;
Launchpad_child::Child_services _child_services;
Genode::Lock _children_lock;
Genode::List<Launchpad_child> _children;
bool _child_name_exists(const char *name);
void _get_unique_child_name(const char *filename, char *dst, int dst_len);
bool _child_name_exists(Launchpad_child::Name const &);
Launchpad_child::Name _get_unique_child_name(Launchpad_child::Name const &);
Genode::Sliced_heap _sliced_heap;
/* cap session for allocating capabilities for parent interfaces */
Genode::Cap_connection _cap_session;
protected:
int _ypos;
public:
Genode::Lock gui_lock;
Launchpad(unsigned long initial_quota);
Launchpad(Genode::Env &env, unsigned long initial_quota);
unsigned long initial_quota() { return _initial_quota; }
@ -273,36 +249,26 @@ class Launchpad
virtual void quota(unsigned long quota) { }
virtual void add_launcher(const char *filename,
virtual void add_launcher(Launchpad_child::Name const &binary_name,
unsigned long default_quota,
Genode::Dataspace_capability config_ds) { }
virtual void add_child(const char *unique_name,
virtual void add_child(Launchpad_child::Name const &,
unsigned long quota,
Launchpad_child *launchpad_child,
Genode::Allocator *alloc) { }
Launchpad_child &,
Genode::Allocator &) { }
virtual void remove_child(const char *name,
Genode::Allocator *alloc) { }
virtual void remove_child(Launchpad_child::Name const &,
Genode::Allocator &) { }
Launchpad_child *start_child(const char *prg_name, unsigned long quota,
Launchpad_child *start_child(Launchpad_child::Name const &binary_name,
unsigned long quota,
Genode::Dataspace_capability config_ds);
/**
* Exit child and close all its sessions
*
* \param timer Timer session to use for watchdog
* mechanism. When using the default
* value, a new timer session gets
* created during the 'exit_child'
* call.
* \param session_close_timeout_ms Timeout in milliseconds until a an
* unresponsive service->close call
* gets canceled.
*/
void exit_child(Launchpad_child *child,
Timer::Session *timer = 0,
int session_close_timeout_ms = 2000);
void exit_child(Launchpad_child &child);
};
#endif /* _INCLUDE__LAUNCHPAD__LAUNCHPAD_H_ */

View File

@ -181,7 +181,7 @@ class Scout::Element
/**
* Handle user input or timer event
*/
void handle_event(Event &ev) { if (_evh) _evh->handle(ev); }
void handle_event(Event const &ev) { if (_evh) _evh->handle_event(ev); }
/**
* Request the chapter in which the element lives

View File

@ -76,7 +76,7 @@ class Scout::Event_handler
/**
* Handle event
*/
virtual void handle(Event &e) = 0;
virtual void handle_event(Event const &e) = 0;
};
#endif /* _INCLUDE__SCOUT__EVENT_H_ */

View File

@ -17,6 +17,7 @@
#define _INCLUDE__SCOUT__PLATFORM_H_
#include <base/env.h>
#include <base/attached_dataspace.h>
#include <base/semaphore.h>
#include <timer_session/connection.h>
#include <input_session/input_session.h>
@ -51,150 +52,108 @@ class Scout::Platform
{
private:
/*****************
** Event queue **
*****************/
class Event_queue
Genode::Env &_env;
Event_handler *_event_handler = nullptr;
int _mx = 0, _my = 0;
void _handle_event(Event const &ev)
{
private:
if (_event_handler)
_event_handler->handle_event(ev);
}
static const int queue_size = 1024;
int _head;
int _tail;
Genode::Semaphore _sem;
Genode::Lock _head_lock; /* synchronize add */
/****************************
** Timer event processing **
****************************/
Event _queue[queue_size];
Timer::Connection _timer { _env };
public:
unsigned long _ticks = 0;
/**
* Constructor
*/
Event_queue(): _head(0), _tail(0)
{
Genode::memset(_queue, 0, sizeof(_queue));
}
void add(Event ev)
{
Genode::Lock::Guard lock_guard(_head_lock);
if ((_head + 1)%queue_size != _tail) {
_queue[_head] = ev;
_head = (_head + 1)%queue_size;
_sem.up();
}
}
Event get()
{
_sem.down();
Event ev = _queue[_tail];
_tail = (_tail + 1)%queue_size;
return ev;
}
int pending() const { return _head != _tail; }
} _event_queue;
/******************
** Timer thread **
******************/
class Timer_thread : public Genode::Thread_deprecated<4096>
void _handle_timer()
{
private:
_ticks = _timer.elapsed_ms();
Timer::Connection _timer;
Input::Session &_input;
Input::Event *_ev_buf = { Genode::env()->rm_session()->attach(_input.dataspace()) };
Event_queue &_event_queue;
int _mx, _my;
unsigned long _ticks = { 0 };
Event ev;
ev.assign(Event::TIMER, _mx, _my, 0);
void _import_events()
{
if (_input.pending() == false) return;
_handle_event(ev);
}
for (int i = 0, num = _input.flush(); i < num; i++)
{
Event ev;
Input::Event e = _ev_buf[i];
Genode::Signal_handler<Platform> _timer_handler {
_env.ep(), *this, &Platform::_handle_timer };
if (e.type() == Input::Event::RELEASE
|| e.type() == Input::Event::PRESS) {
_mx = e.ax();
_my = e.ay();
ev.assign(e.type() == Input::Event::PRESS ? Event::PRESS : Event::RELEASE,
e.ax(), e.ay(), e.code());
_event_queue.add(ev);
}
if (e.type() == Input::Event::MOTION) {
_mx = e.ax();
_my = e.ay();
ev.assign(Event::MOTION, e.ax(), e.ay(), e.code());
_event_queue.add(ev);
}
}
/****************************
** Input event processing **
****************************/
Input::Session &_input;
Genode::Attached_dataspace _input_ds { _env.rm(), _input.dataspace() };
Input::Event * const _ev_buf = _input_ds.local_addr<Input::Event>();
bool _event_pending = 0;
void _handle_input()
{
if (_input.pending() == false) return;
for (int i = 0, num = _input.flush(); i < num; i++)
{
Event ev;
Input::Event e = _ev_buf[i];
_event_pending = i + 1 < num;
if (e.type() == Input::Event::RELEASE
|| e.type() == Input::Event::PRESS) {
_mx = e.ax();
_my = e.ay();
ev.assign(e.type() == Input::Event::PRESS ? Event::PRESS : Event::RELEASE,
e.ax(), e.ay(), e.code());
_handle_event(ev);
}
public:
/**
* Constructor
*
* Start thread immediately on construction.
*/
Timer_thread(Input::Session &input, Event_queue &event_queue)
: Thread_deprecated("timer"), _input(input), _event_queue(event_queue)
{ start(); }
void entry()
{
while (1) {
Event ev;
ev.assign(Event::TIMER, _mx, _my, 0);
_event_queue.add(ev);
_import_events();
_timer.msleep(10);
_ticks += 10;
}
if (e.type() == Input::Event::MOTION) {
_mx = e.ax();
_my = e.ay();
ev.assign(Event::MOTION, e.ax(), e.ay(), e.code());
_handle_event(ev);
}
}
}
unsigned long ticks() const { return _ticks; }
} _timer_thread;
Genode::Signal_handler<Platform> _input_handler {
_env.ep(), *this, &Platform::_handle_input};
public:
Platform(Input::Session &input) : _timer_thread(input, _event_queue) { }
Platform(Genode::Env &env, Input::Session &input)
: _env(env), _input(input) { }
/**
* Get timer ticks in miilliseconds
*/
unsigned long timer_ticks() const { return _timer_thread.ticks(); }
unsigned long timer_ticks() const { return _ticks; }
/**
* Return true if an event is pending
* Register event handler
*/
bool event_pending() const { return _event_queue.pending(); }
void event_handler(Event_handler &handler)
{
_event_handler = &handler;
/**
* Request event
*
* \param e destination where to store event information.
*
* If there is no event pending, this function blocks
* until there is an event to deliver.
*/
Event get_event() { return _event_queue.get(); }
_timer.sigh(_timer_handler);
_timer.trigger_periodic(40*1000);
_input.sigh(_input_handler);
}
bool event_pending() const { return _event_pending; }
};
#endif /* _INCLUDE__SCOUT__PLATFORM_H_ */

View File

@ -78,7 +78,7 @@ class Scout::User_state : public Parent_element
/**
* Apply input event to mouse focus state
*/
void handle_event(Event &ev)
void handle_event(Event const &ev)
{
_key_cnt += ev.type == Event::PRESS ? 1 : 0;
_key_cnt -= ev.type == Event::RELEASE ? 1 : 0;

View File

@ -34,21 +34,34 @@ class Scout::Window : public Parent_element
Graphics_backend &_gfx_backend;
Rect _dirty;
Area _max_size;
Point _view_position;
int _request_cnt; /* nb of requests since last process */
bool const _scout_quirk; /* enable redraw quirk for scout */
/*
* We limit the rate of (expensive) view-position updates to the rate
* of 'process_redraw' calls instead of eagerly responding to
* individual input events (which trigger calls of 'vpos').
*/
Point _view_position, _next_view_position = _view_position;
void _update_view_position()
{
if (_view_position == _next_view_position) return;
_view_position = _next_view_position;
_gfx_backend.position(_view_position);
}
public:
Window(Graphics_backend &gfx_backend, Point position, Area size,
Area max_size, bool scout_quirk)
:
_gfx_backend(gfx_backend), _max_size(max_size), _request_cnt(0),
_scout_quirk(scout_quirk)
_scout_quirk(scout_quirk), _view_position(position)
{
/* init element attributes */
_view_position = position;
_size = size;
_size = size;
}
virtual ~Window() { }
@ -56,8 +69,8 @@ class Scout::Window : public Parent_element
/**
* Return current window position
*/
int view_x() const { return _view_position.x(); }
int view_y() const { return _view_position.y(); }
int view_x() const { return _next_view_position.x(); }
int view_y() const { return _next_view_position.y(); }
int view_w() const { return _size.w(); }
int view_h() const { return _size.h(); }
@ -71,11 +84,7 @@ class Scout::Window : public Parent_element
/**
* Move window to new position
*/
virtual void vpos(int x, int y)
{
_view_position = Point(x, y);
_gfx_backend.position(_view_position);
}
virtual void vpos(int x, int y) { _next_view_position = Point(x, y); }
/**
* Define vertical scroll offset
@ -133,6 +142,8 @@ class Scout::Window : public Parent_element
*/
void process_redraw()
{
_update_view_position();
if (_request_cnt == 0) return;
/* get actual drawing area (clipped against canvas dimensions) */
@ -198,7 +209,7 @@ class Scout::Drag_event_handler : public Event_handler
/**
* Event handler interface
*/
void handle(Event &ev)
void handle_event(Event const &ev) override
{
if (ev.type == Event::PRESS) _key_cnt++;
if (ev.type == Event::RELEASE) _key_cnt--;