genode/gems/src/server/d3m/input_service.h
Norman Feske 6d837c9e26 Attach affinity information to session requests
This patch extends the 'Parent::session()' and 'Root::session()'
functions with an additional 'affinity' parameter, which is inteded to
express the preferred affinity of the new session. For CPU sessions
provided by core, the values will be used to select the set of CPUs
assigned to the CPU session. For other services, the session affinity
information can be utilized to optimize the locality of the server
thread with the client. For example, to enable the IRQ session to route
an IRQ to the CPU core on which the corresponding device driver (the IRQ
client) is running.
2013-08-13 17:08:25 +02:00

270 lines
6.4 KiB
C++

/*
* \brief D3m input service
* \author Norman Feske
* \author Christian Helmuth
* \date 2012-01-25
*
* D3m supports merging the input events of multiple devices into one
* stream of events. Each driver corresponds to an event 'Source'. When the
* driver announces the "Input" session interface, the corresponding
* 'Source' is added to the 'Source_registry'. The d3m input serves queries
* all sources registered at the source registry for input and merges the
* streams of events.
*/
/*
* Copyright (C) 2012-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.
*/
#ifndef _INPUT_SERVICE_H_
#define _INPUT_SERVICE_H_
/* Genode includes */
#include <os/attached_ram_dataspace.h>
#include <root/component.h>
#include <util/list.h>
#include <input_session/client.h>
#include <input/event.h>
namespace Input {
class Source : public Genode::List<Source>::Element
{
public:
class Source_unavailable { };
private:
Genode::Root_capability _root;
Input::Session_capability _session;
Input::Session_client _client;
Event *_ev_buf;
Genode::size_t _ev_buf_max; /* in events */
/**
* Open input session via the specified root capability
*/
static Session_capability
_request_session(Genode::Root_capability root)
{
const char *args = "ram_quota=8K";
try {
using namespace Genode;
return static_cap_cast<Session>
(Root_client(root).session(args, Genode::Affinity()));
} catch (...) {
throw Source_unavailable();
}
}
public:
/**
* Constructor
*
* At construction time, the '_client' gets initialized using the
* default-initialized (invalid) '_session' capability. The
* 'Source::session' function is not usaable before
* re-initializing the object via the 'connect' function.
*/
Source()
: _client(_session), _ev_buf(0), _ev_buf_max(0) { }
/**
* Called when the driver announces the "Input" service
*/
void connect(Genode::Root_capability root)
{
_root = root;
_session = _request_session(_root);
_client = Session_client(_session);
/* locally map input-event buffer */
Genode::Dataspace_capability ds_cap = _client.dataspace();
_ev_buf = Genode::env()->rm_session()->attach(ds_cap);
_ev_buf_max = Genode::Dataspace_client(ds_cap).size()
/ sizeof(Event);
}
/**
* Return true is 'session()' is ready to use
*/
bool connected() const { return _session.valid(); }
/**
* Return true if input is pending
*/
bool input_pending() const { return connected() && _client.is_pending(); }
/**
* Return event buffer
*/
Event const *ev_buf() const { return _ev_buf; }
/**
* Flush input events
*/
Genode::size_t flush() { return _client.flush(); }
};
struct Source_registry
{
private:
Genode::Lock _lock;
Genode::List<Source> _sources;
public:
/**
* Register a new source of input events
*
* This function is called once for each driver, when the driver
* announced its "Input" service. By adding the new source, the
* driver's input events become visible to the d3m input session.
*/
void add_source(Source *entry)
{
Genode::Lock::Guard guard(_lock);
_sources.insert(entry);
}
bool any_source_has_pending_input()
{
Genode::Lock::Guard guard(_lock);
for (Source *e = _sources.first(); e; e = e->next())
if (e->connected() && e->input_pending())
return true;
return false;
}
/**
* Flush all input events from all available sources
*
* This function merges the input-event streams of all sources into
* one.
*
* \param dst destination event buffer
* \param dst_max capacility of event buffer, in number of events
*
* \return total number of available input events
*/
Genode::size_t flush_sources(Event *dst, Genode::size_t dst_max) const
{
Genode::size_t dst_count = 0;
for (Source *e = _sources.first(); e; e = e->next()) {
if (!e->connected() || !e->input_pending())
continue;
/*
* Copy input events from driver to client buffer
*/
Event const *src = e->ev_buf();
Genode::size_t const src_max = e->flush();
for (Genode::size_t i = 0; i < src_max; i++, dst_count++) {
if (dst_count == dst_max) {
PERR("client input-buffer overflow");
return dst_count;
}
dst[dst_count] = src[i];
}
}
return dst_count;
}
};
/*****************************
** Input service front end **
*****************************/
class Session_component : public Genode::Rpc_object<Session>
{
private:
Source_registry &_source_registry;
/*
* Input event buffer shared with the client
*/
enum { MAX_EVENTS = 1000 };
Genode::Attached_ram_dataspace _ev_ds;
public:
Session_component(Source_registry &source_registry)
:
_source_registry(source_registry),
_ev_ds(Genode::env()->ram_session(), MAX_EVENTS*sizeof(Event))
{ }
/*****************************
** Input-session interface **
*****************************/
Genode::Dataspace_capability dataspace() { return _ev_ds.cap(); }
bool is_pending() const
{
return _source_registry.any_source_has_pending_input();
}
int flush()
{
return _source_registry.flush_sources(_ev_ds.local_addr<Event>(),
MAX_EVENTS);
}
};
/**
* Shortcut for single-client root component
*/
typedef Genode::Root_component<Session_component, Genode::Single_client> Root_component;
class Root : public Root_component
{
private:
Source_registry &_source_registry;
protected:
Session_component *_create_session(const char *args)
{
try {
return new (md_alloc()) Session_component(_source_registry);
} catch (Genode::Allocator::Out_of_memory()) {
PERR("Out of memory");
throw Genode::Root::Quota_exceeded();
} catch (...) {
PERR("Exception in construction of NIC slave");
throw;
}
}
public:
Root(Genode::Rpc_entrypoint *session_ep,
Genode::Allocator *md_alloc,
Source_registry &source_registry)
:
Root_component(session_ep, md_alloc),
_source_registry(source_registry)
{ }
};
}
#endif /* _INPUT_SERVICE_H_ */