mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-01 19:46:45 +00:00
511acad507
This patch integrates three region maps into each PD session to reduce the session overhead and to simplify the PD creation procedure. Please refer to the issue cited below for an elaborative discussion. Note the API change: With this patch, the semantics of core's RM service have changed. Now, the service is merely a tool for creating and destroying managed dataspaces, which are rarely needed. Regular components no longer need a RM session. For this reason, the corresponding argument for the 'Process' and 'Child' constructors has been removed. The former interface of the 'Rm_session' is not named 'Region_map'. As a minor refinement, the 'Fault_type' enum values are now part of the 'Region_map::State' struct. Issue #1938
312 lines
7.9 KiB
C++
312 lines
7.9 KiB
C++
/*
|
|
* \brief Fork bomb to stress Genode
|
|
* \author Christian Helmuth
|
|
* \date 2007-08-16
|
|
*
|
|
* The better part of this code is derived from the original init
|
|
* implementation by Norman.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2007-2013 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU General Public License version 2.
|
|
*/
|
|
|
|
#include <base/env.h>
|
|
#include <base/child.h>
|
|
#include <base/sleep.h>
|
|
#include <base/service.h>
|
|
#include <base/snprintf.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::Pd_connection _pd;
|
|
Genode::Rom_connection _rom;
|
|
Genode::Ram_connection _ram;
|
|
Genode::Cpu_connection _cpu;
|
|
char _name[32];
|
|
|
|
Bomb_child_resources(const char *file_name, const char *name,
|
|
Genode::size_t ram_quota)
|
|
: _pd(name), _rom(file_name, name), _ram(name), _cpu(name)
|
|
{
|
|
Genode::strncpy(_name, name, sizeof(_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,
|
|
private Init::Child_policy_enforce_labeling,
|
|
public Genode::List<Bomb_child>::Element
|
|
{
|
|
private:
|
|
|
|
/*
|
|
* Entry point used for serving the parent interface
|
|
*/
|
|
enum { STACK_SIZE = 2048 * sizeof(Genode::addr_t) };
|
|
Genode::Rpc_entrypoint _entrypoint;
|
|
|
|
Genode::Child _child;
|
|
Genode::Service_registry *_parent_services;
|
|
Genode::Child_policy_dynamic_rom_file _config_policy;
|
|
|
|
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_resources(file_name, unique_name, ram_quota),
|
|
Init::Child_policy_enforce_labeling(Bomb_child_resources::_name),
|
|
_entrypoint(cap_session, STACK_SIZE, "bomb_ep_child", false),
|
|
_child(_rom.dataspace(), _pd.cap(), _ram.cap(), _cpu.cap(),
|
|
&_entrypoint, this),
|
|
_parent_services(parent_services),
|
|
_config_policy("config", _entrypoint, &_ram)
|
|
{
|
|
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();
|
|
}
|
|
|
|
~Bomb_child() { PLOG("%s", __PRETTY_FUNCTION__); }
|
|
|
|
|
|
/****************************
|
|
** Child-policy interface **
|
|
****************************/
|
|
|
|
const char *name() const { return Bomb_child_resources::_name; }
|
|
|
|
void filter_session_args(const char * x, char *args, Genode::size_t args_len)
|
|
{
|
|
Child_policy_enforce_labeling::filter_session_args(0, args, args_len);
|
|
}
|
|
|
|
Service *resolve_session_request(const char *service_name,
|
|
const char *args)
|
|
{
|
|
Service * service = nullptr;
|
|
|
|
/* check for config file request */
|
|
if ((service = _config_policy.resolve_session_request(service_name,
|
|
args)))
|
|
return service;
|
|
|
|
return _parent_services->find(service_name);
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
* 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;
|
|
|
|
|
|
/**
|
|
* Check if a program with the specified name already exists
|
|
*/
|
|
static bool child_name_exists(const char *name)
|
|
{
|
|
Bomb_child *c = _children.first();
|
|
|
|
for ( ; c; c = c->List<Bomb_child>::Element::next())
|
|
if (strcmp(c->name(), name) == 0)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Create a unique name based on the filename
|
|
*
|
|
* 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)
|
|
{
|
|
Lock::Guard lock_guard(_children_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);
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
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();
|
|
|
|
unsigned const rounds = node.attribute_value("rounds", 1U);
|
|
unsigned const generation = node.attribute_value("generations", 1U);
|
|
unsigned const children = node.attribute_value("children", 2U);
|
|
unsigned const sleeptime = node.attribute_value("sleep", 2000U);
|
|
unsigned long const demand = node.attribute_value("demand", 1024UL * 1024);
|
|
|
|
printf("--- bomb started ---\n");
|
|
|
|
/* 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 };
|
|
|
|
static Service_registry parent_services;
|
|
for (unsigned i = 0; names[i]; i++)
|
|
parent_services.insert(new (env()->heap()) Parent_service(names[i]));
|
|
|
|
unsigned long avail = env()->ram_session()->avail();
|
|
unsigned long amount = (avail - demand) / children;
|
|
if (amount < (demand * children)) {
|
|
PLOG("I'm a leaf node - generation %u - not enough memory.",
|
|
generation);
|
|
sleep_forever();
|
|
}
|
|
if (generation == 0) {
|
|
PLOG("I'm a leaf node - generation 0");
|
|
sleep_forever();
|
|
}
|
|
|
|
for (unsigned round = 0; round < rounds ; ++round) {
|
|
for (unsigned i = children; i; --i)
|
|
start_child("bomb", &cap, amount, &parent_services, generation - 1);
|
|
|
|
/* is init our parent? */
|
|
if (!timer()) 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));
|
|
}
|
|
|
|
timer()->msleep(sleeptime);
|
|
PINF("[%03d] It's time to kill all my children...", round);
|
|
|
|
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;
|
|
}
|
|
|
|
PINF("[%03d] Done.", round);
|
|
}
|
|
|
|
/* master if we have a timer connection */
|
|
if (timer())
|
|
PINF("Done. Going to sleep");
|
|
|
|
sleep_forever();
|
|
return 0;
|
|
}
|