os: make internal report_rom classes reusable

This patch moves the formerly internal classes of the report-ROM service
to the public location os/include/report_rom/ so that they can be reused
by other components such as the upcoming clipboard.
This commit is contained in:
Norman Feske 2015-09-23 11:06:25 +02:00 committed by Christian Helmuth
parent 702646a4a3
commit 02d07655ce
10 changed files with 639 additions and 447 deletions

View File

@ -11,17 +11,15 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _REPORT_SERVICE_H_
#define _REPORT_SERVICE_H_
#ifndef _INCLUDE__REPORT_ROM__REPORT_SERVICE_H_
#define _INCLUDE__REPORT_ROM__REPORT_SERVICE_H_
/* Genode includes */
#include <util/arg_string.h>
#include <report_session/report_session.h>
#include <root/component.h>
#include <os/print_lines.h>
/* local includes */
#include <rom_registry.h>
#include <util/print_lines.h>
#include <report_rom/rom_registry.h>
namespace Report {
@ -36,6 +34,8 @@ struct Report::Session_component : Genode::Rpc_object<Session>, Rom::Writer
Rom::Registry_for_writer &_registry;
Genode::Session_label const _label;
Genode::Attached_ram_dataspace _ds;
Rom::Module &_module;
@ -59,26 +59,25 @@ struct Report::Session_component : Genode::Rpc_object<Session>, Rom::Writer
public:
Session_component(Rom::Module::Name const &name, size_t buffer_size,
Session_component(Genode::Session_label const &label, size_t buffer_size,
Rom::Registry_for_writer &registry, bool &verbose)
:
_registry(registry),
_registry(registry), _label(label),
_ds(Genode::env()->ram_session(), buffer_size),
_module(_create_module(name)),
_module(_create_module(label.string())),
_verbose(verbose)
{ }
/**
* Destructor
*
* Clear report when the report session gets closes.
*/
~Session_component()
{
_module.write_content(0, 0);
_registry.release(*this, _module);
}
/**
* Rom::Writer interface
*/
Genode::Session_label label() const override { return _label; }
Dataspace_capability dataspace() override { return _ds.cap(); }
void submit(size_t length) override
@ -90,7 +89,7 @@ struct Report::Session_component : Genode::Rpc_object<Session>, Rom::Writer
_log_lines(_ds.local_addr<char>(), length);
}
_module.write_content(_ds.local_addr<char>(), length);
_module.write_content(*this, _ds.local_addr<char>(), length);
}
void response_sigh(Genode::Signal_context_capability) override { }
@ -112,16 +111,12 @@ struct Report::Root : Genode::Root_component<Session_component>
{
using namespace Genode;
/* read label from session arguments */
char label[200];
Arg_string::find_arg(args, "label").string(label, sizeof(label), "");
/* read report buffer size from session arguments */
size_t const buffer_size =
Arg_string::find_arg(args, "buffer_size").ulong_value(0);
return new (md_alloc())
Session_component(Rom::Module::Name(label), buffer_size,
Session_component(Genode::Session_label(args), buffer_size,
_rom_registry, _verbose);
}
@ -137,4 +132,4 @@ struct Report::Root : Genode::Root_component<Session_component>
{ }
};
#endif /* _REPORT_SERVICE_H_ */
#endif /* _INCLUDE__REPORT_ROM__REPORT_SERVICE_H_ */

View File

