Adapt low-level components to new parent interface

This patch adjusts the components of the os repository as well as device
drivers to the new parent interface.

Issue #2120
This commit is contained in:
Norman Feske 2016-11-06 14:27:26 +01:00 committed by Christian Helmuth
parent cfdbccc5c2
commit 8bafb9d41b
50 changed files with 1764 additions and 1964 deletions

View File

@ -109,6 +109,12 @@ void (*Genode::call_component_construct)(Genode::Env &) = &lx_hybrid_component_c
*/
void Genode::call_global_static_constructors() { }
Genode::size_t Component::stack_size() __attribute__((weak));
Genode::size_t Component::stack_size()
{
return 16UL * 1024 * sizeof(Genode::addr_t);
}
/*
* Hybrid components are not allowed to implement legacy main(). This enables
* us to hook in and bootstrap components as usual.

View File

@ -44,9 +44,6 @@ static int exit_status;
static void exit_on_suspended() { exit(exit_status); }
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
/*
* Component implements classical main function in construct.
*/

View File

@ -46,9 +46,6 @@ static int exit_status;
static void exit_on_suspended() { exit(exit_status); }
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
struct Unexpected_errno_change { };
/*

View File

@ -27,9 +27,6 @@ static int exit_status;
static void exit_on_suspended() { exit(exit_status); }
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
/*
* Component implements classical main function in construct.
*/

View File

@ -53,9 +53,6 @@ static int exit_status;
static void exit_on_suspended() { exit(exit_status); }
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
/*
* Component implements classical main function in construct.
*/

View File

@ -600,7 +600,7 @@ class Greedy : public Genode::Thread {
if (i % 8192 == 0) {
/* transfer some quota to avoid tons of upgrade messages */
char const * const buf = "ram_quota=1280K";
_env.parent().upgrade(_env.pd_session_cap(), buf);
_env.upgrade(Genode::Parent::Env::pd(), buf);
log(Hex(i * 4096));
/* trigger some work to see quota in kernel decreasing */
// Nova::Rights rwx(true, true, true);

View File

@ -135,10 +135,7 @@ class Pci_driver : public Bsd::Bus_driver
return Genode::retry<Platform::Session::Out_of_metadata>(
[&] () { return _pci.alloc_dma_buffer(size); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%zd",
donate);
_env.parent().upgrade(_pci.cap(), quota);
_pci.upgrade_ram(donate);
donate = donate * 2 > size ? 4096 : donate * 2;
});
}
@ -161,9 +158,7 @@ class Pci_driver : public Bsd::Bus_driver
int probe()
{
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%u", 8192U);
_env.parent().upgrade(_pci.cap(), buf);
_pci.upgrade_ram(8*1024);
/*
* We hide ourself in the bus_dma_tag_t as well as
@ -404,10 +399,7 @@ extern "C" int pci_mapreg_map(struct pci_attach_args *pa,
[&] () { device.config_write(Pci_driver::CMD, cmd,
Platform::Device::ACCESS_16BIT); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld",
donate);
drv->env().parent().upgrade(drv->pci().cap(), quota);
drv->pci().upgrade_ram(donate);
donate *= 2;
});

View File

@ -177,10 +177,7 @@ struct Pci_driver
Genode::retry<Platform::Device::Quota_exceeded>(
[&] () { client.config_write(devfn, val, _access_size(val)); } ,
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld",
donate);
Genode::env()->parent()->upgrade(_pci.cap(), quota);
_pci.upgrade_ram(donate);
donate *= 2;
});
}
@ -223,10 +220,7 @@ struct Pci_driver
Ram_dataspace_capability ram_cap = Genode::retry<Platform::Session::Out_of_metadata>(
[&] () { return _pci.alloc_dma_buffer(size); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld",
donate);
Genode::env()->parent()->upgrade(_pci.cap(), quota);
_pci.upgrade_ram(donate);
donate = donate * 2 > size ? 4096 : donate * 2;
});

View File

@ -188,10 +188,7 @@ class Lx::Pci_dev : public pci_dev, public Lx_kit::List<Pci_dev>::Element
Genode::retry<Platform::Device::Quota_exceeded>(
[&] () { _client.config_write(devfn, val, _access_size(val)); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld",
donate);
Genode::env()->parent()->upgrade(pci()->cap(), quota);
pci()->upgrade_ram(donate);
donate *= 2;
});
}
@ -230,9 +227,7 @@ void Lx::for_each_pci_device(FUNC const &func)
* Functor that is called if the platform driver throws a
* 'Out_of_metadata' exception.
*/
auto handler = [&] () {
Genode::env()->parent()->upgrade(Lx::pci()->cap(),
"ram_quota=4096"); };
auto handler = [&] () { Lx::pci()->upgrade_ram(4096); };
/*
* Obtain first device, the operation may exceed the session quota.

View File

@ -60,9 +60,7 @@ class Pci_dev_list
* Functor that is called if the platform driver throws a
* 'Out_of_metadata' exception.
*/
auto handler = [&] () {
Lx_kit::env().env().parent().upgrade(Lx::pci()->cap(),
"ram_quota=4096"); };
auto handler = [&] () { Lx::pci()->upgrade_ram(4096); };
/*
* Obtain first device, the operation may exceed the session quota.

View File

@ -89,10 +89,7 @@ Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached)
cap = retry<Platform::Session::Out_of_metadata>(
[&] () { return Lx::pci()->alloc_dma_buffer(size); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld",
donate);
Genode::env()->parent()->upgrade(Lx::pci()->cap(), quota);
Lx::pci()->upgrade_ram(donate);
donate = donate * 2 > size ? 4096 : donate * 2;
});

View File

@ -156,7 +156,7 @@ struct Decorator::Main : Window_factory_base
Window(attribute(window_node, "id", 0UL), nitpicker, animator, config);
} catch (Nitpicker::Session::Out_of_metadata) {
Genode::log("Handle Out_of_metadata of nitpicker session - upgrade by 8K");
Genode::env()->parent()->upgrade(nitpicker.cap(), "ram_quota=8192");
nitpicker.upgrade_ram(8192);
}
}
return 0;

View File

@ -35,4 +35,5 @@ build_boot_image { core init hello_client hello_server }
append qemu_args " -nographic "
run_genode_until forever
run_genode_until "hello test completed.*\n" 10

View File

@ -75,7 +75,7 @@ class Pci_card
* Iterate through all accessible devices.
*/
Platform::Device_capability prev_device_cap, device_cap;
Genode::env()->parent()->upgrade(_pci_drv.cap(), "ram_quota=4096");
_pci_drv.upgrade_ram(4096);
for (device_cap = _pci_drv.first_device();
device_cap.valid();
device_cap = _pci_drv.next_device(prev_device_cap)) {

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <util/list.h>
#include <base/registry.h>
#include <base/child.h>
#include <init/child_policy.h>
#include <os/child_policy_dynamic_rom.h>
@ -41,48 +42,29 @@ class Child_base : public Genode::Child_policy
typedef Genode::size_t size_t;
typedef Genode::Registered<Genode::Parent_service> Parent_service;
typedef Genode::Registry<Parent_service> Parent_services;
private:
Ram &_ram;
Genode::Session_label const _label;
Binary_name const _binary_name;
Genode::Ram_session_capability _ref_ram_cap;
Genode::Ram_session &_ref_ram;
size_t _ram_quota;
size_t _ram_limit;
struct Resources
{
Genode::Pd_connection pd;
Genode::Ram_connection ram;
Genode::Cpu_connection cpu;
Resources(const char *label, Genode::size_t ram_quota)
: pd(label), ram(label), cpu(label)
{
if (ram_quota > DONATED_RAM_QUOTA)
ram_quota -= DONATED_RAM_QUOTA;
else
throw Quota_exceeded();
ram.ref_account(Genode::env()->ram_session_cap());
if (Genode::env()->ram_session()->transfer_quota(ram.cap(), ram_quota) != 0)
throw Quota_exceeded();
}
} _resources;
Genode::Child::Initial_thread _initial_thread { _resources.cpu, _resources.pd,
_label.string() };
Genode::Region_map_client _address_space { _resources.pd.address_space() };
Genode::Service_registry _parent_services;
Genode::Rom_connection _binary_rom;
Parent_services _parent_services;
enum { ENTRYPOINT_STACK_SIZE = 12*1024 };
Genode::Rpc_entrypoint _entrypoint;
Init::Child_policy_enforce_labeling _labeling_policy;
Init::Child_policy_provide_rom_file _binary_policy;
Genode::Child_policy_dynamic_rom_file _config_policy;
Genode::Child _child;
/**
* If set to true, immediately withdraw resources yielded by the child
@ -101,35 +83,39 @@ class Child_base : public Genode::Child_policy
/* true if child is scheduled for destruction */
bool _exited = false;
Genode::Child _child;
public:
/**
* Constructor
*
* \param ref_ram used as reference account for the child'd RAM
* session and for allocating the backing store
* for the child's configuration
*/
Child_base(Ram &ram,
char const *label,
char const *binary,
Genode::Cap_session &cap_session,
Name const &label,
Binary_name const &binary_name,
Genode::Pd_session &pd_session,
Genode::Ram_session &ref_ram,
Genode::Ram_session_capability ref_ram_cap,
Genode::Region_map &local_rm,
Genode::size_t ram_quota,
Genode::size_t ram_limit,
Genode::Signal_context_capability yield_response_sig_cap,
Genode::Signal_context_capability exit_sig_cap,
Genode::Dataspace_capability ldso_ds)
Genode::Signal_context_capability exit_sig_cap)
:
_ram(ram),
_label(label),
_ram_quota(ram_quota),
_ram_limit(ram_limit),
_resources(_label.string(), _ram_quota),
_binary_rom(Genode::prefixed_label(Genode::Session_label(label),
Genode::Session_label(binary)).string()),
_entrypoint(&cap_session, ENTRYPOINT_STACK_SIZE, _label.string(), false),
_label(label), _binary_name(binary_name),
_ref_ram_cap(ref_ram_cap), _ref_ram(ref_ram),
_ram_quota(ram_quota), _ram_limit(ram_limit),
_entrypoint(&pd_session, ENTRYPOINT_STACK_SIZE, _label.string(), false),
_labeling_policy(_label.string()),
_binary_policy("binary", _binary_rom.dataspace(), &_entrypoint),
_config_policy("config", _entrypoint, &_resources.ram),
_child(_binary_rom.dataspace(), ldso_ds, _resources.pd, _resources.pd,
_resources.ram, _resources.ram, _resources.cpu, _initial_thread,
*Genode::env()->rm_session(), _address_space,
_entrypoint, *this),
_config_policy("config", _entrypoint, &ref_ram),
_yield_response_sigh_cap(yield_response_sig_cap),
_exit_sig_cap(exit_sig_cap)
_exit_sig_cap(exit_sig_cap),
_child(local_rm, _entrypoint, *this)
{ }
Genode::Session_label label() const { return _label; }
@ -176,7 +162,7 @@ class Child_base : public Genode::Child_policy
if (!amount)
return;
_ram.withdraw_from(_resources.ram.cap(), amount);
_ram.withdraw_from(_child.ram_session_cap(), amount);
_ram_quota -= amount;
}
@ -187,12 +173,12 @@ class Child_base : public Genode::Child_policy
*/
void upgrade_ram_quota(size_t amount)
{
_ram.transfer_to(_resources.ram.cap(), amount);
_ram.transfer_to(_child.ram_session_cap(), amount);
_ram_quota += amount;
/* wake up child if resource request is in flight */
size_t const req = requested_ram_quota();
if (req && _resources.ram.avail() >= req) {
if (req && _child.ram().avail() >= req) {
_child.notify_resource_avail();
/* clear request state */
@ -258,9 +244,9 @@ class Child_base : public Genode::Child_policy
{
return Ram_status(_ram_quota,
_ram_limit,
_ram_quota - _resources.ram.quota(),
_resources.ram.used(),
_resources.ram.avail(),
_ram_quota - _child.ram().quota(),
_child.ram().used(),
_child.ram().avail(),
requested_ram_quota());
}
@ -274,36 +260,41 @@ class Child_base : public Genode::Child_policy
** Child_policy interface **
****************************/
const char *name() const { return _label.string(); }
Name name() const override { return _label.string(); }
Genode::Service *resolve_session_request(const char *service_name,
const char *args)
Genode::Ram_session_capability ref_ram_cap() const override { return _ref_ram_cap; }
Genode::Ram_session &ref_ram() override { return _ref_ram; }
void init(Genode::Ram_session &session, Genode::Ram_session_capability cap) override
{
Genode::Service *service = 0;
/* check for binary file request */
if ((service = _binary_policy.resolve_session_request(service_name, args)))
return service;
/* check for config file request */
if ((service = _config_policy.resolve_session_request(service_name, args)))
return service;
/* fill parent service registry on demand */
if (!(service = _parent_services.find(service_name))) {
service = new (Genode::env()->heap())
Genode::Parent_service(service_name);
_parent_services.insert(service);
}
/* return parent service */
return service;
session.ref_account(_ref_ram_cap);
_ref_ram.transfer_quota(cap, _ram_quota);
}
void filter_session_args(const char *service,
char *args, Genode::size_t args_len)
Genode::Service &resolve_session_request(Genode::Service::Name const &name,
Genode::Session_state::Args const &args) override
{
_labeling_policy.filter_session_args(service, args, args_len);
Genode::Service *service = nullptr;
/* check for config file request */
if ((service = _config_policy.resolve_session_request(name.string(), args.string())))
return *service;
/* populate session-local parent service registry on demand */
_parent_services.for_each([&] (Parent_service &s) {
if (s.name() == name)
service = &s; });
if (service)
return *service;
return *new (Genode::env()->heap()) Parent_service(_parent_services, name);
}
void filter_session_args(Genode::Service::Name const &service,
char *args, Genode::size_t args_len) override
{
_labeling_policy.filter_session_args(service.string(), args, args_len);
}
void yield_response()
@ -311,8 +302,8 @@ class Child_base : public Genode::Child_policy
if (_withdraw_on_yield_response) {
enum { RESERVE = 4*1024*1024 };
size_t amount = _resources.ram.avail() < RESERVE
? 0 : _resources.ram.avail() - RESERVE;
size_t amount = _child.ram().avail() < RESERVE
? 0 : _child.ram().avail() - RESERVE;
/* try to immediately withdraw freed-up resources */
try { withdraw_ram_quota(amount); }

View File

@ -112,7 +112,7 @@ struct File_system::Connection : File_system::Connection_base
*/
void upgrade_ram()
{
Genode::env()->parent()->upgrade(cap(), "ram=8K");
File_system::Connection_base::upgrade_ram(8*1024);
}
enum { UPGRADE_ATTEMPTS = 2 };

View File

@ -26,6 +26,10 @@ namespace Nitpicker { class Connection; }
class Nitpicker::Connection : public Genode::Connection<Session>,
public Session_client
{
public:
enum { RAM_QUOTA = 36*1024UL };
private:
Framebuffer::Session_client _framebuffer;
@ -48,8 +52,7 @@ class Nitpicker::Connection : public Genode::Connection<Session>,
* Declare ram-quota donation
*/
using Genode::Arg_string;
enum { SESSION_METADATA = 36*1024 };
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", SESSION_METADATA);
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", RAM_QUOTA);
return session(parent, argbuf);
}
@ -90,20 +93,12 @@ class Nitpicker::Connection : public Genode::Connection<Session>,
void buffer(Framebuffer::Mode mode, bool use_alpha)
{
enum { ARGBUF_SIZE = 128 };
char argbuf[ARGBUF_SIZE];
argbuf[0] = 0;
Genode::size_t const needed = ram_quota(mode, use_alpha);
Genode::size_t const upgrade = needed > _session_quota
? needed - _session_quota
: 0;
if (upgrade > 0) {
Genode::Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota",
upgrade);
Genode::env()->parent()->upgrade(cap(), argbuf);
this->upgrade_ram(upgrade);
_session_quota += upgrade;
}

View File

@ -24,6 +24,7 @@
namespace Nitpicker {
using Genode::size_t;
struct Session_client;
struct View;
typedef Genode::Capability<View> View_capability;
struct Session;
@ -37,6 +38,8 @@ struct Nitpicker::Session : Genode::Session
{
static const char *service_name() { return "Nitpicker"; }
typedef Session_client Client;
/**
* Session-local view handle
*

View File

@ -22,6 +22,8 @@ namespace Report { struct Connection; }
struct Report::Connection : Genode::Connection<Session>, Session_client
{
enum { RAM_QUOTA = 4*4096 }; /* value used for 'Slave::Connection' */
/**
* Issue session request
*

View File

@ -44,6 +44,7 @@ namespace Report {
using Genode::size_t;
struct Session;
struct Session_client;
}
@ -51,6 +52,8 @@ struct Report::Session : Genode::Session
{
static const char *service_name() { return "Report"; }
typedef Session_client Client;
/**
* Request the dataspace used to carry reports and responses
*/

View File

@ -48,6 +48,12 @@ install_config {
<start name="loader">
<resource name="RAM" quantum="10M"/>
<provides> <service name="Loader"/> </provides>
<config>
<policy label="test-fault_detection">
<parent-rom name="test-segfault"/>
<parent-rom name="init"/>
</policy>
</config>
</start>
<start name="test-fault_detection">
<resource name="RAM" quantum="10M"/>

View File

@ -76,6 +76,11 @@ append config {
<start name="loader">
<resource name="RAM" quantum="1M"/>
<provides><service name="Loader"/></provides>
<config>
<policy label="test-loader">
<parent-rom name="testnit"/>
</policy>
</config>
</start>
<start name="test-loader">
<resource name="RAM" quantum="1G"/>

View File

@ -25,6 +25,7 @@ install_config {
<start name="test-resource_yield">
<resource name="RAM" quantum="16M"/>
<provides> <service name="ROM" /> </provides>
<config/>
</start>
</config>
}

View File

@ -135,7 +135,7 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component>
throw Root::Unavailable();
}
Factory *factory = new (&_alloc) Factory(num);
Block::Factory *factory = new (&_alloc) Block::Factory(num);
::Session_component *session = new (&_alloc)
::Session_component(*factory, _env.ep(), tx_buf_size);
log("session opened at device ", num, " for '", label, "'");
@ -145,8 +145,8 @@ class Block::Root_multiple_clients : public Root_component< ::Session_component>
void _destroy_session(::Session_component *session)
{
Driver_factory &factory = session->factory();
destroy(&_alloc, session);
destroy(&_alloc, &factory);
Genode::destroy(&_alloc, session);
Genode::destroy(&_alloc, &factory);
}
public:

View File

@ -46,7 +46,7 @@ struct X86_hba : Platform::Hba
pci_device_cap = retry<Platform::Session::Out_of_metadata>(
[&] () { return pci.next_device(pci_device_cap, AHCI_DEVICE,
CLASS_MASK); },
[&] () { env.parent().upgrade(pci.cap(), "ram_quota=4096"); });
[&] () { pci.upgrade_ram(4096); });
if (!pci_device_cap.valid()) {
Genode::error("no AHCI controller found");
@ -102,10 +102,7 @@ struct X86_hba : Platform::Hba
Genode::retry<Platform::Device::Quota_exceeded>(
[&] () { pci_device->config_write(op, cmd, width); },
[&] () {
char quota[32];
Genode::snprintf(quota, sizeof(quota), "ram_quota=%ld",
donate);
env.parent().upgrade(pci.cap(), quota);
pci.upgrade_ram(donate);
donate *= 2;
});
}
@ -134,9 +131,7 @@ struct X86_hba : Platform::Hba
return retry<Platform::Session::Out_of_metadata>(
[&] () { return pci.alloc_dma_buffer(size); },
[&] () {
char quota[32];
snprintf(quota, sizeof(quota), "ram_quota=%ld", donate);
env.parent().upgrade(pci.cap(), quota);
pci.upgrade_ram(donate);
donate = donate * 2 > size ? 4096 : donate * 2;
});
}

View File

@ -305,7 +305,4 @@ struct Audio_out::Main
** Component **
***************/
namespace Component {
Genode::size_t stack_size() { return 2*1024*sizeof(addr_t); }
void construct(Genode::Env &env) { static Audio_out::Main main(env); }
}
void Component::construct(Genode::Env &env) { static Audio_out::Main main(env); }

View File

@ -214,5 +214,4 @@ struct Main
};
Genode::size_t Component::stack_size() { return 4*1024*sizeof(long); }
void Component::construct(Genode::Env &env) { static Main inst(env); }

View File

@ -481,6 +481,8 @@ namespace Genode
_deinit();
}
using Nic::Session_component::cap;
void phy_write(const uint8_t phyaddr, const uint8_t regnum, const uint16_t data)
{

View File

@ -15,71 +15,32 @@
#include <os/slave.h>
enum { STACK_SIZE = 2 * sizeof(void *) * 1024 };
enum { STACK_SIZE = 4 * sizeof(void *) * 1024 };
namespace Platform { class Device_pd_policy; }
class Platform::Device_pd_policy : public Genode::Slave_policy
class Platform::Device_pd_policy : public Genode::Slave::Policy
{
private:
Genode::Root_capability _cap;
Genode::Lock _lock;
Genode::Ram_session_capability _ram_ref_cap;
Genode::Slave _device_pd_slave;
protected:
char const **_permitted_services() const
char const **_permitted_services() const override
{
static char const *permitted_services[] = { "LOG", "CAP", "RM", 0 };
static char const *permitted_services[] = {
"RAM", "PD", "CPU", "LOG", "ROM", 0 };
return permitted_services;
};
public:
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
Device_pd_policy(Genode::Rpc_entrypoint &slave_ep,
Genode::Region_map &local_rm,
Genode::Ram_session_capability ram_ref_cap,
Genode::addr_t device_pd_ram_quota,
const char * label)
Genode::size_t ram_quota,
Genode::Session_label const &label)
:
Slave_policy(label, slave_ep, nullptr, "device_pd"),
_lock(Genode::Lock::LOCKED),
_ram_ref_cap(ram_ref_cap),
_device_pd_slave(slave_ep, *this, device_pd_ram_quota, ram_ref_cap)
Genode::Slave::Policy(label, "device_pd", slave_ep, local_rm,
ram_ref_cap, ram_quota)
{ }
bool announce_service(const char *service_name,
Genode::Root_capability root,
Genode::Allocator *alloc,
Genode::Server *server)
{
/* wait for 'platform_drv' to announce the DEVICE_PD service */
if (Genode::strcmp(service_name, "DEVICE_PD"))
return false;
_cap = root;
_lock.unlock();
return true;
}
Genode::Root_capability root() {
if (!_cap.valid())
_lock.lock();
return _cap;
}
Genode::Ram_connection &ram_slave() { return _device_pd_slave.ram(); }
/**
* Override struct Genode::Child_policy::ref_ram_cap with our ram cap
*/
Genode::Ram_session_capability ref_ram_cap() const override {
return _ram_ref_cap; }
};

View File

@ -62,11 +62,8 @@ struct Expanding_region_map_client : Genode::Region_map_client
if (Genode::env()->ram_session()->avail() < UPGRADE_QUOTA)
throw;
char buf[32];
Genode::snprintf(buf, sizeof(buf), "ram_quota=%u",
UPGRADE_QUOTA);
_env.parent().upgrade(_env.pd_session_cap(), buf);
Genode::String<32> arg("ram_quota=", (unsigned)UPGRADE_QUOTA);
_env.upgrade(Genode::Parent::Env::pd(), arg.string());
}
);
}

