mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-01 08:48:20 +00:00
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:
parent
cfdbccc5c2
commit
8bafb9d41b
@ -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.
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 { };
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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); }
|
||||
|
@ -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 };
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -25,6 +25,7 @@ install_config {
|
||||
<start name="test-resource_yield">
|
||||
<resource name="RAM" quantum="16M"/>
|
||||
<provides> <service name="ROM" /> </provides>
|
||||
<config/>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
@ -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); }
|
||||
|
@ -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); }
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
@ -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); }
|
||||
|
@ -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),)
|
||||
|
@ -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.
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -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); }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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); }
|
||||
|
@ -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); }
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user