@ -0,0 +1,285 @@
/*
* \brief ROM module written by report service, read by ROM service
* \author Norman Feske
* \date 2014-01-11
*/
/*
* 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 _INCLUDE__REPORT_ROM__ROM_MODULE_H_
#define _INCLUDE__REPORT_ROM__ROM_MODULE_H_
/* Genode includes */
#include <util/volatile_object.h>
#include <os/attached_ram_dataspace.h>
#include <os/session_policy.h>
namespace Rom {
using Genode::size_t;
using Genode::Lazy_volatile_object;
using Genode::Attached_ram_dataspace;
class Module;
class Readable_module;
class Registry;
class Writer;
class Reader;
class Buffer;
typedef Genode::List<Module> Module_list;
typedef Genode::List<Reader> Reader_list;
typedef Genode::List<Writer> Writer_list;
}
struct Rom::Writer : Writer_list::Element
{
virtual Genode::Session_label label() const = 0;
};
struct Rom::Reader : Reader_list::Element
{
virtual void notify_module_changed() = 0;
virtual void notify_module_invalidated() = 0;
};
struct Rom::Readable_module
{
/**
* Exception type
*/
class Buffer_too_small { };
/**
* Read content of ROM module
*
* Called by ROM service when a dataspace is obtained by the client.
*
* \throw Buffer_too_small
*/
virtual size_t read_content(Reader const &reader, char *dst,
size_t dst_len) const = 0;
virtual size_t size() const = 0;
};
/**
* A Rom::Module gets created as soon as either a ROM client or a Report client
* refers to it.
*
* XXX We never know which of both types of client is actually connected. How
* should pay for it? There are two choices: The backing store could be paid
* by the server, thereby exposing the server to possibe resource exhaustion
* triggered by a malicious client. Alternatively, we could make all clients of
* either kind of service pay that refer to the Rom::Module. In the worst case,
* however, if there are many client for a single report, the paid-for RAM
* quota will never be used. For now, we simply allocate the backing store from
* the server's quota.
*
* The Rom::Module gets destroyed when no client refers to it anymore.
*/
struct Rom::Module : Module_list::Element, Readable_module
{
public:
typedef Genode::String<200> Name;
struct Read_policy
{
/**
* Return true if the reader is allowed to read the module content
*/
virtual bool read_permitted(Module const &,
Writer const &, Reader const &) const = 0;
};
struct Write_policy
{
/**
* Return true of the writer is permitted to write content
*
* This policy hook can be used to implement dynamic policies
* as employed by the clipboard, which blocks reports from
* unfocused clients.
*/
virtual bool write_permitted(Module const &, Writer const &) const = 0;
};
private:
Name _name;
Read_policy const &_read_policy;
Write_policy const &_write_policy;
Reader_list mutable _readers;
Writer_list mutable _writers;
/**
* Origin of the content currently stored in the module
*/
Writer const *_last_writer = nullptr;
/**
* Dataspace used as backing store
*
* The buffer for the content is not allocated from the heap to
* allow for the immediate release of the underlying backing store when
* the module gets destructed.
*/
Lazy_volatile_object<Attached_ram_dataspace> _ds;
/**
* Content size, which may less than the capacilty of '_ds'.
*/
size_t _size = 0;
/********************************
** Interface used by registry **
********************************/
friend class Registry;
/**
* Constructor
*
* \param name module name
* \param read_policy policy hook function that is evaluated each
* time when the module content is obtained
* \param write_policy policy hook function that is evaluated each
* time when the module content is changed
*/
Module(Name const &name,
Read_policy const &read_policy,
Write_policy const &write_policy)
:
_name(name), _read_policy(read_policy), _write_policy(write_policy)
{ }
/*************************************************
** Interface to be used by the 'Registry' only **
*************************************************/
bool _reader_is_registered(Reader const &reader) const
{
for (Reader const *r = _readers.first(); r; r = r->next())
if (r == &reader)
return true;
return false;
}
void _register(Reader &reader) { _readers.insert(&reader); }
void _unregister(Reader &reader) { _readers.remove(&reader); }
void _register(Writer &writer)
{
_writers.insert(&writer);
}
void _unregister(Writer const &writer)
{
_writers.remove(&writer);
/* clear content if its origin disappears */
if (_last_writer == &writer) {
Genode::memset(_ds->local_addr<char>(), 0, _size);
_size = 0;
_last_writer = nullptr;
}
}
bool _has_name(Name const &name) const { return name == _name; }
bool _is_in_use() const
{
return _readers.first() || _writers.first();
}
unsigned _num_writers() const
{
unsigned cnt = 0;
for (Writer const *w = _writers.first(); w; w = w->next())
cnt++;
return cnt;
}
public:
/**
* Assign new content to the ROM module
*
* Called by report service when a new report comes in.
*/
void write_content(Writer const &writer, char const * const src, size_t const src_len)
{
if (!_write_policy.write_permitted(*this, writer))
return;
_size = 0;
_last_writer = &writer;
/*
* Realloc backing store if needed
*
* Take a terminating zero into account, which we append to each
* report. This way, we do not need to trust report clients to
* append a zero termination to textual reports.
*/
if (!_ds.is_constructed() || _ds->size() < (src_len + 1))
_ds.construct(Genode::env()->ram_session(), (src_len + 1));
/* copy content into backing store */
_size = src_len;
Genode::memcpy(_ds->local_addr<char>(), src, _size);
/* append zero termination */
_ds->local_addr<char>()[src_len] = 0;
/* notify ROM clients that access the module */
for (Reader *r = _readers.first(); r; r = r->next()) {
if (_read_policy.read_permitted(*this, *_last_writer, *r))
r->notify_module_changed();
else
r->notify_module_invalidated();
}
}
/**
* Readable_module interface
*/
size_t read_content(Reader const &reader, char *dst, size_t dst_len) const override
{
if (!_ds.is_constructed() || !_last_writer)
return 0;
if (!_read_policy.read_permitted(*this, *_last_writer, reader))
return 0;
if (dst_len < _size)
throw Buffer_too_small();
Genode::memcpy(dst, _ds->local_addr<char>(), _size);
return _size;
}
virtual size_t size() const override { return _size; }
Name name() const { return _name; }
};
#endif /* _INCLUDE__REPORT_ROM__ROM_MODULE_H_ */