View File

@ -29,24 +29,24 @@ class Nonpci::Ps2 : public Platform::Device_component
REG_STATUS = 0x64,
};
Genode::Rpc_entrypoint &_ep;
Platform::Irq_session_component _irq_mouse;
Genode::Io_port_connection _data;
Genode::Io_port_connection _status;
public:
Ps2(Genode::Rpc_entrypoint * ep, Platform::Session_component * session)
Ps2(Genode::Rpc_entrypoint &ep, Platform::Session_component &session)
:
Platform::Device_component(ep, session, IRQ_KEYBOARD),
_ep(ep),
_irq_mouse(IRQ_MOUSE, ~0UL),
_data(REG_DATA, ACCESS_WIDTH), _status(REG_STATUS, ACCESS_WIDTH)
{
ep->manage(&_irq_mouse);
_ep.manage(&_irq_mouse);
}
~Ps2() {
ep()->dissolve(&_irq_mouse);
}
~Ps2() { _ep.dissolve(&_irq_mouse); }
Genode::Irq_session_capability irq(Genode::uint8_t virt_irq) override
{
@ -97,7 +97,7 @@ class Nonpci::Pit : public Platform::Device_component
public:
Pit(Genode::Rpc_entrypoint * ep, Platform::Session_component * session)
Pit(Genode::Rpc_entrypoint &ep, Platform::Session_component &session)
:
Platform::Device_component(ep, session, IRQ_PIT),
_ports(PIT_PORT, PORTS_WIDTH)
@ -147,17 +147,17 @@ Platform::Device_capability Platform::Session_component::device(String const &na
switch(devices_i) {
case 0:
dev = new (_md_alloc) Nonpci::Ps2(_ep, this);
dev = new (_md_alloc) Nonpci::Ps2(_ep, *this);
break;
case 1:
dev = new (_md_alloc) Nonpci::Pit(_ep, this);
dev = new (_md_alloc) Nonpci::Pit(_ep, *this);
break;
default:
return Device_capability();
}
_device_list.insert(dev);
return _ep->manage(dev);
return _ep.manage(dev);
} catch (Genode::Allocator::Out_of_memory) {
throw Out_of_metadata();
} catch (Genode::Parent::Service_denied) {

View File

@ -73,6 +73,7 @@ Genode::Io_mem_session_capability Platform::Device_component::io_mem(Genode::uin
_io_mem[i].insert(io_mem);
return io_mem->cap();
} catch (Genode::Allocator::Out_of_memory) {
Genode::error("Quota_exceeded in Device_component::io_mem");
throw Quota_exceeded();
} catch (...) {
return Genode::Io_mem_session_capability();
@ -116,9 +117,9 @@ void Platform::Device_component::config_write(unsigned char address,
}
/* assign device to device_pd */
if (address == PCI_CMD_REG && value & PCI_CMD_DMA && _session) {
if (address == PCI_CMD_REG && value & PCI_CMD_DMA) {
try {
_session->assign_device(this);
_session.assign_device(this);
} catch (Platform::Session::Out_of_metadata) {
throw Quota_exceeded();
} catch (...) {
@ -145,14 +146,14 @@ Genode::Irq_session_capability Platform::Device_component::irq(Genode::uint8_t i
_irq_session = construct_at<Irq_session_component>(_mem_irq_component,
_irq_line, ~0UL);
_ep->manage(_irq_session);
_ep.manage(_irq_session);
return _irq_session->cap();
}
_irq_session = construct_at<Irq_session_component>(_mem_irq_component,
_configure_irq(_irq_line),
(!_session->msi_usage() || !_msi_cap()) ? ~0UL : _config_space);
_ep->manage(_irq_session);
(!_session.msi_usage() || !_msi_cap()) ? ~0UL : _config_space);
_ep.manage(_irq_session);
Genode::uint16_t msi_cap = _msi_cap();

View File

@ -37,10 +37,10 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
Device_config _device_config;
Genode::addr_t _config_space;
Config_access _config_access;
Genode::Rpc_entrypoint *_ep;
Platform::Session_component *_session;
Genode::Rpc_entrypoint &_ep;
Platform::Session_component &_session;
unsigned short _irq_line;
Irq_session_component *_irq_session;
Irq_session_component *_irq_session = nullptr;
Genode::Lazy_volatile_object<Genode::Io_mem_connection> _io_mem_config_extended;
@ -177,28 +177,22 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
Platform::Device::ACCESS_16BIT);
}
protected:
Genode::Rpc_entrypoint * ep() { return _ep; }
public:
/**
* Constructor
*/
Device_component(Device_config device_config, Genode::addr_t addr,
Genode::Rpc_entrypoint *ep,
Platform::Session_component * session,
Genode::Allocator * md_alloc)
Genode::Rpc_entrypoint &ep,
Platform::Session_component &session,
Genode::Allocator &md_alloc)
:
_device_config(device_config), _config_space(addr),
_ep(ep), _session(session),
_irq_line(_device_config.read(&_config_access, PCI_IRQ_LINE,
Platform::Device::ACCESS_8BIT)),
_irq_session(nullptr),
_slab_ioport(md_alloc, &_slab_ioport_block_data),
_slab_iomem(md_alloc, &_slab_iomem_block_data)
_slab_ioport(&md_alloc, &_slab_ioport_block_data),
_slab_iomem(&md_alloc, &_slab_iomem_block_data)
{
for (unsigned i = 0; i < Device::NUM_RESOURCES; i++) {
_io_port_conn[i] = nullptr;
@ -210,15 +204,14 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
/**
* Constructor for non PCI devices
*/
Device_component(Genode::Rpc_entrypoint * ep,
Platform::Session_component * session, unsigned irq)
Device_component(Genode::Rpc_entrypoint &ep,
Platform::Session_component &session, unsigned irq)
:
_config_space(~0UL),
_ep(ep), _session(session),
_irq_line(irq),
_irq_session(nullptr),
_slab_ioport(0, &_slab_ioport_block_data),
_slab_iomem(0, &_slab_iomem_block_data)
_slab_ioport(nullptr, &_slab_ioport_block_data),
_slab_iomem(nullptr, &_slab_iomem_block_data)
{
for (unsigned i = 0; i < Device::NUM_RESOURCES; i++)
_io_port_conn[i] = nullptr;
@ -230,7 +223,7 @@ class Platform::Device_component : public Genode::Rpc_object<Platform::Device>,
~Device_component()
{
if (_irq_session) {
_ep->dissolve(_irq_session);
_ep.dissolve(_irq_session);
_irq_session->~Irq_session();
}

View File

@ -13,6 +13,7 @@
#pragma once
#include <base/connection.h>
#include <base/rpc_server.h>
#include <io_mem_session/capability.h>
@ -21,6 +22,7 @@ namespace Platform {
struct Device_pd;
struct Device_pd_client;
struct Device_pd_connection;
struct Device_pd_component;
}
@ -28,6 +30,8 @@ struct Platform::Device_pd : Genode::Session
{
static const char *service_name() { return "DEVICE_PD"; }
typedef Device_pd_client Client;
GENODE_RPC_THROW(Rpc_attach_dma_mem, void, attach_dma_mem,
GENODE_TYPE_LIST(Genode::Rm_session::Out_of_metadata),
Genode::Dataspace_capability);
@ -54,6 +58,17 @@ struct Platform::Device_pd_client : Genode::Rpc_client<Device_pd>
}
};
struct Platform::Device_pd_connection : Genode::Connection<Device_pd>, Device_pd_client
{
enum { RAM_QUOTA = 0UL };
Device_pd_connection(Genode::Capability<Device_pd> cap)
:
Genode::Connection<Device_pd>(cap),
Device_pd_client(cap)
{ }
};
struct Platform::Device_pd_component : Genode::Rpc_object<Device_pd,
Device_pd_component>
{

File diff suppressed because it is too large Load Diff

View File

@ -12,9 +12,8 @@
*/
/* Genode */
#include <base/env.h>
#include <base/component.h>
#include <base/heap.h>
#include <os/server.h>
#include <root/component.h>
#include <rtc_session/rtc_session.h>
@ -52,7 +51,7 @@ class Rtc::Root : public Genode::Root_component<Session_component>
public:
Root(Server::Entrypoint &ep, Allocator &md_alloc)
Root(Entrypoint &ep, Allocator &md_alloc)
:
Genode::Root_component<Session_component>(&ep.rpc_ep(), &md_alloc)
{
@ -64,23 +63,14 @@ class Rtc::Root : public Genode::Root_component<Session_component>
struct Rtc::Main
{
Server::Entrypoint &ep;
Env &env;
Sliced_heap sliced_heap { env()->ram_session(), env()->rm_session() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Root root { ep, sliced_heap };
Root root { env.ep(), sliced_heap };
Main(Server::Entrypoint &ep) : ep(ep)
{
env()->parent()->announce(ep.manage(root));
}
Main(Env &env) : env(env) { env.parent().announce(env.ep().manage(root)); }
};
/**********************
** Server framework **
**********************/
char const * Server::name() { return "rtc_ep"; }
Genode::size_t Server::stack_size() { return 1024 * sizeof(long); }
void Server::construct(Server::Entrypoint &ep) { static Rtc::Main inst(ep); }
void Component::construct(Genode::Env &env) { static Rtc::Main main(env); }

View File

@ -1,7 +1,7 @@
TARGET = rtc_drv
REQUIRES = x86
SRC_CC = main.cc
LIBS = base server
LIBS = base
# enforce hybrid prg on Linux
ifeq ($(filter-out $(SPECS),linux),)

View File

@ -3,3 +3,10 @@ subsystems via a session interface. The resources for the new subsystem are
provided by the client when opening the session. The client has no control over
the functioning of the subsystem except for the controlling the lifetime of the
subsystem.
By default, the loaded subsystem can access only those ROM modules that were
loaded into the loader session by the loader client. However, it is possible
to define a whitelist of ROM modules to be obtained from the loader's parent.
For an example, refer to the example 'run/loader.run' script.

View File

@ -29,150 +29,100 @@ namespace Loader {
using namespace Genode;
typedef Registered<Parent_service> Parent_service;
typedef Registry<Parent_service> Parent_services;
class Child : public Child_policy
{
private:
typedef String<Session::Name::MAX_SIZE> Label;
Env &_env;
Label _label;
Session_label const _label;
Name const _binary_name;
Rpc_entrypoint &_ep;
size_t const _ram_quota;
struct Resources
{
Pd_connection pd;
Ram_connection ram;
Cpu_connection cpu;
Parent_services &_parent_services;
Resources(char const *label,
Ram_session_client &ram_session_client,
size_t ram_quota,
Signal_context_capability fault_sigh)
: pd(label), ram(label), cpu(label)
{
/* deduce session costs from usable ram quota */
size_t session_donations = Cpu_connection::RAM_QUOTA +
Ram_connection::RAM_QUOTA;
if (ram_quota > session_donations)
ram_quota -= session_donations;
else ram_quota = 0;
ram.ref_account(ram_session_client);
ram_session_client.transfer_quota(ram.cap(), ram_quota);
/*
* Install CPU exception and RM fault handler assigned by
* the loader client via 'Loader_session::fault_handler'.
*/
cpu.exception_sigh(fault_sigh);
Region_map_client address_space(pd.address_space());
address_space.fault_handler(fault_sigh);
}
} _resources;
Genode::Child::Initial_thread _initial_thread { _resources.cpu,
_resources.pd,
_label.string() };
Region_map_client _address_space { _resources.pd.address_space() };
Service_registry &_parent_services;
Service &_local_nitpicker_service;
Service &_local_rom_service;
Service &_local_cpu_service;
Service &_local_pd_service;
Rom_session_client _binary_rom_session;
Init::Child_policy_provide_rom_file _binary_policy;
Init::Child_policy_enforce_labeling _labeling_policy;
Genode::Child _child;
Rom_session_capability _rom_session(char const *name)
{
try {
char args[Session::Name::MAX_SIZE];
snprintf(args, sizeof(args), "ram_quota=4K, label=\"%s\"", name);
return static_cap_cast<Rom_session>(_local_rom_service.session(args, Affinity()));
} catch (Genode::Parent::Service_denied) {
Genode::error("Lookup for ROM module \"", name, "\" failed");
throw;
}
}
public:
Child(char const *binary_name,
char const *label,
Dataspace_capability ldso_ds,
Rpc_entrypoint &ep,
Ram_session_client &ram_session_client,
Child(Env &env,
Name const &binary_name,
Session_label const &label,
size_t ram_quota,
Service_registry &parent_services,
Parent_services &parent_services,
Service &local_rom_service,
Service &local_cpu_service,
Service &local_pd_service,
Service &local_nitpicker_service,
Signal_context_capability fault_sigh)
:
_env(env),
_label(label),
_ep(ep),
_resources(_label.string(), ram_session_client, ram_quota, fault_sigh),
_binary_name(binary_name),
_ram_quota(Genode::Child::effective_ram_quota(ram_quota)),
_parent_services(parent_services),
_local_nitpicker_service(local_nitpicker_service),
_local_rom_service(local_rom_service),
_local_cpu_service(local_cpu_service),
_local_pd_service(local_pd_service),
_binary_rom_session(_rom_session(binary_name)),
_binary_policy("binary", _binary_rom_session.dataspace(), &_ep),
_labeling_policy(_label.string()),
_child(_binary_rom_session.dataspace(), ldso_ds,
_resources.pd, _resources.pd,
_resources.ram, _resources.ram,
_resources.cpu, _initial_thread,
*env()->rm_session(), _address_space, _ep, *this)
_child(_env.rm(), _env.ep().rpc_ep(), *this)
{ }
~Child()
{
_local_rom_service.close(_binary_rom_session);
}
~Child() { }
/****************************
** Child-policy interface **
****************************/
char const *name() const override { return _label.string(); }
Name name() const override { return _label; }
void filter_session_args(char const *service, char *args, size_t args_len) override
Binary_name binary_name() const override { return _binary_name; }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Ram_session &ram, Ram_session_capability ram_cap) override
{
_labeling_policy.filter_session_args(service, args, args_len);
ram.ref_account(ref_ram_cap());
ref_ram().transfer_quota(ram_cap, _ram_quota);
}
Service *resolve_session_request(const char *name,
const char *args) override
void filter_session_args(Service::Name const &service, char *args, size_t args_len) override
{
Service *service = 0;
_labeling_policy.filter_session_args(service.string(), args, args_len);
}
if ((service = _binary_policy.resolve_session_request(name, args)))
return service;
if (!strcmp(name, "Nitpicker")) return &_local_nitpicker_service;
if (!strcmp(name, "ROM")) return &_local_rom_service;
if (!strcmp(name, "CPU")) return &_local_cpu_service;
if (!strcmp(name, "PD")) return &_local_pd_service;
Service &resolve_session_request(Service::Name const &name,
Session_state::Args const &args) override
{
if (name == "Nitpicker") return _local_nitpicker_service;
if (name == "ROM") return _local_rom_service;
if (name == "CPU") return _local_cpu_service;
if (name == "PD") return _local_pd_service;
/* populate session-local parent service registry on demand */
service = _parent_services.find(name);
if (!service) {
service = new (env()->heap()) Parent_service(name);
_parent_services.insert(service);
}
return service;
Service *service = nullptr;
_parent_services.for_each([&] (Parent_service &s) {
if (s.name() == name)
service = &s; });
if (service)
return *service;
return *new (env()->heap()) Parent_service(_parent_services, name);
}
};
}

View File

@ -12,14 +12,13 @@
*/
/* Genode includes */
#include <base/env.h>
#include <base/component.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 <root/component.h>
#include <os/session_policy.h>
/* local includes */
#include <child.h>
@ -41,104 +40,79 @@ class Loader::Session_component : public Rpc_object<Session>
{
private:
struct Local_rom_service : Service
struct Local_rom_factory : Local_service<Rom_session_component>::Factory
{
Rpc_entrypoint &_ep;
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)
void _close(Rom_session_component &rom)
{
_rom_sessions.remove(rom);
destroy(&_md_alloc, rom);
_rom_sessions.remove(&rom);
Genode::destroy(_md_alloc, &rom);
}
Local_rom_service(Rpc_entrypoint &ep,
Local_rom_factory(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)
_ep(ep), _md_alloc(md_alloc), _rom_modules(rom_modules)
{ }
~Local_rom_service()
~Local_rom_factory()
{
Lock::Guard guard(_lock);
while (_rom_sessions.first()) {
_ep.remove(_rom_sessions.first());
_close(_rom_sessions.first());
}
while (_rom_sessions.first())
_close(*_rom_sessions.first());
}
Genode::Session_capability session(char const *args,
Affinity const &affinity)
Rom_session_component &create(Args const &args, Affinity affinity) override
{
/* try to find ROM module at local ROM service */
try {
Lock::Guard guard(_lock);
Session_label const label = label_from_args(args);
Session_label name = label.last_element();
Session_label const label = label_from_args(args.string());
Session_label const name = label.last_element();
Rom_module &module = _rom_modules.lookup_and_lock(name.string());
Rom_session_component *rom = new (&_md_alloc)
Rom_session_component(module);
Rom_session_component *rom = new (_md_alloc)
Rom_session_component(_ep, module);
_rom_sessions.insert(rom);
return _ep.manage(rom);
return *rom;
} catch (...) { }
/* fall back to parent_rom_service */
return _parent_rom_service.session(args, affinity);
throw Denied();
}
void close(Session_capability session)
void upgrade(Rom_session_component &, Args const &) override { }
void destroy(Rom_session_component &session) override
{
Lock::Guard guard(_lock);
Rom_session_component *component;
_ep.apply(session, [&] (Rom_session_component *rsc) {
component = rsc;
if (component) _ep.remove(component);
});
if (component) {
_close(component);
return;
}
_parent_rom_service.close(session);
_close(session);
}
void upgrade(Session_capability session, const char *) { }
};
typedef Local_service<Rom_session_component> Local_rom_service;
/**
* Common base class of 'Local_cpu_service' and 'Local_pd_service'
*/
struct Intercepted_parent_service : Service
struct Intercepted_parent_service : Genode::Parent_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 *) { }
Intercepted_parent_service(Env &env, Service::Name const &name)
: Parent_service(env, name) { }
};
/**
@ -147,20 +121,17 @@ class Loader::Session_component : public Rpc_object<Session>
*/
struct Local_cpu_service : Intercepted_parent_service
{
Local_cpu_service() : Intercepted_parent_service("CPU") { }
Local_cpu_service(Env &env) : Intercepted_parent_service(env, "CPU") { }
Genode::Session_capability session(char const *args,
Affinity const &affinity)
void initiate_request(Session_state &session) override
{
Capability<Cpu_session> cap = env()->parent()->session<Cpu_session>(args, affinity);
Cpu_session_client(cap).exception_sigh(fault_sigh);
return cap;
}
Intercepted_parent_service::initiate_request(session);
void upgrade(Session_capability session, const char *args)
{
try { env()->parent()->upgrade(session, args); }
catch (Genode::Ipc_error) { throw Unavailable(); }
if (session.phase != Session_state::AVAILABLE)
return;
Cpu_session_client cpu(reinterpret_cap_cast<Cpu_session>(session.cap));
cpu.exception_sigh(fault_sigh);
}
};
@ -169,109 +140,100 @@ class Loader::Session_component : public Rpc_object<Session>
*/
struct Local_pd_service : Intercepted_parent_service
{
Local_pd_service() : Intercepted_parent_service("PD") { }
Local_pd_service(Env &env) : Intercepted_parent_service(env, "PD") { }
Genode::Session_capability session(char const *args,
Affinity const &affinity)
void initiate_request(Session_state &session) override
{
Pd_session_client pd(env()->parent()->session<Pd_session>(args, affinity));
Intercepted_parent_service::initiate_request(session);
if (session.phase != Session_state::AVAILABLE)
return;
Pd_session_client pd(reinterpret_cap_cast<Pd_session>(session.cap));
Region_map_client(pd.address_space()).fault_handler(fault_sigh);
Region_map_client(pd.stack_area()) .fault_handler(fault_sigh);
Region_map_client(pd.linker_area()) .fault_handler(fault_sigh);
return pd;
}
};
struct Local_nitpicker_service : Service
struct Local_nitpicker_factory : Local_service<Nitpicker::Session_component>::Factory
{
Rpc_entrypoint &_ep;
Ram_session &_ram;
Allocator &_md_alloc;
Entrypoint &_ep;
Ram_session &_ram;
Area _max_size;
Nitpicker::View_capability _parent_view;
Signal_context_capability view_ready_sigh;
Nitpicker::Session_component *open_session;
Lazy_volatile_object<Nitpicker::Session_component> session;
Local_nitpicker_service(Rpc_entrypoint &ep, Ram_session &ram,
Allocator &md_alloc)
:
Service("virtual_nitpicker"),
_ep(ep),
_ram(ram),
_md_alloc(md_alloc),
open_session(0)
{ }
Local_nitpicker_factory(Entrypoint &ep, Ram_session &ram)
: _ep(ep), _ram(ram) { }
~Local_nitpicker_service()
{
if (!open_session)
return;
_ep.dissolve(open_session);
destroy(&_md_alloc, open_session);
}
void constrain_geometry(Area size)
{
_max_size = size;
}
void constrain_geometry(Area size) { _max_size = size; }
void parent_view(Nitpicker::View_capability view)
{
_parent_view = view;
}
Genode::Session_capability session(char const *args,
Affinity const &)
Nitpicker::Session_component &create(Args const &args, Affinity) override
{
if (open_session)
throw Unavailable();
if (session.constructed()) {
warning("attempt to open more than one nitpicker session");
throw Parent::Service_denied();
}
open_session = new (&_md_alloc)
Nitpicker::Session_component(_ep,
_ram,
_max_size,
_parent_view,
view_ready_sigh,
args);
return _ep.manage(open_session);
session.construct(_ep, _ram, _max_size,
_parent_view, view_ready_sigh, args.string());
return *session;
}
void upgrade(Genode::Session_capability session, const char *) { }
void upgrade(Nitpicker::Session_component &, Args const &) override { }
void destroy(Nitpicker::Session_component &) override { }
};
typedef Local_service<Nitpicker::Session_component> Local_nitpicker_service;
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;
Dataspace_capability _ldso_ds;
Service_registry _parent_services;
Rom_module_registry _rom_modules;
Local_rom_service _rom_service;
Local_cpu_service _cpu_service;
Local_pd_service _pd_service;
Local_nitpicker_service _nitpicker_service;
Signal_context_capability _fault_sigh;
Child *_child;
Env &_env;
Session_label const _label;
Xml_node const _config;
size_t const _ram_quota;
Ram_session_client_guard _local_ram { _env.ram_session_cap(), _ram_quota };
Heap _md_alloc { _local_ram, _env.rm() };
size_t _subsystem_ram_quota_limit = 0;
Parent_services _parent_services;
Rom_module_registry _rom_modules { _env, _config, _local_ram, _md_alloc };
Local_rom_factory _rom_factory { _env.ep(), _md_alloc, _rom_modules };
Local_rom_service _rom_service { _rom_factory };
Local_cpu_service _cpu_service { _env };
Local_pd_service _pd_service { _env };
Local_nitpicker_factory _nitpicker_factory { _env.ep(), _local_ram };
Local_nitpicker_service _nitpicker_service { _nitpicker_factory };
Signal_context_capability _fault_sigh;
Lazy_volatile_object<Child> _child;
/**
* Return virtual nitpicker session component
*/
Nitpicker::Session_component &_virtual_nitpicker_session() const
Nitpicker::Session_component &_virtual_nitpicker_session()
{
if (!_nitpicker_service.open_session)
if (!_nitpicker_factory.session.constructed())
throw View_does_not_exist();
return *_nitpicker_service.open_session;
return *_nitpicker_factory.session;
}
Nitpicker::Session_component const &_virtual_nitpicker_session() const
{
if (!_nitpicker_factory.session.constructed())
throw View_does_not_exist();
return *_nitpicker_factory.session;
}
public:
@ -279,34 +241,30 @@ class Loader::Session_component : public Rpc_object<Session>
/**
* Constructor
*/
Session_component(size_t quota, Ram_session &ram, Cap_session &cap,
Dataspace_capability ldso_ds)
Session_component(Env &env, Session_label const &label,
Xml_node config, size_t quota)
:
_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"),
_ldso_ds(ldso_ds),
_rom_modules(_ram_session_client, _md_alloc),
_rom_service(_ep, _md_alloc, _rom_modules),
_nitpicker_service(_ep, _ram_session_client, _md_alloc),
_child(0)
{ }
_env(env), _label(label), _config(config), _ram_quota(quota)
{
/* fetch all parent-provided ROMs according to the config */
config.for_each_sub_node("parent-rom", [&] (Xml_node rom)
{
typedef Rom_module::Name Name;
Name name = rom.attribute_value("name", Name());
_rom_modules.fetch_parent_rom_module(name);
});
}
~Session_component()
{
if (_child)
destroy(&_md_alloc, _child);
_child.destruct();
/*
* 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);
}
_parent_services.for_each([&] (Parent_service &service) {
destroy(env()->heap(), &service); });
}
@ -334,17 +292,17 @@ class Loader::Session_component : public Rpc_object<Session>
void constrain_geometry(Area size) override
{
_nitpicker_service.constrain_geometry(size);
_nitpicker_factory.constrain_geometry(size);
}
void parent_view(Nitpicker::View_capability view) override
{
_nitpicker_service.parent_view(view);
_nitpicker_factory.parent_view(view);
}
void view_ready_sigh(Signal_context_capability sigh) override
{
_nitpicker_service.view_ready_sigh = sigh;
_nitpicker_factory.view_ready_sigh = sigh;
}
void fault_sigh(Signal_context_capability sigh) override
@ -369,22 +327,21 @@ class Loader::Session_component : public Rpc_object<Session>
void start(Name const &binary_name, Name const &label) override
{
if (_child) {
PWRN("cannot start subsystem twice");
if (_child.constructed()) {
warning("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();
size_t const ram_quota = (_subsystem_ram_quota_limit > 0)
? min(_subsystem_ram_quota_limit, _ram_quota)
: _ram_quota;
try {
_child = new (&_md_alloc)
Child(binary_name.string(), label.string(), _ldso_ds,
_ep, _ram_session_client,
ram_quota, _parent_services, _rom_service,
_cpu_service, _pd_service, _nitpicker_service,
_fault_sigh);
_child.construct(_env, binary_name.string(),
prefixed_label(_label, Session_label(label.string())),
ram_quota, _parent_services, _rom_service,
_cpu_service, _pd_service, _nitpicker_service,
_fault_sigh);
}
catch (Genode::Parent::Service_denied) {
throw Rom_module_does_not_exist(); }
@ -406,61 +363,53 @@ class Loader::Root : public Root_component<Session_component>
{
private:
Ram_session &_ram;
Cap_session &_cap;
Dataspace_capability _ldso_ds;
Env &_env;
Xml_node const _config;
protected:
Session_component *_create_session(const char *args)
{
size_t quota =
Arg_string::find_arg(args, "ram_quota").ulong_value(0);
size_t quota = Arg_string::find_arg(args, "ram_quota").ulong_value(0);
return new (md_alloc()) Session_component(quota, _ram, _cap, _ldso_ds);
Xml_node session_config("<policy/>");
Session_label const label = label_from_args(args);
try { session_config = Session_policy(label, _config); }
catch (...) { }
return new (md_alloc()) Session_component(_env, label, session_config, quota);
}
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, Dataspace_capability ldso_ds)
Root(Env &env, Xml_node config, Allocator &md_alloc)
:
Root_component<Session_component>(&session_ep, &md_alloc),
_ram(ram), _cap(cap), _ldso_ds(ldso_ds)
Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc),
_env(env), _config(config)
{ }
};
Genode::Dataspace_capability request_ldso_ds()
namespace Loader { struct Main; }
struct Loader::Main
{
try {
static Genode::Rom_connection rom("ld.lib.so");
return rom.dataspace();
} catch (...) { }
return Genode::Dataspace_capability();
}
Env &env;
Heap heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Root root { env, config.xml(), heap };
Main(Env &env) : env(env)
{
env.parent().announce(env.ep().manage(root));
}
};
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,
request_ldso_ds());
env()->parent()->announce(ep.manage(&root));
sleep_forever();
return 0;
}
void Component::construct(Genode::Env &env) { static Loader::Main main(env); }

View File

@ -39,7 +39,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>
*/
Genode::Signal_context_capability _view_ready_sigh;
Genode::Rpc_entrypoint &_ep;
Genode::Entrypoint &_ep;
Area _max_size;
@ -148,7 +148,7 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>
/**
* Constructor
*/
Session_component(Genode::Rpc_entrypoint &ep,
Session_component(Genode::Entrypoint &ep,
Genode::Ram_session &ram,
Area max_size,
Nitpicker::View_capability parent_view,
@ -166,10 +166,18 @@ class Nitpicker::Session_component : public Genode::Rpc_object<Session>
_view_handle(_nitpicker.create_view(_parent_view_handle)),
_proxy_input(_nitpicker.input_session(), _motion_delta),
_proxy_input_cap(_ep.manage(&_proxy_input)),
_proxy_input_cap(_ep.manage(_proxy_input)),
_command_ds(&ram, sizeof(Command_buffer))
{ }
{
_ep.manage(*this);
}
~Session_component()
{
_ep.dissolve(_proxy_input);
_ep.dissolve(*this);
}
/*********************************

View File

@ -11,20 +11,26 @@
#include <rom_session/rom_session.h>
#include <base/rpc_server.h>
#include <os/attached_ram_dataspace.h>
#include <os/attached_rom_dataspace.h>
namespace Genode {
class Rom_module : public List<Rom_module>::Element
{
public:
typedef String<128> Name;
private:
enum { MAX_NAME_LEN = 64 };
char _name[MAX_NAME_LEN];
Name const _name;
Ram_session &_ram;
Attached_ram_dataspace _fg;
Attached_ram_dataspace _bg;
Lazy_volatile_object<Attached_rom_dataspace> _parent_rom;
bool _bg_has_pending_data;
Signal_context_capability _sigh;
@ -33,20 +39,28 @@ namespace Genode {
public:
Rom_module(char const *name, Ram_session &ram_session)
enum Origin { PARENT_PROVIDED, SESSION_LOCAL };
Rom_module(Env &env, Xml_node config, Name const &name,
Ram_session &ram_session, Origin origin)
:
_ram(ram_session),
_name(name), _ram(ram_session),
_fg(&_ram, 0), _bg(&_ram, 0),
_bg_has_pending_data(false),
_lock(Lock::LOCKED)
{
strncpy(_name, name, sizeof(_name));
if (origin == SESSION_LOCAL)
return;
try {
_parent_rom.construct(env, name.string()); }
catch (...) {
warning("ROM ", name, " unavailable from parent, "
"try to use session-local ROM");
}
}
bool has_name(char const *name) const
{
return strcmp(_name, name) == 0;
}
bool has_name(Name const &name) const { return _name == name; }
void lock() { _lock.lock(); }
void unlock() { _lock.unlock(); }
@ -72,6 +86,9 @@ namespace Genode {
*/
Rom_dataspace_capability fg_dataspace()
{
if (_parent_rom.constructed())
return static_cap_cast<Rom_dataspace>(_parent_rom->cap());
if (!_fg.size() && !_bg_has_pending_data) {
Genode::error("no data loaded");
return Rom_dataspace_capability();
@ -95,7 +112,13 @@ namespace Genode {
*
* This function is indirectly called by the ROM session client.
*/
void sigh(Signal_context_capability sigh) { _sigh = sigh; }
void sigh(Signal_context_capability sigh)
{
if (_parent_rom.constructed())
_parent_rom->sigh(sigh);
_sigh = sigh;
}
/**
* Commit data contained in background dataspace
@ -126,6 +149,8 @@ namespace Genode {
{
private:
Env &_env;
Xml_node const _config;
Lock _lock;
Ram_session &_ram_session;
Allocator &_md_alloc;
@ -145,9 +170,11 @@ namespace Genode {
* module data
* \param md_alloc backing store for ROM module meta data
*/
Rom_module_registry(Ram_session &ram_session, Allocator &md_alloc)
Rom_module_registry(Env &env, Xml_node config, Ram_session &ram_session,
Allocator &md_alloc)
:
_ram_session(ram_session), _md_alloc(md_alloc)
_env(env), _config(config), _ram_session(ram_session),
_md_alloc(md_alloc)
{ }
~Rom_module_registry()
@ -167,7 +194,7 @@ namespace Genode {
*
* \throw Lookup_failed
*/
Rom_module &lookup_and_lock(char const *name)
Rom_module &lookup_and_lock(Rom_module::Name const &name)
{
Lock::Guard guard(_lock);
@ -181,7 +208,7 @@ namespace Genode {
throw Lookup_failed();
}
Dataspace_capability alloc_rom_module(char const *name, size_t size)
Dataspace_capability alloc_rom_module(Rom_module::Name const &name, size_t size)
{
try {
Rom_module &module = lookup_and_lock(name);
@ -193,7 +220,8 @@ namespace Genode {
Lock::Guard guard(_lock);
Rom_module *module = new (&_md_alloc)
Rom_module(name, _ram_session);
Rom_module(_env, _config, name, _ram_session,
Rom_module::SESSION_LOCAL);
Rom_module_lock_guard module_guard(*module);
@ -203,6 +231,25 @@ namespace Genode {
}
}
void fetch_parent_rom_module(Rom_module::Name const &name)
{
try {
lookup_and_lock(name);
}
catch (Lookup_failed) {
Lock::Guard guard(_lock);
Rom_module *module = new (&_md_alloc)
Rom_module(_env, _config, name, _ram_session,
Rom_module::PARENT_PROVIDED);
Rom_module_lock_guard module_guard(*module);
_list.insert(module);
}
}
/**
* \throw Lookup_failed
*/
@ -220,12 +267,15 @@ namespace Genode {
{
private:
Entrypoint &_ep;
Rom_module &_rom_module;
public:
Rom_session_component(Rom_module &rom_module)
: _rom_module(rom_module) { }
Rom_session_component(Entrypoint &ep, Rom_module &rom_module)
: _ep(ep), _rom_module(rom_module) { _ep.manage(*this); }
~Rom_session_component() { _ep.dissolve(*this); }
Rom_dataspace_capability dataspace()
{

View File

@ -691,7 +691,7 @@ class Audio_out::Root : public Audio_out::Root_component
void _destroy_session(Session_component *session)
{
if (--_sessions == 0) _mixer.stop();
destroy(md_alloc(), session);
Genode::destroy(md_alloc(), session);
}
public:

View File

@ -1072,7 +1072,7 @@ class Nitpicker::Root : public Genode::Root_component<Session_component>
session->destroy_all_views();
_mode.forget(*session);
destroy(md_alloc(), session);
Genode::destroy(md_alloc(), session);
}
public:

View File

@ -1,6 +1,7 @@
/*
* \brief Fork bomb to stress Genode
* \author Christian Helmuth
* \author Norman Feske
* \date 2007-08-16
*
* The better part of this code is derived from the original init
@ -8,165 +9,128 @@
*/
/*
* Copyright (C) 2007-2013 Genode Labs GmbH
* Copyright (C) 2007-2016 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.
*/
#include <base/env.h>
#include <base/component.h>
#include <base/child.h>
#include <base/sleep.h>
#include <base/service.h>
#include <base/snprintf.h>
#include <base/attached_rom_dataspace.h>
#include <init/child_policy.h>
#include <ram_session/connection.h>
#include <cpu_session/connection.h>
#include <rom_session/connection.h>
#include <cap_session/connection.h>
#include <pd_session/connection.h>
#include <timer_session/connection.h>
#include <os/config.h>
#include <os/child_policy_dynamic_rom.h>
#include <util/xml_node.h>
using namespace Genode;
class Bomb_child_resources
{
protected:
Genode::Session_label _rom_label;
Genode::Pd_connection _pd;
Genode::Rom_connection _rom;
Genode::Ram_connection _ram;
Genode::Cpu_connection _cpu;
typedef String<32> Name;
Name _name;
Genode::Region_map_client _address_space { _pd.address_space() };
Bomb_child_resources(const char *elf_name, const char *name,
Genode::size_t ram_quota)
:
_rom_label(Genode::prefixed_label(Genode::Session_label(name),
Genode::Session_label(elf_name))),
_pd(name), _rom(_rom_label.string()),
_ram(name), _cpu(name), _name(name)
{
_ram.ref_account(env()->ram_session_cap());
Genode::env()->ram_session()->transfer_quota(_ram.cap(), ram_quota);
if (!_ram.cap().valid() || !_cpu.cap().valid()) {
class Ram_or_cpu_session_not_valid { };
throw Ram_or_cpu_session_not_valid();
}
}
};
class Bomb_child : private Bomb_child_resources,
public Genode::Child_policy,
public Genode::List<Bomb_child>::Element
class Bomb_child : public Child_policy
{
private:
Init::Child_policy_enforce_labeling _enforce_labeling_policy;
Genode::Child::Initial_thread _initial_thread;
Env &_env;
Binary_name const _binary_name;
Name const _label;
size_t const _ram_quota;
/*
* Entry point used for serving the parent interface
*/
enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) };
Genode::Rpc_entrypoint _entrypoint;
enum { STACK_SIZE = 2048 * sizeof(addr_t) };
Rpc_entrypoint _ep { &_env.pd(), STACK_SIZE, "bomb_ep_child", false };
Genode::Child _child;
Genode::Service_registry *_parent_services;
Genode::Child_policy_dynamic_rom_file _config_policy;
Registry<Registered<Parent_service> > &_parent_services;
Init::Child_policy_enforce_labeling _labeling_policy { _label.string() };
Child_policy_dynamic_rom_file _config_policy { "config", _ep, &_env.ram() };
Child _child { _env.rm(), _ep, *this };
public:
Bomb_child(const char *file_name,
const char *unique_name,
Genode::size_t ram_quota,
Cap_session *cap_session,
Service_registry *parent_services,
unsigned generation)
Bomb_child(Env &env,
Name const &binary_name,
Name const &label,
size_t ram_quota,
Registry<Registered<Parent_service> > &parent_services,
unsigned generation)
:
Bomb_child_resources(file_name, unique_name, ram_quota),
_enforce_labeling_policy(_name.string()),
_initial_thread(_cpu, _pd, unique_name),
_entrypoint(cap_session, STACK_SIZE, "bomb_ep_child", false),
_child(_rom.dataspace(), Genode::Dataspace_capability(),
_pd, _pd, _ram, _ram, _cpu, _initial_thread,
*Genode::env()->rm_session(), _address_space, _entrypoint, *this),
_parent_services(parent_services),
_config_policy("config", _entrypoint, &_ram)
_env(env), _binary_name(binary_name), _label(label),
_ram_quota(Child::effective_ram_quota(ram_quota)),
_parent_services(parent_services)
{
char client_config[64];
snprintf(client_config, sizeof(client_config),
"<config generations=\"%u\"/>", generation);
_config_policy.load(client_config, strlen(client_config) + 1);
_entrypoint.activate();
String<64> config("<config generations=\"", generation, "\"/>");
_config_policy.load(config.string(), config.length());
_ep.activate();
}
~Bomb_child() { Genode::log(__PRETTY_FUNCTION__); }
~Bomb_child() { log(__PRETTY_FUNCTION__); }
/****************************
** Child-policy interface **
****************************/
const char *name() const { return Bomb_child_resources::_name.string(); }
Name name() const override { return _label; }
void filter_session_args(const char * x, char *args, Genode::size_t args_len)
Binary_name binary_name() const override { return _binary_name; }
void init(Ram_session &ram, Ram_session_capability ram_cap) override
{
_enforce_labeling_policy.filter_session_args(0, args, args_len);
ram.ref_account(_env.ram_session_cap());
_env.ram().transfer_quota(ram_cap, _ram_quota);
}
Service *resolve_session_request(const char *service_name,
const char *args)
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void filter_session_args(Service::Name const &,
char *args, size_t args_len) override
{
Service * service = nullptr;
_labeling_policy.filter_session_args(nullptr, args, args_len);
}
Service &resolve_session_request(Service::Name const &service_name,
Session_state::Args const &args) override
{
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;
return _parent_services->find(service_name);
_parent_services.for_each([&] (Service &s) {
if (!service && service_name == s.name())
service = &s; });
if (!service)
throw Parent::Service_denied();
return *service;
}
};
/*
* List of children
*
* Access to the children list from different threads
* must be synchronized via the children lock.
*/
static Lock _children_lock;
static List<Bomb_child> _children;
typedef Registry<Registered<Bomb_child> > Children;
/**
* Check if a program with the specified name already exists
*/
static bool child_name_exists(const char *name)
static bool child_name_exists(Children const &children,
Bomb_child::Name const &name)
{
Bomb_child *c = _children.first();
bool found = false;
for ( ; c; c = c->List<Bomb_child>::Element::next())
if (strcmp(c->name(), name) == 0)
return true;
children.for_each([&] (Bomb_child const &child) {
if (!found && child.name() == name)
found = true; });
return false;
return found;
}
@ -176,80 +140,28 @@ static bool child_name_exists(const char *name)
* If a program with the filename as name already exists, we
* add a counting number as suffix.
*/
static void get_unique_child_name(const char *filename, char *dst,
size_t dst_len, unsigned generation)
static Bomb_child::Name
unique_child_name(Children const &children, Bomb_child::Name const &binary_name,
unsigned const generation)
{
Lock::Guard lock_guard(_children_lock);
/* serialize calls to this function */
static Lock lock;
Lock::Guard guard(lock);
char buf[32];
char suffix[8];
suffix[0] = 0;
for (int cnt = 1; true; cnt++) {
/* build program name composed of filename and numeric suffix */
snprintf(buf, sizeof(buf), "%s_g%u%s", filename, generation, suffix);
for (unsigned cnt = 1; ; cnt++) {
/* if such a program name does not exist yet, we are happy */
if (!child_name_exists(buf)) {
strncpy(dst, buf, dst_len);
return;
}
/* increase number of suffix */
snprintf(suffix, sizeof(suffix), ".%d", cnt + 1);
Bomb_child::Name const unique(binary_name, "_g", generation, ".", cnt);
if (!child_name_exists(children, unique.string()))
return unique;
}
}
/**
* Start a child
*/
static int start_child(const char *file_name, Cap_session *cap_session,
size_t ram_quota, Service_registry *parent_services,
unsigned generation)
void Component::construct(Genode::Env &env)
{
char name[64];
get_unique_child_name(file_name, name, sizeof(name), generation);
Bomb_child *c = new (env()->heap())
Bomb_child(file_name, name, ram_quota, cap_session, parent_services,
generation);
Lock::Guard lock_guard(_children_lock);
_children.insert(c);
return 0;
}
/**
* Kill child
*/
static void exit_child(Bomb_child *child)
{
destroy(env()->heap(), child);
}
/**
* Request timer service
*
* \return timer session, or 0 if bomb is our parent
*/
Timer::Session *timer()
{
try {
static Timer::Connection timer_inst;
return &timer_inst;
} catch (Parent::Service_denied) { }
return 0;
}
int main(int argc, char **argv)
{
Genode::Xml_node node = config()->xml_node();
static Attached_rom_dataspace config(env, "config");
Xml_node node = config.xml();
unsigned const rounds = node.attribute_value("rounds", 1U);
unsigned const generation = node.attribute_value("generations", 1U);
@ -258,23 +170,26 @@ int main(int argc, char **argv)
unsigned long const demand = node.attribute_value("demand", 1024UL * 1024);
log("--- bomb started ---");
if (timer())
/* try to create timer session, if it fails, bomb is our parent */
static Lazy_volatile_object<Timer::Connection> timer;
try { timer.construct(env); } catch (Parent::Service_denied) { }
if (timer.constructed())
log("rounds=", rounds, " generations=", generation, " children=",
children, " sleep=", sleeptime, " demand=", demand/1024, "K");
/* connect to core's cap service used for creating parent capabilities */
Cap_connection cap;
/* names of services provided by the parent */
static const char *names[] = {
"CAP", "RAM", "RM", "PD", "CPU", "ROM", "LOG", 0 };
"RAM", "PD", "CPU", "ROM", "LOG", 0 };
static Service_registry parent_services;
static Heap heap(env.ram(), env.rm());
static Registry<Registered<Parent_service> > parent_services;
for (unsigned i = 0; names[i]; i++)
parent_services.insert(new (env()->heap()) Parent_service(names[i]));
new (heap) Registered<Parent_service>(parent_services, names[i]);
unsigned long avail = env()->ram_session()->avail();
unsigned long avail = env.ram().avail();
unsigned long amount = (avail - demand) / children;
if (amount < (demand * children)) {
log("I'm a leaf node - generation ", generation, " - not enough memory.");
@ -285,43 +200,42 @@ int main(int argc, char **argv)
sleep_forever();
}
static Children child_registry;
Bomb_child::Name const binary_name("bomb");
for (unsigned round = 0; round < rounds ; ++round) {
for (unsigned i = children; i; --i)
start_child("bomb", &cap, amount, &parent_services, generation - 1);
for (unsigned i = children; i; --i) {
new (heap)
Registered<Bomb_child>(child_registry, env, binary_name,
unique_child_name(child_registry, binary_name,
generation - 1),
amount, parent_services, generation - 1);
}
/* is init our parent? */
if (!timer()) sleep_forever();
if (!timer.constructed()) sleep_forever();
/* don't ask parent for further resources if we ran out of memory */
static Signal_receiver sig_rec;
static Signal_context sig_ctx_res_avail;
if (round == 0) {
/* prevent to block for resource upgrades caused by clients */
env()->parent()->resource_avail_sigh(sig_rec.manage(&sig_ctx_res_avail));
env.parent().resource_avail_sigh(sig_rec.manage(&sig_ctx_res_avail));
}
timer()->msleep(sleeptime);
timer->msleep(sleeptime);
log("[", round, "] It's time to kill all my children...");
while (1) {
Bomb_child *c;
_children_lock.lock();
c = _children.first();
if (c) _children.remove(c);
_children_lock.unlock();
if (c) exit_child(c);
else break;
}
child_registry.for_each([&] (Registered<Bomb_child> &child) {
destroy(heap, &child); });
log("[", round, "] Done.");
}
/* master if we have a timer connection */
if (timer())
if (timer.constructed())
log("Done. Going to sleep");
sleep_forever();
return 0;
}

View File

@ -5,63 +5,78 @@
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
* Copyright (C) 2012-2016 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/component.h>
#include <os/slave.h>
#include <timer_session/connection.h>
#include <cap_session/connection.h>
struct Test_slave_policy : Genode::Slave_policy
namespace Test {
using namespace Genode;
struct Policy;
struct Main;
}
struct Test::Policy : Genode::Slave::Policy
{
const char **_permitted_services() const
{
static const char *permitted_services[] = {
"RM", "LOG", 0 };
"CPU", "RAM", "ROM", "PD", "LOG", 0 };
return permitted_services;
};
Test_slave_policy(char const *name, Genode::Rpc_entrypoint &ep)
: Genode::Slave_policy(name, ep, Genode::env()->ram_session())
Policy(Genode::Env &env, Name const &name)
:
Genode::Slave::Policy(name, name, env.ep().rpc_ep(), env.rm(),
env.ram_session_cap(), 1024*1024)
{ }
};
int main(int, char **)
struct Test::Main
{
using namespace Genode;
Env &_env;
enum { STACK_SIZE = 2*4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "slave_ep");
Policy _policy { _env, "test-dynamic_config" };
static Test_slave_policy slave_policy("test-dynamic_config", ep);
unsigned _cnt = 0;
/* define initial config for slave */
slave_policy.configure("<config><counter>-1</counter></config>");
static Genode::Slave slave(ep, slave_policy, 768*1024);
/* update slave config at regular intervals */
int counter = 0;
for (;;) {
static Timer::Connection timer;
timer.msleep(250);
/* re-generate configuration */
char buf[100];
Genode::snprintf(buf, sizeof(buf),
"<config><counter>%d</counter></config>",
counter++);
slave_policy.configure(buf);
void _configure()
{
String<256> const config("<config><counter>", _cnt, "</counter></config>");
_policy.configure(config.string());
_cnt++;
}
return 0;
}
Child _child { _env.rm(), _env.ep().rpc_ep(), _policy };
Timer::Connection timer { _env };
Signal_handler<Main> _timeout_handler { _env.ep(), *this, &Main::_handle_timeout };
void _handle_timeout() { _configure(); }
Main(Env &env) : _env(env)
{
/* update slave config at regular intervals */
timer.sigh(_timeout_handler);
timer.trigger_periodic(250*1000);
/* define initial config for slave before returning to entrypoint */
_configure();
}
};
void Component::construct(Genode::Env &env) { static Test::Main main(env); }

View File

@ -5,110 +5,91 @@
*/
/*
* Copyright (C) 2008-2013 Genode Labs GmbH
* Copyright (C) 2008-2016 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.
*/
#include <base/log.h>
#include <base/env.h>
#include <base/sleep.h>
#include <base/component.h>
#include <base/child.h>
#include <ram_session/connection.h>
#include <rom_session/connection.h>
#include <cpu_session/connection.h>
#include <cap_session/connection.h>
#include <pd_session/connection.h>
#include <log_session/log_session.h>
#include <loader_session/connection.h>
#include <region_map/client.h>
using namespace Genode;
/***************
** Utilities **
***************/
static void wait_for_signal_for_context(Genode::Signal_receiver &sig_rec,
Genode::Signal_context const &sig_ctx)
template <typename TEST>
class Iterative_test
{
Genode::Signal s = sig_rec.wait_for_signal();
public:
if (s.num() && s.context() == &sig_ctx) {
Genode::log("got exception for child");
} else {
Genode::error("got unexpected signal while waiting for child");
class Unexpected_signal { };
throw Unexpected_signal();
}
}
private:
Env &_env;
Signal_context_capability _finished_sigh;
unsigned const _cnt_max = 5;
unsigned _cnt = 0;
Signal_handler<Iterative_test> _fault_handler {
_env.ep(), *this, &Iterative_test::_handle_fault };
TEST _test;;
void _handle_fault()
{
if (_cnt++ >= _cnt_max) {
Signal_transmitter(_finished_sigh).submit();
log("-- finished ", _test.name(), " --");
return;
}
_test.start_iteration(_env, _fault_handler);
}
public:
Iterative_test(Env &env, Signal_context_capability finished_sigh)
:
_env(env), _finished_sigh(finished_sigh)
{
log("-- exercise ", _test.name(), " --");
_test.start_iteration(_env, _fault_handler);
}
};
/******************************************************************
** Test for detecting the failure of an immediate child process **
******************************************************************/
/********************************************************************
** Test for detecting the failure of an immediate child component **
********************************************************************/
class Test_child : public Genode::Child_policy
{
private:
struct Resources
{
Genode::Pd_connection pd;
Genode::Ram_connection ram;
Genode::Cpu_connection cpu;
Resources(Genode::Signal_context_capability sigh, char const *label)
: pd(label)
{
using namespace Genode;
/* transfer some of our own ram quota to the new child */
enum { CHILD_QUOTA = 1*1024*1024 };
ram.ref_account(env()->ram_session_cap());
env()->ram_session()->transfer_quota(ram.cap(), CHILD_QUOTA);
/* register default exception handler */
cpu.exception_sigh(sigh);
/* register handler for unresolvable page faults */
Region_map_client address_space(pd.address_space());
address_space.fault_handler(sigh);
}
} _resources;
Genode::Child::Initial_thread _initial_thread;
/*
* The order of the following members is important. The services must
* appear before the child to ensure the correct order of destruction.
* I.e., the services must remain alive until the child has stopped
* executing. Otherwise, the child may hand out already destructed
* local services when dispatching an incoming session call.
*/
Genode::Rom_connection _elf;
Genode::Parent_service _log_service;
Genode::Parent_service _rm_service;
Genode::Region_map_client _address_space { _resources.pd.address_space() };
Genode::Child _child;
Env &_env;
size_t const _ram_quota = 1024*1024;
Binary_name const _binary_name;
Signal_context_capability _sigh;
Parent_service _cpu_service { _env, Cpu_session::service_name() };
Parent_service _ram_service { _env, Ram_session::service_name() };
Parent_service _pd_service { _env, Pd_session::service_name() };
Parent_service _log_service { _env, Log_session::service_name() };
Parent_service _rom_service { _env, Rom_session::service_name() };
Child _child;
public:
/**
* Constructor
*/
Test_child(Genode::Rpc_entrypoint &ep,
char const *elf_name,
Test_child(Env &env, Name const &binary_name,
Genode::Signal_context_capability sigh)
:
_resources(sigh, elf_name),
_initial_thread(_resources.cpu, _resources.pd, elf_name),
_elf(elf_name),
_log_service("LOG"), _rm_service("RM"),
_child(_elf.dataspace(), Genode::Dataspace_capability(),
_resources.pd, _resources.pd,
_resources.ram, _resources.ram,
_resources.cpu, _initial_thread,
*Genode::env()->rm_session(), _address_space, ep, *this)
_env(env), _binary_name(binary_name), _sigh(sigh),
_child(_env.rm(), _env.ep().rpc_ep(), *this)
{ }
@ -116,138 +97,102 @@ class Test_child : public Genode::Child_policy
** Child-policy interface **
****************************/
const char *name() const { return "child"; }
Name name() const override { return "child"; }
Genode::Service *resolve_session_request(const char *service, const char *)
Binary_name binary_name() const override { return _binary_name; }
Ram_session &ref_ram() override { return _env.ram(); }
Ram_session_capability ref_ram_cap() const override { return _env.ram_session_cap(); }
void init(Ram_session &ram, Ram_session_capability ram_cap) override
{
/* forward white-listed session requests to our parent */
return !Genode::strcmp(service, "LOG") ? &_log_service
: !Genode::strcmp(service, "RM") ? &_rm_service
: 0;
ram.ref_account(ref_ram_cap());
ref_ram().transfer_quota(ram_cap, _ram_quota);
}
void filter_session_args(const char *service,
char *args, Genode::size_t args_len)
void init(Cpu_session &cpu, Cpu_session_capability) override
{
/* define session label for sessions forwarded to our parent */
Genode::Arg_string::set_arg_string(args, args_len, "label", "child");
/* register default exception handler */
cpu.exception_sigh(_sigh);
}
void init(Pd_session &pd, Pd_session_capability) override
{
/* register handler for unresolvable page faults */
Region_map_client address_space(pd.address_space());
address_space.fault_handler(_sigh);
}
Service &resolve_session_request(Service::Name const &service,
Session_state::Args const &args) override
{
if (service == Cpu_session::service_name()) return _cpu_service;
if (service == Ram_session::service_name()) return _ram_service;
if (service == Pd_session::service_name()) return _pd_service;
if (service == Log_session::service_name()) return _log_service;
if (service == Rom_session::service_name()) return _rom_service;
throw Parent::Service_denied();
}
void filter_session_args(Service::Name const &,
char *args, size_t args_len) override
{
/* prefix session label */
Session_label const orig(label_from_args(args));
Arg_string::set_arg_string(args, args_len, "label",
prefixed_label(name(), orig).string());
}
};
void faulting_child_test()
struct Faulting_child_test
{
using namespace Genode;
static char const *name() { return "failure detection in immediate child"; }
log("-- exercise failure detection of immediate child --");
Lazy_volatile_object<Test_child> _child;
/*
* Entry point used for serving the parent interface
*/
enum { STACK_SIZE = 8*1024 };
Cap_connection cap;
Rpc_entrypoint ep(&cap, STACK_SIZE, "child");
/*
* Signal receiver and signal context for signals originating from the
* children's CPU-session and RM session.
*/
Signal_receiver sig_rec;
Signal_context sig_ctx;
/*
* Iteratively start a faulting program and detect the faults
*/
for (int i = 0; i < 5; i++) {
log("create child ", i);
/* create and start child process */
Test_child child(ep, "test-segfault", sig_rec.manage(&sig_ctx));
log("wait_for_signal");
wait_for_signal_for_context(sig_rec, sig_ctx);
sig_rec.dissolve(&sig_ctx);
/*
* When finishing the loop iteration, the local variables including
* 'child' will get destructed. A new child will be created at the
* beginning of the next iteration.
*/
void start_iteration(Env &env, Signal_context_capability fault_sigh)
{
_child.construct(env, "test-segfault", fault_sigh);
}
log("");
}
};
/******************************************************************
** Test for detecting failures in a child started by the loader **
******************************************************************/
void faulting_loader_child_test()
struct Faulting_loader_child_test
{
using namespace Genode;
static char const *name() { return "failure detection in loaded child"; }
log("-- exercise failure detection of loaded child --");
Lazy_volatile_object<Loader::Connection> loader;
/*
* Signal receiver and signal context for receiving faults originating from
* the loader subsystem.
*/
static Signal_receiver sig_rec;
Signal_context sig_ctx;
for (int i = 0; i < 5; i++) {
log("create loader session ", i);
Loader::Connection loader(1024*1024);
void start_iteration(Env &env, Signal_context_capability fault_sigh)
{
loader.construct(env, 1024*1024);
/* register fault handler at loader session */
loader.fault_sigh(sig_rec.manage(&sig_ctx));
loader->fault_sigh(fault_sigh);
/* start subsystem */
loader.start("test-segfault");
wait_for_signal_for_context(sig_rec, sig_ctx);
sig_rec.dissolve(&sig_ctx);
loader->start("test-segfault");
}
log("");
}
};
/***********************************************************************
** Test for detecting failures in a grandchild started by the loader **
***********************************************************************/
void faulting_loader_grand_child_test()
struct Faulting_loader_grand_child_test
{
using namespace Genode;
static char const *name() { return "failure detection of loaded grand child"; }
log("-- exercise failure detection of loaded grand child --");
/*
* Signal receiver and signal context for receiving faults originating from
* the loader subsystem.
*/
static Signal_receiver sig_rec;
Signal_context sig_ctx;
for (int i = 0; i < 5; i++) {
log("create loader session ", i);
Loader::Connection loader(2024*1024);
/*
* Install init config for subsystem into the loader session
*/
char const *config =
static char const *config()
{
return
"<config>\n"
" <parent-provides>\n"
" <service name=\"ROM\"/>\n"
@ -261,50 +206,74 @@ void faulting_loader_grand_child_test()
" <resource name=\"RAM\" quantum=\"10M\"/>\n"
" </start>\n"
"</config>";
size_t config_size = strlen(config);
Dataspace_capability config_ds =
loader.alloc_rom_module("config", config_size);
char *config_ds_addr = env()->rm_session()->attach(config_ds);
memcpy(config_ds_addr, config, config_size);
env()->rm_session()->detach(config_ds_addr);
loader.commit_rom_module("config");
/* register fault handler at loader session */
loader.fault_sigh(sig_rec.manage(&sig_ctx));
/* start subsystem */
loader.start("init", "init");
wait_for_signal_for_context(sig_rec, sig_ctx);
sig_rec.dissolve(&sig_ctx);
}
log("");
}
static size_t config_size() { return strlen(config()); }
Lazy_volatile_object<Loader::Connection> loader;
void start_iteration(Env &env, Signal_context_capability fault_sigh)
{
loader.construct(env, 2*1024*1024);
/* import config into loader session */
{
Attached_dataspace ds(loader->alloc_rom_module("config", config_size()));
memcpy(ds.local_addr<char>(), config(), config_size());
loader->commit_rom_module("config");
}
/* register fault handler at loader session */
loader->fault_sigh(fault_sigh);
/* start subsystem */
loader->start("init", "init");
}
};
/******************
** Main program **
******************/
int main(int argc, char **argv)
struct Main
{
using namespace Genode;
Env &_env;
log("--- fault_detection test started ---");
Lazy_volatile_object<Iterative_test<Faulting_child_test> > _test_1;
Lazy_volatile_object<Iterative_test<Faulting_loader_child_test> > _test_2;
Lazy_volatile_object<Iterative_test<Faulting_loader_grand_child_test> > _test_3;
faulting_child_test();
Signal_handler<Main> _test_1_finished_handler {
_env.ep(), *this, &Main::_handle_test_1_finished };
faulting_loader_child_test();
Signal_handler<Main> _test_2_finished_handler {
_env.ep(), *this, &Main::_handle_test_2_finished };
faulting_loader_grand_child_test();
Signal_handler<Main> _test_3_finished_handler {
_env.ep(), *this, &Main::_handle_test_3_finished };
log("--- finished fault_detection test ---");
return 0;
}
void _handle_test_1_finished()
{
_test_1.destruct();
_test_2.construct(_env, _test_2_finished_handler);
}
void _handle_test_2_finished()
{
_test_2.destruct();
_test_3.construct(_env, _test_3_finished_handler);
}
void _handle_test_3_finished()
{
_test_3.destruct();
log("--- finished fault_detection test ---");
_env.parent().exit(0);
}
Main(Env &env) : _env(env)
{
_test_1.construct(_env, _test_1_finished_handler);
}
};
void Component::construct(Env &env) { static Main main(env); }

View File

@ -12,6 +12,7 @@
*/
#include <base/log.h>
#include <base/component.h>
#include <os/reporter.h>
#include <os/attached_rom_dataspace.h>
#include <timer_session/connection.h>
@ -20,7 +21,7 @@
#define ASSERT(cond) \
if (!(cond)) { \
Genode::error("assertion ", #cond, " failed"); \
return -2; }
throw -2; }
static void report_brightness(Genode::Reporter &reporter, int value)
@ -30,7 +31,7 @@ static void report_brightness(Genode::Reporter &reporter, int value)
}
int main(int argc, char **argv)
void Component::construct(Genode::Env &env)
{
using namespace Genode;
@ -70,7 +71,7 @@ int main(int argc, char **argv)
brightness_reporter.enabled(false);
/* give report_rom some time to close the report session */
static Timer::Connection timer;
Timer::Connection timer;
timer.msleep(250);
brightness_rom.update();
@ -89,7 +90,7 @@ int main(int argc, char **argv)
Reporter again("brightness");
again.enabled(true);
error("expected Service_denied");
return -3;
throw -3;
} catch (Genode::Parent::Service_denied) {
log("ROM client: catched Parent::Service_denied - OK");
}
@ -98,5 +99,5 @@ int main(int argc, char **argv)
sig_rec.dissolve(&sig_ctx);
return 0;
env.parent().exit(0);
}

View File

@ -27,11 +27,11 @@
/* Genode includes */
#include <util/arg_string.h>
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <base/log.h>
#include <base/signal.h>
#include <cap_session/connection.h>
#include <timer_session/connection.h>
#include <os/config.h>
#include <os/slave.h>
@ -51,32 +51,31 @@ class Child
struct Ram_chunk : Genode::List<Ram_chunk>::Element
{
Genode::Env &env;
size_t const size;
Genode::Ram_dataspace_capability ds_cap;
Ram_chunk(size_t size)
Ram_chunk(Genode::Env &env, size_t size)
:
size(size),
ds_cap(Genode::env()->ram_session()->alloc(size))
env(env),size(size), ds_cap(env.ram().alloc(size))
{ }
~Ram_chunk()
{
Genode::env()->ram_session()->free(ds_cap);
}
~Ram_chunk() { env.ram().free(ds_cap); }
};
bool const _expand;
Genode::List<Ram_chunk> _ram_chunks;
Timer::Connection _timer;
Genode::Signal_receiver _sig_rec;
Genode::Signal_dispatcher<Child> _periodic_timeout_dispatcher;
Genode::Signal_dispatcher<Child> _yield_dispatcher;
unsigned long const _period_ms;
Genode::Env &_env;
Genode::Heap _heap { _env.ram(), _env.rm() };
bool const _expand;
Genode::List<Ram_chunk> _ram_chunks;
Timer::Connection _timer { _env };
Genode::Signal_handler<Child> _periodic_timeout_handler;
Genode::Signal_handler<Child> _yield_handler;
unsigned long const _period_ms;
void _dispatch_periodic_timeout(unsigned);
void _dispatch_yield(unsigned);
void _handle_periodic_timeout();
void _handle_yield();
void _schedule_next_timeout()
{
@ -85,16 +84,16 @@ class Child
public:
Child();
Child(Genode::Env &, Genode::Xml_node);
void main();
};
void Child::_dispatch_periodic_timeout(unsigned)
void Child::_handle_periodic_timeout()
{
size_t const chunk_size = 1024*1024;
if (Genode::env()->ram_session()->avail() < chunk_size) {
if (_env.ram().avail() < chunk_size) {
if (_expand) {
Genode::log("quota consumed, request additional resources");
@ -112,7 +111,7 @@ void Child::_dispatch_periodic_timeout(unsigned)
}
/* perform allocation and remember chunk in list */
_ram_chunks.insert(new (Genode::env()->heap()) Ram_chunk(chunk_size));
_ram_chunks.insert(new (_heap) Ram_chunk(_env, chunk_size));
Genode::log("allocated chunk of ", chunk_size / 1024, " KiB");
@ -120,12 +119,12 @@ void Child::_dispatch_periodic_timeout(unsigned)
}
void Child::_dispatch_yield(unsigned)
void Child::_handle_yield()
{
using namespace Genode;
/* request yield request arguments */
Parent::Resource_args const args = env()->parent()->yield_request();
Parent::Resource_args const args = _env.parent().yield_request();
log("yield request: ", args.string());
@ -144,63 +143,37 @@ void Child::_dispatch_yield(unsigned)
size_t const chunk_size = chunk->size;
_ram_chunks.remove(chunk);
destroy(env()->heap(), chunk);
destroy(_heap, chunk);
released_quota += chunk_size;
log("released chunk of ", chunk_size, " bytes");
}
/* acknowledge yield request */
env()->parent()->yield_response();
_env.parent().yield_response();
_schedule_next_timeout();
}
static inline unsigned long read_period_ms_from_config()
{
unsigned long period_ms = 500;
if (Genode::config()->xml_node().has_attribute("period_ms"))
Genode::config()->xml_node().attribute("period_ms").value(&period_ms);
return period_ms;
}
Child::Child()
Child::Child(Genode::Env &env, Genode::Xml_node config)
:
_expand(Genode::config()->xml_node().attribute_value("expand", false)),
_periodic_timeout_dispatcher(_sig_rec, *this,
&Child::_dispatch_periodic_timeout),
_yield_dispatcher(_sig_rec, *this,
&Child::_dispatch_yield),
_period_ms(read_period_ms_from_config())
_env(env),
_expand(config.attribute_value("expand", false)),
_periodic_timeout_handler(_env.ep(), *this, &Child::_handle_periodic_timeout),
_yield_handler(_env.ep(), *this, &Child::_handle_yield),
_period_ms(config.attribute_value("period_ms", 500UL))
{
/* register yield signal handler */
Genode::env()->parent()->yield_sigh(_yield_dispatcher);
_env.parent().yield_sigh(_yield_handler);
/* register timeout signal handler and schedule periodic timeouts */
_timer.sigh(_periodic_timeout_dispatcher);
_timer.sigh(_periodic_timeout_handler);
_schedule_next_timeout();
}
void Child::main()
{
using namespace Genode;
for (;;) {
Signal sig = _sig_rec.wait_for_signal();
Signal_dispatcher_base *dispatcher =
dynamic_cast<Signal_dispatcher_base *>(sig.context());
if (dispatcher)
dispatcher->dispatch(sig.num());
}
}
/*****************
** Parent role **
*****************/
@ -209,48 +182,100 @@ void Child::main()
* The parent grants resource requests as long as it has free resources.
* Once in a while, it politely requests the child to yield resources.
*/
class Parent : Genode::Slave_policy
class Parent : Genode::Slave::Policy
{
private:
/**
* Return singleton entrypoint instance
*
* The entrypoint cannot be a regular member because we need to pass
* it into the constructor of the 'Slave_policy' base class.
*/
static Genode::Rpc_entrypoint &_entrypoint();
Genode::Env &_env;
typedef Genode::size_t size_t;
size_t const slave_quota = 10*1024*1024;
enum { SLAVE_QUOTA = 10*1024*1024 };
Genode::Slave _slave = { _entrypoint(), *this, slave_quota };
Genode::Child _child = { _env.rm(), _env.ep().rpc_ep(), *this };
Timer::Connection _timer;
Timer::Connection _timer { _env };
Genode::Lock _yield_blockade;
void _print_status()
{
Genode::log("quota: ", _slave.ram().quota() / 1024, " KiB "
"used: ", _slave.ram().used() / 1024, " KiB");
Genode::log("quota: ", _child.ram().quota() / 1024, " KiB "
"used: ", _child.ram().used() / 1024, " KiB");
}
size_t _used_ram_prior_yield = 0;
/* perform the test three times */
unsigned _cnt = 3;
unsigned const _wait_secs = 5;
unsigned _wait_cnt = 0;
enum State { WAIT, YIELD_REQUESTED, YIELD_GOT_RESPONSE };
State _state = WAIT;
void _schedule_one_second_timeout()
{
Genode::log("wait ", _wait_cnt, "/", _wait_secs);
_timer.trigger_once(1000*1000);
}
void _init()
{
_state = WAIT;
_wait_cnt = 0;
_schedule_one_second_timeout();
}
void _request_yield()
{
/* remember quantum of resources used by the child */
_used_ram_prior_yield = _child.ram().used();
Genode::log("request yield (ram prior yield: ", _used_ram_prior_yield);
/* issue yield request */
Genode::Parent::Resource_args yield_args("ram_quota=5M");
_child.yield(yield_args);
_state = YIELD_REQUESTED;
}
void _handle_timeout()
{
_print_status();
_wait_cnt++;
if (_wait_cnt >= _wait_secs) {
_request_yield();
} else {
_schedule_one_second_timeout();
}
}
Genode::Signal_handler<Parent> _timeout_handler {
_env.ep(), *this, &Parent::_handle_timeout };
public:
class Insufficient_yield { };
/**
* Constructor
*/
Parent()
Parent(Genode::Env &env)
:
Genode::Slave_policy("test-resource_yield", _entrypoint(),
Genode::env()->ram_session())
Genode::Slave::Policy(Label(), "test-resource_yield", env.ep().rpc_ep(),
env.rm(), env.ram_session_cap(), SLAVE_QUOTA),
_env(env)
{
configure("<config child=\"yes\" />");
_timer.sigh(_timeout_handler);
_init();
}
int main();
/****************************
** Slave_policy interface **
@ -258,95 +283,39 @@ class Parent : Genode::Slave_policy
char const **_permitted_services() const
{
static char const *services[] = { "RM", "LOG", "Timer" };
static char const *services[] = { "RAM", "PD", "CPU", "ROM", "LOG", "Timer" };
return services;
}
void yield_response()
{
_yield_blockade.unlock();
Genode::log("got yield response");
_state = YIELD_GOT_RESPONSE;
/*
* At this point, the ownership of '_yield_blockade' will be passed
* to the main program. By trying to aquire it here, we block until
* the main program is ready.
*
* This way, we ensure that the main program validates the
* statistics before the 'yield_response' RPC call returns.
* Otherwise, the child might allocate new resources before the
* main program is able to see the amount of yielded resources.
*/
Genode::Lock::Guard guard(_yield_blockade);
_print_status();
/* validate that the amount of yielded resources matches the request */
size_t const used_after_yield = _child.ram().used();
if (used_after_yield + 5*1024*1024 > _used_ram_prior_yield) {
Genode::error("child has not yielded enough resources");
throw Insufficient_yield();
}
if (_cnt-- > 0) {
_init();
} else {
Genode::log("--- test-resource_yield finished ---");
_env.parent().exit(0);
}
}
};
Genode::Rpc_entrypoint &Parent::_entrypoint()
{
using namespace Genode;
static Cap_connection cap;
size_t const stack_size = sizeof(addr_t)*2*1024;
static Rpc_entrypoint ep(&cap, stack_size, "ep", false);
return ep;
}
/***************
** Component **
***************/
int Parent::main()
{
using namespace Genode;
_entrypoint().activate();
/* perform the test three times */
for (unsigned j = 0; j < 3; j++) {
/* wait five seconds and observe growth of resource usage */
for (unsigned i = 0; i < 5; i++) {
_timer.msleep(1000);
_print_status();
}
/* remember quantum of resources used by the child */
size_t const used_prior_yield = _slave.ram().used();
/* issue yield request */
Genode::Parent::Resource_args yield_args("ram_quota=5M");
_slave.yield(yield_args);
/*
* Synchronously wait for a yield response. Note that a careful parent
* would never trust its child to comply to the yield request.
*/
log("wait for yield response");
_yield_blockade.lock();
_yield_blockade.lock();
log("got yield response");
_print_status();
/* validate that the amount of yielded resources matches the request */
size_t const used_after_yield = _slave.ram().used();
if (used_after_yield + 5*1024*1024 > used_prior_yield) {
error("child has not yielded enough resources");
return -1;
}
/* let the 'yield_response' RPC call return */
_yield_blockade.unlock();
}
log("--- test-resource_yield finished ---");
return 0;
}
/******************
** Main program **
******************/
int main(int argc, char **argv)
void Component::construct(Genode::Env &env)
{
using namespace Genode;
@ -354,17 +323,14 @@ int main(int argc, char **argv)
* Read value '<config child="" />' attribute to decide whether to perform
* the child or the parent role.
*/
bool const is_child = config()->xml_node().has_attribute("child")
&& config()->xml_node().attribute_value("child", false);
static Attached_rom_dataspace config(env, "config");
bool const is_child = config.xml().attribute_value("child", false);
if (is_child) {
log("--- test-resource_yield child role started ---");
static ::Child child;
child.main();
return -1; /* the child should never reach this point */
static ::Child child(env, config.xml());
} else {
log("--- test-resource_yield parent role started ---");
static ::Parent parent;
return parent.main();
static ::Parent parent(env);
}
}

View File

@ -11,12 +11,13 @@
* under the terms of the GNU General Public License version 2.
*/
#include <base/component.h>
#include <base/heap.h>
#include <base/log.h>
#include <base/signal.h>
#include <base/sleep.h>
#include <base/thread.h>
#include <timer_session/connection.h>
#include <cap_session/connection.h>
#include <util/misc_math.h>
using namespace Genode;
@ -25,17 +26,17 @@ using namespace Genode;
/**
* Transmit signals in a periodic fashion
*/
class Sender : Thread_deprecated<4096>
class Sender : Thread
{
private:
Signal_transmitter _transmitter;
Timer::Connection _timer; /* timer connection for local use */
unsigned _interval_ms; /* interval between signals in milliseconds */
Signal_transmitter _transmitter;
unsigned const _interval_ms; /* interval between signals in milliseconds */
bool _stop; /* state for destruction protocol */
unsigned _submit_cnt; /* statistics */
bool _idle; /* suppress the submission of signals */
bool _verbose; /* print activities */
bool const _verbose; /* print activities */
/**
* Sender thread submits signals every '_interval_ms' milliseconds
@ -68,10 +69,11 @@ class Sender : Thread_deprecated<4096>
* \param interval_ms interval between signals
* \param verbose print status information
*/
Sender(Signal_context_capability context,
Sender(Env &env, Signal_context_capability context,
unsigned interval_ms, bool verbose = true)
:
Thread_deprecated("sender"),
Thread(env, "sender", 4096*sizeof(long)),
_timer(env),
_transmitter(context),
_interval_ms(interval_ms),
_stop(false),
@ -110,20 +112,20 @@ class Sender : Thread_deprecated<4096>
/**
* Signal handler receives signals and takes some time to handle each
*/
class Handler : Thread_deprecated<4096>
class Handler : Thread
{
private:
unsigned _dispatch_ms; /* time needed for dispatching a signal */
unsigned _id; /* unique ID of signal handler for debug output */
static unsigned _id_cnt; /* counter for producing unique IDs */
Signal_receiver *_receiver; /* signal endpoint */
Timer::Connection _timer; /* timer connection for local use */
unsigned const _dispatch_ms; /* time needed for dispatching a signal */
unsigned const _id; /* unique ID of signal handler for debug output */
static unsigned _id_cnt; /* counter for producing unique IDs */
Signal_receiver &_receiver; /* signal endpoint */
bool _stop; /* state for destruction protocol */
unsigned _receive_cnt; /* number of received notifications */
unsigned _activation_cnt; /* number of invocations of the signal handler */
bool _idle; /* suppress the further handling of signals */
bool _verbose; /* print status information */
bool const _verbose; /* print status information */
/**
* Signal handler needs '_dispatch_ms' milliseconds for each signal
@ -133,7 +135,7 @@ class Handler : Thread_deprecated<4096>
while (!_stop) {
if (!_idle) {
Signal signal = _receiver->wait_for_signal();
Signal signal = _receiver.wait_for_signal();
if (_verbose)
log("handler ", _id, " got ", signal.num(), " "
@ -158,9 +160,10 @@ class Handler : Thread_deprecated<4096>
* \param dispatch_ms duration of signal-handler activity
* \param verbose print status information
*/
Handler(Signal_receiver *receiver, unsigned dispatch_ms, bool verbose = true)
Handler(Env &env, Signal_receiver &receiver, unsigned dispatch_ms, bool verbose = true)
:
Thread_deprecated("handler"),
Thread(env, "handler", 4096*sizeof(long)),
_timer(env),
_dispatch_ms(dispatch_ms),
_id(++_id_cnt),
_receiver(receiver),
@ -214,18 +217,6 @@ unsigned Handler::_id_cnt = 0;
static unsigned test_cnt = 0;
/**
* Timer connection to be used by the main program
*/
static Timer::Connection timer;
/**
* Connection to CAP service used for allocating signal-context capabilities
*/
static Genode::Cap_connection cap;
/**
* Symbolic error codes
*/
@ -257,7 +248,7 @@ class Id_signal_context : public Signal_context
* submitted notifications on the sender side does not match the number of
* notifications received at the signal handler.
*/
static void fast_sender_test()
static void fast_sender_test(Env &env)
{
enum { SPEED = 10 };
enum { TEST_DURATION = 50*SPEED };
@ -272,9 +263,12 @@ static void fast_sender_test()
Signal_receiver receiver;
Id_signal_context context_123(123);
Handler *handler = new (env()->heap()) Handler(&receiver, HANDLER_INTERVAL, false);
Sender *sender = new (env()->heap()) Sender(receiver.manage(&context_123),
SENDER_INTERVAL, false);
Heap heap(env.ram(), env.rm());
Timer::Connection timer(env);
Handler *handler = new (heap) Handler(env, receiver, HANDLER_INTERVAL, false);
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123),
SENDER_INTERVAL, false);
timer.msleep(TEST_DURATION);
@ -293,8 +287,8 @@ static void fast_sender_test()
receiver.dissolve(&context_123);
destroy(env()->heap(), sender);
destroy(env()->heap(), handler);
destroy(heap, sender);
destroy(heap, handler);
log("TEST ", test_cnt, " FINISHED");
}
@ -308,7 +302,7 @@ static void fast_sender_test()
* Furthermore, if operating in non-descrete mode, the total number of sent and
* handled notifications is checked.
*/
static void multiple_handlers_test()
static void multiple_handlers_test(Env &env)
{
enum { SPEED = 10 };
enum { TEST_DURATION = 50*SPEED };
@ -321,14 +315,16 @@ static void multiple_handlers_test()
log("TEST ", ++test_cnt, ": one busy sender, ", (int)NUM_HANDLERS, " handlers");
log("");
Heap heap(env.ram(), env.rm());
Timer::Connection timer(env);
Signal_receiver receiver;
Handler *handler[NUM_HANDLERS];
for (int i = 0; i < NUM_HANDLERS; i++)
handler[i] = new (env()->heap()) Handler(&receiver, HANDLER_INTERVAL);
handler[i] = new (heap) Handler(env, receiver, HANDLER_INTERVAL);
Id_signal_context context_123(123);
Sender *sender = new (env()->heap()) Sender(receiver.manage(&context_123), SENDER_INTERVAL);
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123), SENDER_INTERVAL);
timer.msleep(TEST_DURATION);
@ -375,9 +371,9 @@ static void multiple_handlers_test()
/* cleanup */
receiver.dissolve(&context_123);
destroy(env()->heap(), sender);
destroy(heap, sender);
for (int i = 0; i < NUM_HANDLERS; i++)
destroy(env()->heap(), handler[i]);
destroy(heap, handler[i]);
log("TEST ", test_cnt, " FINISHED");
}
@ -390,7 +386,7 @@ static void multiple_handlers_test()
* We produce and handle notifications as fast as possible via spinning
* loops at the sender and handler side.
*/
static void stress_test()
static void stress_test(Env &env)
{
enum { SPEED = 10 };
enum { DURATION_SECONDS = 5 };
@ -400,12 +396,14 @@ static void stress_test()
log("TEST ", ++test_cnt, ": stress test, busy signal transmission and handling");
log("");
Timer::Connection timer(env);
Heap heap(env.ram(), env.rm());
Signal_receiver receiver;
Id_signal_context context_123(123);
Handler *handler = new (env()->heap()) Handler(&receiver, 0, false);
Sender *sender = new (env()->heap()) Sender(receiver.manage(&context_123),
0, false);
Handler *handler = new (heap) Handler(env, receiver, 0, false);
Sender *sender = new (heap) Sender(env, receiver.manage(&context_123),
0, false);
for (int i = 1; i <= DURATION_SECONDS; i++) {
log(i, "/", (int)DURATION_SECONDS);
@ -433,14 +431,14 @@ static void stress_test()
throw Test_failed_with_unequal_sent_and_received_signals();
receiver.dissolve(&context_123);
destroy(env()->heap(), sender);
destroy(env()->heap(), handler);
destroy(heap, sender);
destroy(heap, handler);
log("TEST ", test_cnt, " FINISHED");
}
static void lazy_receivers_test()
static void lazy_receivers_test(Env &env)
{
log("");
log("TEST ", ++test_cnt, ": lazy and out-of-order signal reception test");
@ -486,19 +484,22 @@ static void lazy_receivers_test()
/**
* Try correct initialization and cleanup of receiver/context
*/
static void check_context_management()
static void check_context_management(Env &env)
{
Id_signal_context *context;
Signal_receiver *rec;
Signal_context_capability cap;
Timer::Connection timer(env);
Heap heap(env.ram(), env.rm());
/* setup receiver side */
context = new (env()->heap()) Id_signal_context(321);
rec = new (env()->heap()) Signal_receiver;
context = new (heap) Id_signal_context(321);
rec = new (heap) Signal_receiver;
cap = rec->manage(context);
/* spawn sender */
Sender *sender = new (env()->heap()) Sender(cap, 500);
Sender *sender = new (heap) Sender(env, cap, 500);
/* stop sender after timeout */
timer.msleep(1000);
@ -520,10 +521,10 @@ static void check_context_management()
sender->idle();
log("destroy sender");
destroy(env()->heap(), sender);
destroy(heap, sender);
destroy(env()->heap(), context);
destroy(env()->heap(), rec);
destroy(heap, context);
destroy(heap, rec);
}
@ -558,11 +559,13 @@ class Signal_context_destroyer : public Thread_deprecated<4096>
};
static void synchronized_context_destruction_test()
static void synchronized_context_destruction_test(Env &env)
{
Signal_receiver receiver;
Timer::Connection timer(env);
static Heap heap(env.ram(), env.rm());
Signal_context *context = new (env()->heap()) Signal_context;
Signal_context *context = new (heap) Signal_context;
Signal_transmitter transmitter(receiver.manage(context));
transmitter.submit();
@ -595,8 +598,9 @@ static void synchronized_context_destruction_test()
}
static void many_managed_contexts()
static void many_managed_contexts(Env &env)
{
static Heap heap(env.ram(), env.rm());
for (unsigned round = 0; round < 10; ++round) {
unsigned const num_contexts = 200 + 5*round;
@ -605,7 +609,7 @@ static void many_managed_contexts()
Signal_receiver rec;
for (unsigned i = 0; i < num_contexts; ++i) {
Id_signal_context *context = new (env()->heap()) Id_signal_context(i);
Id_signal_context *context = new (heap) Id_signal_context(i);
if (!rec.manage(context).valid()) {
error("failed to manage signal context");
sleep_forever();
@ -617,21 +621,18 @@ static void many_managed_contexts()
}
/**
* Main program
*/
int main(int, char **)
void Component::construct(Genode::Env &env)
{
log("--- signalling test ---");
fast_sender_test();
multiple_handlers_test();
stress_test();
lazy_receivers_test();
check_context_management();
synchronized_context_destruction_test();
many_managed_contexts();
fast_sender_test(env);
multiple_handlers_test(env);
stress_test(env);
lazy_receivers_test(env);
check_context_management(env);
synchronized_context_destruction_test(env);
many_managed_contexts(env);
log("--- signalling test finished ---");
return 0;
env.parent().exit(0);
}