View File

@ -0,0 +1,51 @@
/*
* \brief Interfaces for the registry of ROM modules
* \author Norman Feske
* \date 2014-01-11
*/
/*
* 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 _INCLUDE__REPORT_ROM__ROM_REGISTRY_H_
#define _INCLUDE__REPORT_ROM__ROM_REGISTRY_H_
#include <report_rom/rom_module.h>
namespace Rom {
struct Registry_for_reader;
struct Registry_for_writer;
}
struct Rom::Registry_for_reader
{
/**
* Exception type
*/
class Lookup_failed { };
/**
* Lookup ROM module for given ROM session label
*
* \throw Lookup_failed
*/
virtual Readable_module &lookup(Reader &reader,
Module::Name const &rom_label) = 0;
virtual void release(Reader &reader, Readable_module &module) = 0;
};
struct Rom::Registry_for_writer
{
virtual Module &lookup(Writer &writer, Module::Name const &name) = 0;
virtual void release(Writer &writer, Module &module) = 0;
};
#endif /* _INCLUDE__REPORT_ROM__ROM_REGISTRY_H_ */

View File

@ -0,0 +1,180 @@
/*
* \brief ROM service
* \author Norman Feske
* \date 2014-01-11
*/
/*
* 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 _INCLUDE__REPORT_ROM__ROM_SERVICE_H_
#define _INCLUDE__REPORT_ROM__ROM_SERVICE_H_
/* Genode includes */
#include <util/arg_string.h>
#include <util/xml_node.h>
#include <rom_session/rom_session.h>
#include <root/component.h>
#include <report_rom/rom_registry.h>
#include <os/session_policy.h>
namespace Rom {
class Session_component;
class Module_name_fn;
class Root;
using Genode::Xml_node;
}
class Rom::Session_component : public Genode::Rpc_object<Genode::Rom_session>,
public Reader
{
private:
Registry_for_reader &_registry;
Genode::Session_label const _label;
Readable_module &_module;
Readable_module &_init_module(Genode::Session_label const &label)
{
try {
return _registry.lookup(*this, label.string()); }
catch (Registry_for_reader::Lookup_failed) {
throw Genode::Root::Invalid_args(); }
}
Lazy_volatile_object<Genode::Attached_ram_dataspace> _ds;
size_t _content_size = 0;
/**
* Keep state of valid content to notify the client only once when
* the ROM module becomes invalid.
*/
bool _valid = false;
Genode::Signal_context_capability _sigh;
void _notify_client()
{
if (_sigh.valid())
Genode::Signal_transmitter(_sigh).submit();
}
public:
Session_component(Registry_for_reader &registry,
Genode::Session_label const &label)
:
_registry(registry), _label(label), _module(_init_module(label))
{ }
~Session_component()
{
_registry.release(*this, _module);
}
Genode::Session_label label() const { return _label; }
Genode::Rom_dataspace_capability dataspace() override
{
using namespace Genode;
/* replace dataspace by new one */
/* XXX we could keep the old dataspace if the size fits */
_ds.construct(env()->ram_session(), _module.size());
/* fill dataspace content with report contained in module */
_content_size =
_module.read_content(*this, _ds->local_addr<char>(), _ds->size());
_valid = _content_size > 0;
/* cast RAM into ROM dataspace capability */
Dataspace_capability ds_cap = static_cap_cast<Dataspace>(_ds->cap());
return static_cap_cast<Rom_dataspace>(ds_cap);
}
bool update() override
{
if (!_ds.is_constructed() || _module.size() > _ds->size())
return false;
size_t const new_content_size =
_module.read_content(*this, _ds->local_addr<char>(), _ds->size());
/* clear difference between old and new content */
if (new_content_size < _content_size)
Genode::memset(_ds->local_addr<char>() + new_content_size, 0,
_content_size - new_content_size);
_content_size = new_content_size;
_valid = _content_size > 0;
return true;
}
void sigh(Genode::Signal_context_capability sigh) override
{
_sigh = sigh;
}
/**
* Reader interface
*/
void notify_module_changed() override
{
_notify_client();
}
/**
* Reader interface
*/
void notify_module_invalidated() override
{
/* deliver a signal for an invalidated module only once */
if (!_valid)
return;
_valid = false;
_notify_client();
}
};
class Rom::Root : public Genode::Root_component<Session_component>
{
private:
Registry_for_reader &_registry;
protected:
Session_component *_create_session(const char *args) override
{
using namespace Genode;
return new (md_alloc())
Session_component(_registry, Session_label(args));
}
public:
Root(Server::Entrypoint &ep,
Genode::Allocator &md_alloc,
Registry_for_reader &registry)
:
Genode::Root_component<Session_component>(&ep.rpc_ep(), &md_alloc),
_registry(registry)
{ }
};
#endif /* _INCLUDE__REPORT_ROM__ROM_SERVICE_H_ */

View File

@ -69,7 +69,6 @@ compare_output_to {
[init -> test-report_rom] -> <brightness brightness="77"/>
[init -> test-report_rom]
[init -> test-report_rom] Reporter: close report session
[init -> test-report_rom] ROM client: wait for update notification
[init -> test-report_rom] ROM client: ROM is available despite report was closed - OK
[init -> test-report_rom] Reporter: start reporting (while the ROM client still listens)
[init -> test-report_rom] ROM client: wait for update notification

View File

@ -16,10 +16,11 @@
#include <base/env.h>
#include <os/server.h>
#include <os/config.h>
#include <report_rom/rom_service.h>
#include <report_rom/report_service.h>
/* local includes */
#include <rom_service.h>
#include <report_service.h>
#include "rom_registry.h"
namespace Server {
@ -36,9 +37,7 @@ struct Server::Main
Genode::Sliced_heap sliced_heap = { env()->ram_session(),
env()->rm_session() };
Rom::Registry rom_registry = { sliced_heap };
Xml_node _rom_config_node()
Xml_node _rom_config_node() const
{
try {
return Genode::config()->xml_node().sub_node("rom"); }
@ -48,7 +47,7 @@ struct Server::Main
}
}
Xml_node rom_config = _rom_config_node();
Rom::Registry rom_registry = { sliced_heap, _rom_config_node() };
bool _verbose_config()
{
@ -60,7 +59,7 @@ struct Server::Main
bool verbose = _verbose_config();
Report::Root report_root = { ep, sliced_heap, rom_registry, verbose };
Rom ::Root rom_root = { ep, sliced_heap, rom_registry, rom_config};
Rom ::Root rom_root = { ep, sliced_heap, rom_registry };
Main(Entrypoint &ep) : ep(ep)
{

View File

@ -1,208 +0,0 @@
/*
* \brief ROM module written by report service, read by ROM service
* \author Norman Feske
* \date 2014-01-11
*/
/*
* 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 _ROM_MODULE_
#define _ROM_MODULE_
/* Genode includes */
#include <util/volatile_object.h>
#include <os/attached_ram_dataspace.h>
namespace Rom {
using Genode::size_t;
using Genode::Lazy_volatile_object;
using Genode::Attached_ram_dataspace;
class Module;
class Registry;
class Writer;
class Reader;
class Buffer;
typedef Genode::List<Module> Module_list;
typedef Genode::List<Reader> Reader_list;
}
struct Rom::Writer { };
struct Rom::Reader : Reader_list::Element
{
virtual void notify_module_changed() const = 0;
};
/**
* A Rom::Module gets created as soon as either a ROM client or a Report client
* refers to it.
*
* XXX We never know which of both types of client is actually connected. How
* should pay for it? There are two choices: The backing store could be payed
* by the server, thereby exposing the server to possibe resource exhaustion
* triggered by a malicious client. Alternatively, we could make all clients of
* either kind of service pay that refer to the Rom::Module. In the worst case,
* however, if there are many client for a single report, the paid-for RAM
* quota will never be used. For now, we simply allocate the backing store from
* the server's quota.
*
* The Rom::Module gets destroyed no client refers to it anymore.
*/
struct Rom::Module : Module_list::Element
{
public:
typedef Genode::String<200> Name;
private:
Name _name;
/**
* The ROM module may be read by any number of ROM clients
*/
Reader_list mutable _readers;
/**
* There must be only one or no writer
*/
Writer const mutable * _writer = 0;
/**
* Dataspace used as backing store
*
* The buffer for the content is not allocated from the heap to
* allow for the immediate release of the underlying backing store when
* the module gets destructed.
*/
Lazy_volatile_object<Attached_ram_dataspace> _ds;
/**
* Content size, which may less than the capacilty of '_ds'.
*/
size_t _size = 0;
void _notify_readers() const
{
for (Reader const *r = _readers.first(); r; r = r->next())
r->notify_module_changed();
}
/********************************
** Interface used by registry **
********************************/
friend class Registry;
/**
* Constructor
*/
Module(Name const &name) : _name(name) { }
bool _reader_is_registered(Reader const &reader) const
{
for (Reader const *r = _readers.first(); r; r = r->next())
if (r == &reader)
return true;
return false;
}
void _register(Reader const &reader) const { _readers.insert(&reader); }
void _unregister(Reader const &reader) const { _readers.remove(&reader); }
void _register(Writer const &writer) const
{
class Unexpected_multiple_writers { };
if (_writer)
throw Unexpected_multiple_writers();
_writer = &writer;
}
void _unregister(Writer const &writer) const
{
class Unexpected_unknown_writer { };
if (_writer != &writer)
throw Unexpected_unknown_writer();
_writer = 0;
}
bool _has_name(Name const &name) const { return name == _name; }
bool _is_in_use() const { return _readers.first() || _writer; }
public:
/**
* Assign new content to the ROM module
*
* Called by report service when a new report comes in.
*/
void write_content(char const * const src, size_t const src_len)
{
_size = 0;
/*
* Realloc backing store if needed
*
* Take a terminating zero into account, which we append to each
* report. This way, we do not need to trust report clients to
* append a zero termination to textual reports.
*/
if (!_ds.is_constructed() || _ds->size() < (src_len + 1))
_ds.construct(Genode::env()->ram_session(), (src_len + 1));
/* copy content into backing store */
_size = src_len;
Genode::memcpy(_ds->local_addr<char>(), src, _size);
/* append zero termination */
_ds->local_addr<char>()[src_len] = 0;
/* notify ROM clients that access the module */
for (Reader const *r = _readers.first(); r; r = r->next())
r->notify_module_changed();
}
/**
* Exception type
*/
class Buffer_too_small { };
/**
* Read content of ROM module
*
* Called by ROM service when a dataspace is obtained by the client.
*/
size_t read_content(char *dst, size_t dst_len) const
{
if (!_ds.is_constructed())
return 0;
if (dst_len < _size)
throw Buffer_too_small();
Genode::memcpy(dst, _ds->local_addr<char>(), _size);
return _size;
}
size_t size() const { return _size; }
Name name() const { return _name; }
};
#endif /* _ROM_MODULE_ */

View File

@ -14,29 +14,10 @@
#ifndef _ROM_REGISTRY_H_
#define _ROM_REGISTRY_H_
/* local includes */
#include <rom_module.h>
/* Genode includes */
#include <report_rom/rom_registry.h>
namespace Rom {
struct Registry_for_reader;
struct Registry_for_writer;
}
struct Rom::Registry_for_reader
{
virtual Module const &lookup(Reader const &reader, Module::Name const &name) = 0;
virtual void release(Reader const &reader, Module const &module) = 0;
};
struct Rom::Registry_for_writer
{
virtual Module &lookup(Writer const &writer, Module::Name const &name) = 0;
virtual void release(Writer const &writer, Module const &module) = 0;
};
namespace Rom { struct Registry; }
struct Rom::Registry : Registry_for_reader, Registry_for_writer, Genode::Noncopyable
@ -45,8 +26,38 @@ struct Rom::Registry : Registry_for_reader, Registry_for_writer, Genode::Noncopy
Genode::Allocator &_md_alloc;
Xml_node _config;
Module_list _modules;
struct Read_write_policy : Module::Read_policy, Module::Write_policy
{
bool read_permitted(Module const &,
Writer const &,
Reader const &) const override
{
/*
* The access-control policy is applied at the ROM-session
* construction time by applying the '_report_name' method
* on the session label. Once connected to a ROM module,
* the ROM client is always allowed to read the ROM content.
*/
return true;
}
bool write_permitted(Module const &, Writer const &) const override
{
/*
* Because the report-session label is used as the module name
* for the writer, each report session refers to a distinct
* module. Report client can write to their respective modules
* at any time.
*/
return true;
}
} _read_write_policy;
Module &_lookup(Module::Name const name)
{
for (Module *m = _modules.first(); m; m = m->next())
@ -57,10 +68,12 @@ struct Rom::Registry : Registry_for_reader, Registry_for_writer, Genode::Noncopy
/* XXX proper accounting for the used memory is missing */
/* XXX if we run out of memory, the server will abort */
Module * const module = new (&_md_alloc) Module(name);
Module * const module = new (&_md_alloc)
Module(name, _read_write_policy, _read_write_policy);
_modules.insert(module);
return *module;
}
void _try_to_destroy(Module const &module)
@ -73,7 +86,7 @@ struct Rom::Registry : Registry_for_reader, Registry_for_writer, Genode::Noncopy
}
template <typename USER>
Module &_lookup(USER const &user, Module::Name const &name)
Module &_lookup(USER &user, Module::Name const &name)
{
Module &module = _lookup(name);
module._register(user);
@ -81,34 +94,82 @@ struct Rom::Registry : Registry_for_reader, Registry_for_writer, Genode::Noncopy
}
template <typename USER>
void _release(USER const &user, Module const &module)
void _release(USER &user, Module const &module)
{
module._unregister(user);
/*
* The '_release' function is called by both the report service
* and the ROM service. The latter has merely a 'const' version
* of the module because it is not supposed to modify it. However,
* when closing a ROM session, we have to disassociate the ROM
* session from the module. To do that, we need a non-const
* reference to the module.
*/
const_cast<Module &>(module)._unregister(user);
_try_to_destroy(module);
}
/**
* Return report name that corresponds to the given ROM session label
*
* \throw Registry_for_reader::Lookup_failed
*/
Module::Name _report_name(Module::Name const &rom_label) const
{
try {
for (Xml_node node = _config.sub_node("policy");
true; node = node.next("policy")) {
if (!node.has_attribute("label")
|| !node.has_attribute("report")
|| !node.attribute("label").has_value(rom_label.string()))
continue;
char report[Rom::Module::Name::capacity()];
node.attribute("report").value(report, sizeof(report));
return Rom::Module::Name(report);
}
} catch (Xml_node::Nonexistent_sub_node) { }
PWRN("no valid policy for label \"%s\"", rom_label.string());
throw Root::Invalid_args();
}
public:
Registry(Genode::Allocator &md_alloc) : _md_alloc(md_alloc) { }
Registry(Genode::Allocator &md_alloc, Xml_node config)
:
_md_alloc(md_alloc), _config(config)
{ }
Module &lookup(Writer const &writer, Module::Name const &name) override
Module &lookup(Writer &writer, Module::Name const &name) override
{
return _lookup(writer, name);
Module &module = _lookup(writer, name);
/*
* Enforce invariant that each module can have only one writer at a
* time.
*/
if (module._num_writers() > 1) {
release(writer, module);
throw Root::Invalid_args();
}
return module;
}
void release(Writer const &writer, Module const &module) override
void release(Writer &writer, Module &module) override
{
return _release(writer, module);
}
Module const &lookup(Reader const &reader, Module::Name const &name) override
Readable_module &lookup(Reader &reader, Module::Name const &rom_label) override
{
return _lookup(reader, name);
return _lookup(reader, _report_name(rom_label));
}
void release(Reader const &reader, Module const &module) override
void release(Reader &reader, Readable_module &module) override
{
return _release(reader, module);
return _release(reader, static_cast<Module &>(module));
}
};

View File

@ -1,172 +0,0 @@
/*
* \brief ROM service
* \author Norman Feske
* \date 2014-01-11
*/
/*
* 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 _ROM_SERVICE_H_
#define _ROM_SERVICE_H_
/* Genode includes */
#include <util/arg_string.h>
#include <util/xml_node.h>
#include <rom_session/rom_session.h>
#include <root/component.h>
/* local includes */
#include <rom_registry.h>
namespace Rom {
class Session_component;
class Root;
using Genode::Xml_node;
}
class Rom::Session_component : public Genode::Rpc_object<Genode::Rom_session>,
public Reader
{
private:
Registry_for_reader &_registry;
Module const &_module;
Lazy_volatile_object<Genode::Attached_ram_dataspace> _ds;
size_t _content_size = 0;
Genode::Signal_context_capability _sigh;
public:
Session_component(Registry_for_reader &registry,
Rom::Module::Name const &name)
:
_registry(registry), _module(_registry.lookup(*this, name))
{ }
~Session_component()
{
_registry.release(*this, _module);
}
Genode::Rom_dataspace_capability dataspace() override
{
using namespace Genode;
/* replace dataspace by new one */
/* XXX we could keep the old dataspace if the size fits */
_ds.construct(env()->ram_session(), _module.size());
/* fill dataspace content with report contained in module */
_content_size = _module.read_content(_ds->local_addr<char>(), _ds->size());
/* cast RAM into ROM dataspace capability */
Dataspace_capability ds_cap = static_cap_cast<Dataspace>(_ds->cap());
return static_cap_cast<Rom_dataspace>(ds_cap);
}
bool update() override
{
if (!_ds.is_constructed() || _module.size() > _ds->size())
return false;
size_t const new_content_size =
_module.read_content(_ds->local_addr<char>(), _ds->size());
/* clear difference between old and new content */
if (new_content_size < _content_size)
Genode::memset(_ds->local_addr<char>() + new_content_size, 0,
_content_size - new_content_size);
_content_size = new_content_size;
return true;
}
void sigh(Genode::Signal_context_capability sigh) override
{
_sigh = sigh;
}
/**
* Implementation of 'Reader' interface
*/
void notify_module_changed() const override
{
if (_sigh.valid())
Genode::Signal_transmitter(_sigh).submit();
}
};
class Rom::Root : public Genode::Root_component<Session_component>
{
private:
Registry_for_reader &_registry;
Xml_node const &_config;
typedef Rom::Module::Name Label;
/**
* Determine module name for label according to the configured policy
*/
Rom::Module::Name _module_name(Label const &label) const
{
try {
for (Xml_node node = _config.sub_node("policy");
true; node = node.next("policy")) {
if (!node.has_attribute("label")
|| !node.has_attribute("report")
|| !node.attribute("label").has_value(label.string()))
continue;
char report[Rom::Module::Name::capacity()];
node.attribute("report").value(report, sizeof(report));
return Rom::Module::Name(report);
}
} catch (Xml_node::Nonexistent_sub_node) { }
PWRN("no valid policy for label \"%s\"", label.string());
throw Root::Invalid_args();
}
protected:
Session_component *_create_session(const char *args) override
{
using namespace Genode;
/* read label of ROM module from args */
char label[Label::capacity()];
Arg_string::find_arg(args, "label").string(label, sizeof(label), "");
return new (md_alloc())
Session_component(_registry, _module_name(Label(label)));
}
public:
Root(Server::Entrypoint &ep,
Genode::Allocator &md_alloc,
Registry_for_reader &registry,
Xml_node const &config)
:
Genode::Root_component<Session_component>(&ep.rpc_ep(), &md_alloc),
_registry(registry),
_config(config)
{ }
};
#endif /* _ROM_SERVICE_H_ */

View File

@ -14,6 +14,7 @@
#include <base/printf.h>
#include <os/reporter.h>
#include <os/attached_rom_dataspace.h>
#include <timer_session/connection.h>
#define ASSERT(cond) \
@ -68,8 +69,9 @@ int main(int argc, char **argv)
printf("Reporter: close report session\n");
brightness_reporter.enabled(false);
printf("ROM client: wait for update notification\n");
sig_rec.wait_for_signal();
/* give report_rom some time to close the report session */
static Timer::Connection timer;
timer.msleep(250);
brightness_rom.update();
ASSERT(brightness_rom.is_valid());