mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 06:07:59 +00:00
cli_monitor: read subsystem configs from VFS
This patch changes the way how CLI monitor obtains its subsystem configurations. Originally, this information was provided via the Genode::config mechanism. But for managing complex scenarios, the config node becomes very complex. Hence, it is preferrable to have a distinct file for each subsystem configuration. The CLI monitor scans the directory '/subsystems' for files ending with ".subsystem". Each file has the same syntax as the formerly used subsystem nodes.
This commit is contained in:
parent
f917728ecb
commit
b4ebefd616
@ -63,6 +63,18 @@ class Child_registry : public List<Child>
|
||||
snprintf(suffix, sizeof(suffix), ".%d", cnt + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call functor 'fn' for each child
|
||||
*
|
||||
* The functor receives the child name as 'char const *'.
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_each_child_name(FN const &fn) const
|
||||
{
|
||||
for (Child const *child = first() ; child; child = child->next())
|
||||
fn(child->name());
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CHILD_REGISTRY_H_ */
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <child_registry.h>
|
||||
#include <gdb_prefix.h>
|
||||
#include <format_util.h>
|
||||
#include <process_arg_registry.h>
|
||||
#include <subsystem_config_registry.h>
|
||||
|
||||
class Gdb_command_child : public Child
|
||||
{
|
||||
@ -123,8 +123,10 @@ class Gdb_command_child : public Child
|
||||
};
|
||||
|
||||
|
||||
struct Gdb_command : Command
|
||||
class Gdb_command : public Command
|
||||
{
|
||||
private:
|
||||
|
||||
typedef Genode::Xml_node Xml_node;
|
||||
typedef Genode::Signal_context_capability Signal_context_capability;
|
||||
|
||||
@ -133,70 +135,10 @@ struct Gdb_command : Command
|
||||
Ram &_ram;
|
||||
Child_registry &_children;
|
||||
Genode::Cap_session &_cap;
|
||||
Xml_node _config;
|
||||
Process_arg_registry &_process_args;
|
||||
List<Argument> _arguments;
|
||||
Subsystem_config_registry &_subsystem_configs;
|
||||
Signal_context_capability _yield_response_sigh_cap;
|
||||
Signal_context_capability _kill_gdb_sig_cap;
|
||||
|
||||
Gdb_command(Ram &ram, Genode::Cap_session &cap, Child_registry &children,
|
||||
Xml_node config, Process_arg_registry &process_args,
|
||||
Signal_context_capability yield_response_sigh_cap,
|
||||
Signal_context_capability kill_gdb_sig_cap)
|
||||
:
|
||||
Command("gdb", "create new subsystem with GDB"),
|
||||
_ram(ram), _children(children), _cap(cap), _config(config),
|
||||
_process_args(process_args),
|
||||
_yield_response_sigh_cap(yield_response_sigh_cap),
|
||||
_kill_gdb_sig_cap(kill_gdb_sig_cap)
|
||||
{
|
||||
/* scan config for possible subsystem arguments */
|
||||
try {
|
||||
Xml_node node = _config.sub_node("subsystem");
|
||||
for (;; node = node.next("subsystem")) {
|
||||
|
||||
char name[Parameter::NAME_MAX_LEN];
|
||||
try { node.attribute("name").value(name, sizeof(name)); }
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
PWRN("Missing name in '<subsystem>' configuration");
|
||||
continue;
|
||||
}
|
||||
|
||||
char const *prefix = "config: ";
|
||||
size_t const prefix_len = strlen(prefix);
|
||||
|
||||
char help[Parameter::SHORT_HELP_MAX_LEN + prefix_len];
|
||||
strncpy(help, prefix, ~0);
|
||||
try { node.attribute("help").value(help + prefix_len,
|
||||
sizeof(help) - prefix_len); }
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
PWRN("Missing help in '<subsystem>' configuration");
|
||||
continue;
|
||||
}
|
||||
|
||||
_arguments.insert(new Argument(name, help));
|
||||
}
|
||||
} catch (Xml_node::Nonexistent_sub_node) { /* end of list */ }
|
||||
|
||||
add_parameter(new Parameter("--ram", Parameter::NUMBER, "initial RAM quota"));
|
||||
add_parameter(new Parameter("--ram-limit", Parameter::NUMBER, "limit for expanding RAM quota"));
|
||||
add_parameter(new Parameter("--gdb-ram-preserve", Parameter::NUMBER,
|
||||
"RAM quota which GDB monitor should preserve for itself (default: 5M)"));
|
||||
add_parameter(new Parameter("--verbose", Parameter::VOID, "show diagnostics"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup subsystem in config
|
||||
*/
|
||||
Xml_node _subsystem_node(char const *name)
|
||||
{
|
||||
Xml_node node = _config.sub_node("subsystem");
|
||||
for (;; node = node.next("subsystem")) {
|
||||
if (node.attribute("name").has_value(name))
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the config node for the GDB subsystem
|
||||
*/
|
||||
@ -381,52 +323,19 @@ struct Gdb_command : Command
|
||||
"GDB target binary.\n");
|
||||
throw Child_configuration_failed();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void execute(Command_line &cmd, Terminal::Session &terminal)
|
||||
void _execute_subsystem(char const *name, Command_line &cmd,
|
||||
Terminal::Session &terminal,
|
||||
Xml_node subsystem_node)
|
||||
{
|
||||
/* check if the GDB-related ROM modules are available */
|
||||
try {
|
||||
Genode::Rom_connection gdb_command_config("gdb_command_config");
|
||||
Genode::Rom_connection terminal_crosslink("terminal_crosslink");
|
||||
Genode::Rom_connection noux("noux");
|
||||
Genode::Rom_connection gdb_monitor("gdb_monitor");
|
||||
} catch (Genode::Rom_connection::Rom_connection_failed) {
|
||||
tprintf(terminal, "Error: The 'gdb' command needs the following ROM "
|
||||
"modules (of which some are currently missing): "
|
||||
"gdb_command_config, terminal_crosslink, noux, ",
|
||||
"gdb_monitor\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Genode::Number_of_bytes ram = 0;
|
||||
Genode::Number_of_bytes ram_limit = 0;
|
||||
Genode::Number_of_bytes gdb_ram_preserve = 10*1024*1024;
|
||||
|
||||
char name[128];
|
||||
name[0] = 0;
|
||||
if (cmd.argument(0, name, sizeof(name)) == false) {
|
||||
tprintf(terminal, "Error: no configuration name specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
if (cmd.argument(1, buf, sizeof(buf))) {
|
||||
tprintf(terminal, "Error: unexpected argument \"%s\"\n", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if a configuration for the subsystem exists */
|
||||
try { _subsystem_node(name); }
|
||||
catch (Xml_node::Nonexistent_sub_node) {
|
||||
tprintf(terminal, "Error: no configuration for \"%s\"\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* read default RAM quota from config */
|
||||
try {
|
||||
Xml_node rsc = _subsystem_node(name).sub_node("resource");
|
||||
Xml_node rsc = subsystem_node.sub_node("resource");
|
||||
for (;; rsc = rsc.next("resource")) {
|
||||
if (rsc.attribute("name").has_value("RAM")) {
|
||||
rsc.attribute("quantum").value(&ram);
|
||||
@ -459,7 +368,7 @@ struct Gdb_command : Command
|
||||
char binary_name[128];
|
||||
strncpy(binary_name, name, sizeof(binary_name));
|
||||
try {
|
||||
Xml_node bin = _subsystem_node(name).sub_node("binary");
|
||||
Xml_node bin = subsystem_node.sub_node("binary");
|
||||
bin.attribute("name").value(binary_name, sizeof(binary_name));
|
||||
} catch (...) { }
|
||||
|
||||
@ -488,7 +397,7 @@ struct Gdb_command : Command
|
||||
const char *target_config_addr = 0;
|
||||
size_t target_config_size = 0;
|
||||
try {
|
||||
Xml_node target_config_node = _subsystem_node(name).sub_node("config");
|
||||
Xml_node target_config_node = subsystem_node.sub_node("config");
|
||||
target_config_addr = target_config_node.addr();
|
||||
target_config_size = target_config_node.size();
|
||||
} catch (...) { }
|
||||
@ -537,12 +446,101 @@ struct Gdb_command : Command
|
||||
return;
|
||||
}
|
||||
|
||||
_process_args.list.insert(&child->argument);
|
||||
_children.insert(child);
|
||||
child->start();
|
||||
}
|
||||
|
||||
List<Argument> &arguments() { return _arguments; }
|
||||
public:
|
||||
|
||||
Gdb_command(Ram &ram, Genode::Cap_session &cap, Child_registry &children,
|
||||
Subsystem_config_registry &subsustem_configs,
|
||||
Signal_context_capability yield_response_sigh_cap,
|
||||
Signal_context_capability kill_gdb_sig_cap)
|
||||
:
|
||||
Command("gdb", "create new subsystem with GDB"),
|
||||
_ram(ram), _children(children), _cap(cap),
|
||||
_subsystem_configs(subsustem_configs),
|
||||
_yield_response_sigh_cap(yield_response_sigh_cap),
|
||||
_kill_gdb_sig_cap(kill_gdb_sig_cap)
|
||||
{
|
||||
add_parameter(new Parameter("--ram", Parameter::NUMBER, "initial RAM quota"));
|
||||
add_parameter(new Parameter("--ram-limit", Parameter::NUMBER, "limit for expanding RAM quota"));
|
||||
add_parameter(new Parameter("--gdb-ram-preserve", Parameter::NUMBER,
|
||||
"RAM quota which GDB monitor should preserve for itself (default: 5M)"));
|
||||
add_parameter(new Parameter("--verbose", Parameter::VOID, "show diagnostics"));
|
||||
}
|
||||
|
||||
void _for_each_argument(Argument_fn const &fn) const override
|
||||
{
|
||||
/* functor for processing a subsystem configuration */
|
||||
auto process_subsystem_config_fn = [&] (Genode::Xml_node node) {
|
||||
|
||||
char name[Parameter::Name::size()];
|
||||
try { node.attribute("name").value(name, sizeof(name)); }
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
PWRN("Missing name in '<subsystem>' configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
char const *prefix = "config: ";
|
||||
size_t const prefix_len = strlen(prefix);
|
||||
|
||||
char help[Parameter::Short_help::size() + prefix_len];
|
||||
strncpy(help, prefix, ~0);
|
||||
try { node.attribute("help").value(help + prefix_len,
|
||||
sizeof(help) - prefix_len); }
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
PWRN("Missing help in '<subsystem>' configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
Argument arg(name, help);
|
||||
fn(arg);
|
||||
};
|
||||
|
||||
/* scan subsystem config registry for possible subsystem arguments */
|
||||
_subsystem_configs.for_each_config(process_subsystem_config_fn);
|
||||
}
|
||||
|
||||
void execute(Command_line &cmd, Terminal::Session &terminal)
|
||||
{
|
||||
/* check if the GDB-related ROM modules are available */
|
||||
try {
|
||||
Genode::Rom_connection gdb_command_config("gdb_command_config");
|
||||
Genode::Rom_connection terminal_crosslink("terminal_crosslink");
|
||||
Genode::Rom_connection noux("noux");
|
||||
Genode::Rom_connection gdb_monitor("gdb_monitor");
|
||||
} catch (Genode::Rom_connection::Rom_connection_failed) {
|
||||
tprintf(terminal, "Error: The 'gdb' command needs the following ROM "
|
||||
"modules (of which some are currently missing): "
|
||||
"gdb_command_config, terminal_crosslink, noux, ",
|
||||
"gdb_monitor\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char name[128];
|
||||
name[0] = 0;
|
||||
if (cmd.argument(0, name, sizeof(name)) == false) {
|
||||
tprintf(terminal, "Error: no configuration name specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
if (cmd.argument(1, buf, sizeof(buf))) {
|
||||
tprintf(terminal, "Error: unexpected argument \"%s\"\n", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
_subsystem_configs.for_config(name, [&] (Genode::Xml_node node)
|
||||
{
|
||||
_execute_subsystem(name, cmd, terminal, node);
|
||||
});
|
||||
|
||||
} catch (Subsystem_config_registry::Nonexistent_subsystem_config) {
|
||||
tprintf(terminal, "Error: no configuration for \"%s\"\n", name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _GDB_COMMAND_H_ */
|
||||
|
@ -16,31 +16,36 @@
|
||||
|
||||
/* local includes */
|
||||
#include <child_registry.h>
|
||||
#include <process_arg_registry.h>
|
||||
|
||||
struct Kill_command : Command
|
||||
{
|
||||
Child_registry &_children;
|
||||
|
||||
Process_arg_registry &_process_args;
|
||||
|
||||
void _destroy_child(Child *child, Terminal::Session &terminal)
|
||||
{
|
||||
tprintf(terminal, "destroying subsystem '%s'\n", child->name());
|
||||
_process_args.list.remove(&child->argument);
|
||||
_children.remove(child);
|
||||
Genode::destroy(Genode::env()->heap(), child);
|
||||
}
|
||||
|
||||
Kill_command(Child_registry &children, Process_arg_registry &process_args)
|
||||
Kill_command(Child_registry &children)
|
||||
:
|
||||
Command("kill", "destroy subsystem"),
|
||||
_children(children),
|
||||
_process_args(process_args)
|
||||
_children(children)
|
||||
{
|
||||
add_parameter(new Parameter("--all", Parameter::VOID, "kill all subsystems"));
|
||||
}
|
||||
|
||||
void _for_each_argument(Argument_fn const &fn) const override
|
||||
{
|
||||
auto child_name_fn = [&] (char const *child_name) {
|
||||
Argument arg(child_name, "");
|
||||
fn(arg);
|
||||
};
|
||||
|
||||
_children.for_each_child_name(child_name_fn);
|
||||
}
|
||||
|
||||
void execute(Command_line &cmd, Terminal::Session &terminal)
|
||||
{
|
||||
bool const kill_all = cmd.parameter_exists("--all");
|
||||
@ -68,8 +73,6 @@ struct Kill_command : Command
|
||||
|
||||
tprintf(terminal, "Error: subsystem '%s' does not exist\n", label);
|
||||
}
|
||||
|
||||
List<Argument> &arguments() { return _process_args.list; }
|
||||
};
|
||||
|
||||
#endif /* _KILL_COMMAND_H_ */
|
||||
|
@ -35,18 +35,14 @@ using Genode::off_t;
|
||||
|
||||
struct Completable
|
||||
{
|
||||
template <size_t MAX_LEN> struct String
|
||||
{
|
||||
char buf[MAX_LEN];
|
||||
String(char const *string) { strncpy(buf, string, sizeof(buf)); }
|
||||
};
|
||||
typedef Genode::String<64> Name;
|
||||
typedef Genode::String<160> Short_help;
|
||||
|
||||
enum { NAME_MAX_LEN = 64, SHORT_HELP_MAX_LEN = 160 };
|
||||
String<NAME_MAX_LEN> const _name;
|
||||
String<SHORT_HELP_MAX_LEN> const _short_help;
|
||||
Name const _name;
|
||||
Short_help const _short_help;
|
||||
|
||||
char const *name() const { return _name.buf; }
|
||||
char const *short_help() const { return _short_help.buf; }
|
||||
Name name() const { return _name; }
|
||||
Short_help short_help() const { return _short_help; }
|
||||
|
||||
Completable(char const *name, char const *short_help)
|
||||
: _name(name), _short_help(short_help) { }
|
||||
@ -56,7 +52,7 @@ struct Completable
|
||||
/**
|
||||
* Representation of normal command-line argument
|
||||
*/
|
||||
struct Argument : List<Argument>::Element, Completable
|
||||
struct Argument : Completable
|
||||
{
|
||||
Argument(char const *name, char const *short_help)
|
||||
: Completable(name, short_help) { }
|
||||
@ -103,6 +99,14 @@ struct Command : List<Command>::Element, Completable
|
||||
{
|
||||
List<Parameter> _parameters;
|
||||
|
||||
/**
|
||||
* Functor that takes a command 'Argument' object as argument
|
||||
*/
|
||||
struct Argument_fn
|
||||
{
|
||||
virtual void operator () (Argument const &) const = 0;
|
||||
};
|
||||
|
||||
Command(char const *name, char const *short_help)
|
||||
: Completable(name, short_help) { }
|
||||
|
||||
@ -112,16 +116,28 @@ struct Command : List<Command>::Element, Completable
|
||||
|
||||
List<Parameter> ¶meters() { return _parameters; }
|
||||
|
||||
/**
|
||||
* To be overridden by commands that accept auto-completion of arguments
|
||||
*/
|
||||
virtual List<Argument> &arguments()
|
||||
{
|
||||
static List<Argument> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
virtual void execute(Command_line &, Terminal::Session &terminal) = 0;
|
||||
|
||||
/**
|
||||
* Command-specific support for 'for_each_argument'
|
||||
*/
|
||||
virtual void _for_each_argument(Argument_fn const &fn) const { };
|
||||
|
||||
/**
|
||||
* Execute functor 'fn' for each command argument
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_each_argument(FN const &fn) const
|
||||
{
|
||||
struct _Fn : Argument_fn
|
||||
{
|
||||
FN const &fn;
|
||||
void operator () (Argument const &arg) const override { fn(arg); }
|
||||
_Fn(FN const &fn) : fn(fn) { }
|
||||
} _fn(fn);
|
||||
|
||||
_for_each_argument(_fn);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -162,22 +178,24 @@ struct Argument_tracker
|
||||
* Return true if there is exactly one complete match and no additional
|
||||
* partial matches
|
||||
*/
|
||||
template <typename T>
|
||||
static bool _one_match(char const *str, size_t str_len,
|
||||
List<T> &list)
|
||||
static bool _one_matching_argument(char const *str, size_t str_len,
|
||||
Command const &command)
|
||||
{
|
||||
unsigned complete_cnt = 0, partial_cnt = 0;
|
||||
|
||||
Token tag(str, str_len);
|
||||
for (T *curr = list.first(); curr; curr = curr->next()) {
|
||||
if (strcmp(tag.start(), curr->name(), tag.len()) == 0) {
|
||||
auto argument_fn = [&] (Argument const &arg) {
|
||||
|
||||
if (strcmp(arg.name().string(), str, str_len) == 0) {
|
||||
partial_cnt++;
|
||||
if (strlen(curr->name()) == tag.len())
|
||||
|
||||
if (strlen(arg.name().string()) == str_len)
|
||||
complete_cnt++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return partial_cnt == 1 && complete_cnt == 1;;
|
||||
command.for_each_argument(argument_fn);
|
||||
|
||||
return partial_cnt == 1 && complete_cnt == 1;
|
||||
}
|
||||
|
||||
public:
|
||||
@ -191,8 +209,8 @@ struct Argument_tracker
|
||||
{
|
||||
Token tag(str, str_len);
|
||||
for (T *curr = list.first(); curr; curr = curr->next())
|
||||
if (strcmp(tag.start(), curr->name(), tag.len()) == 0
|
||||
&& strlen(curr->name()) == tag.len())
|
||||
if (strcmp(tag.start(), curr->name().string(), tag.len()) == 0
|
||||
&& strlen(curr->name().string()) == tag.len())
|
||||
return curr;
|
||||
|
||||
return 0;
|
||||
@ -238,7 +256,7 @@ struct Argument_tracker
|
||||
}
|
||||
|
||||
if (!token_may_be_incomplete
|
||||
|| _one_match(token.start(), token.len(), _command.arguments()))
|
||||
|| _one_matching_argument(token.start(), token.len(), _command))
|
||||
_state = EXPECT_SPACE_BEFORE_ARG;
|
||||
}
|
||||
break;
|
||||
@ -469,7 +487,7 @@ class Line_editor
|
||||
{
|
||||
Token cmd(_buf, _cursor_pos);
|
||||
for (Command *curr = _commands.first(); curr; curr = curr->next())
|
||||
if (strcmp(cmd.start(), curr->name(), cmd.len()) == 0
|
||||
if (strcmp(cmd.start(), curr->name().string(), cmd.len()) == 0
|
||||
&& _cursor_pos > cmd.len())
|
||||
return curr;
|
||||
return 0;
|
||||
@ -482,7 +500,7 @@ class Line_editor
|
||||
|
||||
unsigned num_partial_matches = 0;
|
||||
for (T *curr = list.first(); curr; curr = curr->next()) {
|
||||
if (strcmp(token.start(), curr->name(), token.len()) != 0)
|
||||
if (strcmp(token.start(), curr->name().string(), token.len()) != 0)
|
||||
continue;
|
||||
|
||||
num_partial_matches++;
|
||||
@ -490,6 +508,22 @@ class Line_editor
|
||||
return num_partial_matches;
|
||||
}
|
||||
|
||||
unsigned _num_matching_arguments(char const *str, size_t str_len,
|
||||
Command const &command) const
|
||||
{
|
||||
unsigned num_matches = 0;
|
||||
|
||||
auto argument_fn = [&] (Argument const &arg) {
|
||||
|
||||
if (strcmp(arg.name().string(), str, str_len) == 0)
|
||||
num_matches++;
|
||||
};
|
||||
|
||||
command.for_each_argument(argument_fn);
|
||||
|
||||
return num_matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the name-column width of list of partial matches
|
||||
*/
|
||||
@ -501,16 +535,35 @@ class Line_editor
|
||||
|
||||
size_t max_name_len = 0;
|
||||
for (T *curr = list.first(); curr; curr = curr->next()) {
|
||||
if (strcmp(token.start(), curr->name(), token.len()) != 0)
|
||||
if (strcmp(token.start(), curr->name().string(), token.len()) != 0)
|
||||
continue;
|
||||
|
||||
size_t const name_len = strlen(curr->name())
|
||||
size_t const name_len = strlen(curr->name().string())
|
||||
+ strlen(curr->name_suffix());
|
||||
max_name_len = max(max_name_len, name_len);
|
||||
}
|
||||
return max_name_len;
|
||||
}
|
||||
|
||||
unsigned _width_of_matching_arguments(char const *str, size_t str_len,
|
||||
Command const &command) const
|
||||
{
|
||||
size_t max_name_len = 0;
|
||||
|
||||
auto argument_fn = [&] (Argument const &arg) {
|
||||
|
||||
if (strcmp(arg.name().string(), str, str_len) == 0) {
|
||||
size_t const name_len = strlen(arg.name().string());
|
||||
if (name_len > max_name_len)
|
||||
max_name_len = name_len;
|
||||
}
|
||||
};
|
||||
|
||||
command.for_each_argument(argument_fn);
|
||||
|
||||
return max_name_len;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
char const *_any_partial_match_name(char const *str, size_t str_len,
|
||||
List<T> &list)
|
||||
@ -518,12 +571,28 @@ class Line_editor
|
||||
Token token(str, str_len);
|
||||
|
||||
for (T *curr = list.first(); curr; curr = curr->next())
|
||||
if (strcmp(token.start(), curr->name(), token.len()) == 0)
|
||||
return curr->name();
|
||||
if (strcmp(token.start(), curr->name().string(), token.len()) == 0)
|
||||
return curr->name().string();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Argument::Name _any_matching_argument(char const *str, size_t str_len,
|
||||
Command const &command) const
|
||||
{
|
||||
Argument::Name name;
|
||||
|
||||
auto argument_fn = [&] (Argument const &arg) {
|
||||
|
||||
if (strcmp(arg.name().string(), str, str_len) == 0)
|
||||
name = arg.name();
|
||||
};
|
||||
|
||||
command.for_each_argument(argument_fn);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void _list_partial_matches(char const *str, size_t str_len,
|
||||
unsigned pad, List<T> &list)
|
||||
@ -531,23 +600,47 @@ class Line_editor
|
||||
Token token(str, str_len);
|
||||
|
||||
for (T *curr = list.first(); curr; curr = curr->next()) {
|
||||
if (strcmp(token.start(), curr->name(), token.len()) != 0)
|
||||
if (strcmp(token.start(), curr->name().string(), token.len()) != 0)
|
||||
continue;
|
||||
|
||||
_write_newline();
|
||||
_write_spaces(2);
|
||||
_write(curr->name());
|
||||
_write(curr->name().string());
|
||||
_write_spaces(1);
|
||||
_write(curr->name_suffix());
|
||||
|
||||
/* pad short help with whitespaces */
|
||||
size_t const name_len = strlen(curr->name())
|
||||
size_t const name_len = strlen(curr->name().string())
|
||||
+ strlen(curr->name_suffix());
|
||||
_write_spaces(pad + 3 - name_len);
|
||||
_write(curr->short_help());
|
||||
_write(curr->short_help().string());
|
||||
}
|
||||
}
|
||||
|
||||
void _list_matching_arguments(char const *str, size_t str_len,
|
||||
unsigned pad, Command const &command)
|
||||
{
|
||||
auto argument_fn = [&] (Argument const &arg) {
|
||||
|
||||
if (strcmp(arg.name().string(), str, str_len) == 0) {
|
||||
|
||||
_write_newline();
|
||||
_write_spaces(2);
|
||||
_write(arg.name().string());
|
||||
_write_spaces(1);
|
||||
_write(arg.name_suffix());
|
||||
|
||||
/* pad short help with whitespaces */
|
||||
size_t const name_len = strlen(arg.name().string())
|
||||
+ strlen(arg.name_suffix());
|
||||
_write_spaces(pad + 3 - name_len);
|
||||
_write(arg.short_help().string());
|
||||
}
|
||||
};
|
||||
|
||||
command.for_each_argument(argument_fn);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void _do_completion(char const *str, size_t str_len, List<T> &list)
|
||||
{
|
||||
@ -556,7 +649,7 @@ class Line_editor
|
||||
/* look up completable token */
|
||||
T *partial_match = 0;
|
||||
for (T *curr = list.first(); curr; curr = curr->next()) {
|
||||
if (strcmp(token.start(), curr->name(), token.len()) == 0) {
|
||||
if (strcmp(token.start(), curr->name().string(), token.len()) == 0) {
|
||||
partial_match = curr;
|
||||
break;
|
||||
}
|
||||
@ -565,8 +658,27 @@ class Line_editor
|
||||
if (!partial_match)
|
||||
return;
|
||||
|
||||
for (unsigned i = token.len(); i < strlen(partial_match->name()); i++)
|
||||
_insert_character(partial_match->name()[i]);
|
||||
for (unsigned i = token.len(); i < strlen(partial_match->name().string()); i++)
|
||||
_insert_character(partial_match->name().string()[i]);
|
||||
|
||||
_insert_character(' ');
|
||||
}
|
||||
|
||||
void _do_argument_completion(char const *str, size_t str_len,
|
||||
Command const &command)
|
||||
{
|
||||
Argument::Name partial_match;
|
||||
|
||||
auto argument_fn = [&] (Argument const &arg) {
|
||||
|
||||
if (strcmp(arg.name().string(), str, str_len) == 0)
|
||||
partial_match = arg.name();
|
||||
};
|
||||
|
||||
command.for_each_argument(argument_fn);
|
||||
|
||||
for (unsigned i = str_len; i < strlen(partial_match.string()); i++)
|
||||
_insert_character(partial_match.string()[i]);
|
||||
|
||||
_insert_character(' ');
|
||||
}
|
||||
@ -577,7 +689,7 @@ class Line_editor
|
||||
_num_partial_matches(str, str_len, command.parameters());
|
||||
|
||||
unsigned const matching_arguments =
|
||||
_num_partial_matches(str, str_len, command.arguments());
|
||||
_num_matching_arguments(str, str_len, command);
|
||||
|
||||
/* matches are ambiguous */
|
||||
if (matching_arguments + matching_parameters > 1) {
|
||||
@ -586,13 +698,17 @@ class Line_editor
|
||||
* Try to complete additional characters that are common among
|
||||
* all matches.
|
||||
*/
|
||||
char buf[Completable::NAME_MAX_LEN];
|
||||
char buf[Completable::Name::size()];
|
||||
strncpy(buf, str, Genode::min(sizeof(buf), str_len + 1));
|
||||
|
||||
/* pick any representative as a template to take characters from */
|
||||
char const *name = _any_partial_match_name(str, str_len, command.parameters());
|
||||
if (!name)
|
||||
name = _any_partial_match_name(str, str_len, command.arguments());
|
||||
Argument::Name arg_name;
|
||||
if (!name) {
|
||||
arg_name = _any_matching_argument(str, str_len, command);
|
||||
if (strlen(arg_name.string()))
|
||||
name = arg_name.string();
|
||||
}
|
||||
|
||||
size_t i = str_len;
|
||||
for (; (i < sizeof(buf) - 1) && (i < strlen(name)); i++) {
|
||||
@ -605,7 +721,7 @@ class Line_editor
|
||||
break;
|
||||
|
||||
if (matching_arguments !=
|
||||
_num_partial_matches(buf, i + 1, command.arguments()))
|
||||
_num_matching_arguments(buf, i + 1, command))
|
||||
break;
|
||||
|
||||
_insert_character(buf[i]);
|
||||
@ -624,10 +740,10 @@ class Line_editor
|
||||
*/
|
||||
size_t const pad =
|
||||
max(_width_of_partial_matches(str, str_len, command.parameters()),
|
||||
_width_of_partial_matches(str, str_len, command.arguments()));
|
||||
_width_of_matching_arguments(str, str_len, command));
|
||||
|
||||
_list_partial_matches(str, str_len, pad, command.parameters());
|
||||
_list_partial_matches(str, str_len, pad, command.arguments());
|
||||
_list_matching_arguments(str, str_len, pad, command);
|
||||
|
||||
_write_newline();
|
||||
_fresh_prompt();
|
||||
@ -639,7 +755,7 @@ class Line_editor
|
||||
_do_completion(str, str_len, command.parameters());
|
||||
|
||||
if (matching_arguments == 1)
|
||||
_do_completion(str, str_len, command.arguments());
|
||||
_do_argument_completion(str, str_len, command);
|
||||
}
|
||||
|
||||
void _perform_completion()
|
||||
|
@ -14,6 +14,8 @@
|
||||
/* Genode includes */
|
||||
#include <os/config.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <vfs/file_system_factory.h>
|
||||
#include <vfs/dir_file_system.h>
|
||||
|
||||
/* public CLI-monitor includes */
|
||||
#include <cli_monitor/ram.h>
|
||||
@ -48,8 +50,8 @@ static inline Command *lookup_command(char const *buf, Command_registry ®istr
|
||||
{
|
||||
Token token(buf);
|
||||
for (Command *curr = registry.first(); curr; curr = curr->next())
|
||||
if (strcmp(token.start(), curr->name(), token.len()) == 0
|
||||
&& strlen(curr->name()) == token.len())
|
||||
if (strcmp(token.start(), curr->name().string(), token.len()) == 0
|
||||
&& strlen(curr->name().string()) == token.len())
|
||||
return curr;
|
||||
return 0;
|
||||
}
|
||||
@ -70,6 +72,30 @@ static size_t ram_preservation_from_config()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return singleton instance of the subsystem config registry
|
||||
*/
|
||||
static Subsystem_config_registry &subsystem_config_registry()
|
||||
{
|
||||
try {
|
||||
|
||||
/* initialize virtual file system */
|
||||
static Vfs::Dir_file_system
|
||||
root_dir(Genode::config()->xml_node().sub_node("vfs"),
|
||||
Vfs::global_file_system_factory());
|
||||
|
||||
static Subsystem_config_registry inst(root_dir);
|
||||
|
||||
return inst;
|
||||
|
||||
} catch (Genode::Xml_node::Nonexistent_sub_node) {
|
||||
|
||||
PERR("missing '<vfs>' configuration");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* look for dynamic linker */
|
||||
@ -86,7 +112,6 @@ int main(int argc, char **argv)
|
||||
static Terminal::Connection terminal;
|
||||
static Command_registry commands;
|
||||
static Child_registry children;
|
||||
static Process_arg_registry process_args;
|
||||
|
||||
/* initialize platform-specific commands */
|
||||
init_extension(commands);
|
||||
@ -112,20 +137,18 @@ int main(int argc, char **argv)
|
||||
|
||||
/* initialize generic commands */
|
||||
commands.insert(new Help_command);
|
||||
Kill_command kill_command(children, process_args);
|
||||
Kill_command kill_command(children);
|
||||
commands.insert(&kill_command);
|
||||
commands.insert(new Gdb_command(ram, cap, children,
|
||||
Genode::config()->xml_node(),
|
||||
process_args,
|
||||
subsystem_config_registry(),
|
||||
yield_response_sig_cap,
|
||||
kill_gdb_sig_cap));
|
||||
commands.insert(new Start_command(ram, cap, children,
|
||||
Genode::config()->xml_node(),
|
||||
process_args,
|
||||
subsystem_config_registry(),
|
||||
yield_response_sig_cap));
|
||||
commands.insert(new Status_command(ram, children));
|
||||
commands.insert(new Yield_command(children, process_args));
|
||||
commands.insert(new Ram_command(children, process_args));
|
||||
commands.insert(new Yield_command(children));
|
||||
commands.insert(new Ram_command(children));
|
||||
|
||||
enum { COMMAND_MAX_LEN = 1000 };
|
||||
static char buf[COMMAND_MAX_LEN];
|
||||
@ -180,7 +203,6 @@ int main(int argc, char **argv)
|
||||
dynamic_cast<Gdb_command_child*>(child);
|
||||
if (gdb_command_child && gdb_command_child->kill_requested()) {
|
||||
tprintf(terminal, "Destroying GDB subsystem after an error occured.\n");
|
||||
process_args.list.remove(&gdb_command_child->argument);
|
||||
children.remove(gdb_command_child);
|
||||
Genode::destroy(Genode::env()->heap(), gdb_command_child);
|
||||
line_editor.reset();
|
||||
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* \brief Registry of process names used as arguments
|
||||
* \author Norman Feske
|
||||
* \date 2013-03-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _PROCESS_ARG_REGISTRY_H_
|
||||
#define _PROCESS_ARG_REGISTRY_H_
|
||||
|
||||
/**
|
||||
* Registry of arguments referring to the currently running processes
|
||||
*/
|
||||
struct Process_arg_registry
|
||||
{
|
||||
Genode::List<Argument> list;
|
||||
};
|
||||
|
||||
#endif /* _PROCESS_ARG_REGISTRY_H_ */
|
@ -16,18 +16,15 @@
|
||||
|
||||
/* local includes */
|
||||
#include <child_registry.h>
|
||||
#include <process_arg_registry.h>
|
||||
|
||||
struct Ram_command : Command
|
||||
{
|
||||
Child_registry &_children;
|
||||
Process_arg_registry &_process_args;
|
||||
|
||||
Ram_command(Child_registry &children, Process_arg_registry &process_args)
|
||||
Ram_command(Child_registry &children)
|
||||
:
|
||||
Command("ram", "set RAM quota of subsystem"),
|
||||
_children(children),
|
||||
_process_args(process_args)
|
||||
_children(children)
|
||||
{
|
||||
add_parameter(new Parameter("--quota", Parameter::NUMBER, "new RAM quota"));
|
||||
add_parameter(new Parameter("--limit", Parameter::NUMBER, "on-demand quota limit"));
|
||||
@ -83,6 +80,16 @@ struct Ram_command : Command
|
||||
}
|
||||
}
|
||||
|
||||
void _for_each_argument(Argument_fn const &fn) const override
|
||||
{
|
||||
auto child_name_fn = [&] (char const *child_name) {
|
||||
Argument arg(child_name, "");
|
||||
fn(arg);
|
||||
};
|
||||
|
||||
_children.for_each_child_name(child_name_fn);
|
||||
}
|
||||
|
||||
void execute(Command_line &cmd, Terminal::Session &terminal)
|
||||
{
|
||||
char label[128];
|
||||
@ -116,8 +123,6 @@ struct Ram_command : Command
|
||||
_set_quota(terminal, *child, quota);
|
||||
}
|
||||
}
|
||||
|
||||
List<Argument> &arguments() { return _process_args.list; }
|
||||
};
|
||||
|
||||
#endif /* _RAM_COMMAND_H_ */
|
||||
|
@ -17,103 +17,34 @@
|
||||
/* Genode includes */
|
||||
#include <util/xml_node.h>
|
||||
|
||||
struct Start_command : Command
|
||||
/* local includes */
|
||||
#include <subsystem_config_registry.h>
|
||||
|
||||
class Start_command : public Command
|
||||
{
|
||||
private:
|
||||
|
||||
typedef Genode::Xml_node Xml_node;
|
||||
typedef Genode::Signal_context_capability Signal_context_capability;
|
||||
|
||||
Ram &_ram;
|
||||
Child_registry &_children;
|
||||
Genode::Cap_session &_cap;
|
||||
Xml_node _config;
|
||||
Process_arg_registry &_process_args;
|
||||
Subsystem_config_registry &_subsystem_configs;
|
||||
List<Argument> _arguments;
|
||||
Signal_context_capability _yield_response_sigh_cap;
|
||||
|
||||
Start_command(Ram &ram, Genode::Cap_session &cap, Child_registry &children,
|
||||
Xml_node config, Process_arg_registry &process_args,
|
||||
Signal_context_capability yield_response_sigh_cap)
|
||||
:
|
||||
Command("start", "create new subsystem"),
|
||||
_ram(ram), _children(children), _cap(cap), _config(config),
|
||||
_process_args(process_args),
|
||||
_yield_response_sigh_cap(yield_response_sigh_cap)
|
||||
{
|
||||
/* scan config for possible subsystem arguments */
|
||||
try {
|
||||
Xml_node node = _config.sub_node("subsystem");
|
||||
for (;; node = node.next("subsystem")) {
|
||||
|
||||
char name[Parameter::NAME_MAX_LEN];
|
||||
try { node.attribute("name").value(name, sizeof(name)); }
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
PWRN("Missing name in '<subsystem>' configuration");
|
||||
continue;
|
||||
}
|
||||
|
||||
char const *prefix = "config: ";
|
||||
size_t const prefix_len = strlen(prefix);
|
||||
|
||||
char help[Parameter::SHORT_HELP_MAX_LEN + prefix_len];
|
||||
strncpy(help, prefix, ~0);
|
||||
try { node.attribute("help").value(help + prefix_len,
|
||||
sizeof(help) - prefix_len); }
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
PWRN("Missing help in '<subsystem>' configuration");
|
||||
continue;
|
||||
}
|
||||
|
||||
_arguments.insert(new Argument(name, help));
|
||||
}
|
||||
} catch (Xml_node::Nonexistent_sub_node) { /* end of list */ }
|
||||
|
||||
add_parameter(new Parameter("--count", Parameter::NUMBER, "number of instances"));
|
||||
add_parameter(new Parameter("--ram", Parameter::NUMBER, "initial RAM quota"));
|
||||
add_parameter(new Parameter("--ram-limit", Parameter::NUMBER, "limit for expanding RAM quota"));
|
||||
add_parameter(new Parameter("--verbose", Parameter::VOID, "show diagnostics"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup subsystem in config
|
||||
*/
|
||||
Xml_node _subsystem_node(char const *name)
|
||||
{
|
||||
Xml_node node = _config.sub_node("subsystem");
|
||||
for (;; node = node.next("subsystem")) {
|
||||
if (node.attribute("name").has_value(name))
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
void execute(Command_line &cmd, Terminal::Session &terminal)
|
||||
void _execute_subsystem(char const *name, Command_line &cmd,
|
||||
Terminal::Session &terminal,
|
||||
Genode::Xml_node subsystem_node)
|
||||
{
|
||||
size_t count = 1;
|
||||
Genode::Number_of_bytes ram = 0;
|
||||
Genode::Number_of_bytes ram_limit = 0;
|
||||
|
||||
char name[128];
|
||||
name[0] = 0;
|
||||
if (cmd.argument(0, name, sizeof(name)) == false) {
|
||||
tprintf(terminal, "Error: no configuration name specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
if (cmd.argument(1, buf, sizeof(buf))) {
|
||||
tprintf(terminal, "Error: unexpected argument \"%s\"\n", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if a configuration for the subsystem exists */
|
||||
try { _subsystem_node(name); }
|
||||
catch (Xml_node::Nonexistent_sub_node) {
|
||||
tprintf(terminal, "Error: no configuration for \"%s\"\n", name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* read default RAM quota from config */
|
||||
try {
|
||||
Xml_node rsc = _subsystem_node(name).sub_node("resource");
|
||||
Xml_node rsc = subsystem_node.sub_node("resource");
|
||||
for (;; rsc = rsc.next("resource")) {
|
||||
if (rsc.attribute("name").has_value("RAM")) {
|
||||
rsc.attribute("quantum").value(&ram);
|
||||
@ -146,7 +77,7 @@ struct Start_command : Command
|
||||
char binary_name[128];
|
||||
strncpy(binary_name, name, sizeof(binary_name));
|
||||
try {
|
||||
Xml_node bin = _subsystem_node(name).sub_node("binary");
|
||||
Xml_node bin = subsystem_node.sub_node("binary");
|
||||
bin.attribute("name").value(binary_name, sizeof(binary_name));
|
||||
} catch (...) { }
|
||||
|
||||
@ -196,7 +127,7 @@ struct Start_command : Command
|
||||
|
||||
/* configure child */
|
||||
try {
|
||||
Xml_node config_node = _subsystem_node(name).sub_node("config");
|
||||
Xml_node config_node = subsystem_node.sub_node("config");
|
||||
child->configure(config_node.addr(), config_node.size());
|
||||
if (verbose)
|
||||
tprintf(terminal, " config: inline\n");
|
||||
@ -205,12 +136,86 @@ struct Start_command : Command
|
||||
tprintf(terminal, " config: none\n");
|
||||
}
|
||||
|
||||
_process_args.list.insert(&child->argument);
|
||||
_children.insert(child);
|
||||
child->start();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Start_command(Ram &ram, Genode::Cap_session &cap, Child_registry &children,
|
||||
Subsystem_config_registry &subsustem_configs,
|
||||
Signal_context_capability yield_response_sigh_cap)
|
||||
:
|
||||
Command("start", "create new subsystem"),
|
||||
_ram(ram), _children(children), _cap(cap),
|
||||
_subsystem_configs(subsustem_configs),
|
||||
_yield_response_sigh_cap(yield_response_sigh_cap)
|
||||
{
|
||||
add_parameter(new Parameter("--count", Parameter::NUMBER, "number of instances"));
|
||||
add_parameter(new Parameter("--ram", Parameter::NUMBER, "initial RAM quota"));
|
||||
add_parameter(new Parameter("--ram-limit", Parameter::NUMBER, "limit for expanding RAM quota"));
|
||||
add_parameter(new Parameter("--verbose", Parameter::VOID, "show diagnostics"));
|
||||
}
|
||||
|
||||
void _for_each_argument(Argument_fn const &fn) const override
|
||||
{
|
||||
/* functor for processing a subsystem configuration */
|
||||
auto process_subsystem_config_fn = [&] (Genode::Xml_node node) {
|
||||
|
||||
char name[Parameter::Name::size()];
|
||||
try { node.attribute("name").value(name, sizeof(name)); }
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
PWRN("Missing name in '<subsystem>' configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
char const *prefix = "config: ";
|
||||
size_t const prefix_len = strlen(prefix);
|
||||
|
||||
char help[Parameter::Short_help::size() + prefix_len];
|
||||
strncpy(help, prefix, ~0);
|
||||
try { node.attribute("help").value(help + prefix_len,
|
||||
sizeof(help) - prefix_len); }
|
||||
catch (Xml_node::Nonexistent_attribute) {
|
||||
PWRN("Missing help in '<subsystem>' configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
Argument arg(name, help);
|
||||
fn(arg);
|
||||
};
|
||||
|
||||
/* scan subsystem config registry for possible subsystem arguments */
|
||||
_subsystem_configs.for_each_config(process_subsystem_config_fn);
|
||||
}
|
||||
|
||||
void execute(Command_line &cmd, Terminal::Session &terminal)
|
||||
{
|
||||
char name[128];
|
||||
name[0] = 0;
|
||||
if (cmd.argument(0, name, sizeof(name)) == false) {
|
||||
tprintf(terminal, "Error: no configuration name specified\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[128];
|
||||
if (cmd.argument(1, buf, sizeof(buf))) {
|
||||
tprintf(terminal, "Error: unexpected argument \"%s\"\n", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
_subsystem_configs.for_config(name, [&] (Genode::Xml_node node)
|
||||
{
|
||||
_execute_subsystem(name, cmd, terminal, node);
|
||||
});
|
||||
|
||||
} catch (Subsystem_config_registry::Nonexistent_subsystem_config) {
|
||||
tprintf(terminal, "Error: no configuration for \"%s\"\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
List<Argument> &arguments() { return _arguments; }
|
||||
};
|
||||
|
||||
|
161
repos/os/src/app/cli_monitor/subsystem_config_registry.h
Normal file
161
repos/os/src/app/cli_monitor/subsystem_config_registry.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* \brief Registry of subsystem configuration
|
||||
* \author Norman Feske
|
||||
* \date 2015-01-27
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SUBSYSTEM_CONFIG_REGISTRY_H_
|
||||
#define _SUBSYSTEM_CONFIG_REGISTRY_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <vfs/file_system.h>
|
||||
#include <vfs/vfs_handle.h>
|
||||
|
||||
class Subsystem_config_registry
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Exception type
|
||||
*/
|
||||
class Nonexistent_subsystem_config { };
|
||||
|
||||
private:
|
||||
|
||||
Vfs::File_system &_fs;
|
||||
|
||||
enum { CONFIG_BUF_SIZE = 32*1024 };
|
||||
char _config_buf[CONFIG_BUF_SIZE];
|
||||
|
||||
char const *_subsystems_path() { return "/subsystems"; }
|
||||
char const *_subsystem_suffix() { return ".subsystem"; }
|
||||
|
||||
/**
|
||||
* Return index of ".subsystem" suffix in dirent name
|
||||
*
|
||||
* \return index, or 0 if no matching suffix could be found
|
||||
*/
|
||||
unsigned _subsystem_suffix(Vfs::Directory_service::Dirent const &dirent)
|
||||
{
|
||||
unsigned found = 0;
|
||||
for (unsigned i = 0; i < sizeof(dirent.name) && dirent.name[i]; i++)
|
||||
if (Genode::strcmp(_subsystem_suffix(), &dirent.name[i]) == 0)
|
||||
found = i;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Subsystem_config_registry(Vfs::File_system &fs)
|
||||
:
|
||||
_fs(fs)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Execute functor 'fn' for specified subsystem name
|
||||
*
|
||||
* The functor is called with the subsystem XML node as argument
|
||||
*
|
||||
* \throw Nonexistent_subsystem_config
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_config(char const *name, FN const &fn)
|
||||
{
|
||||
/*
|
||||
* Load subsystem configuration
|
||||
*/
|
||||
|
||||
Genode::Path<256> path(_subsystems_path());
|
||||
path.append("/");
|
||||
path.append(name);
|
||||
path.append(_subsystem_suffix());
|
||||
|
||||
Vfs::Vfs_handle *handle = nullptr;
|
||||
|
||||
Vfs::Directory_service::Open_result const open_result =
|
||||
_fs.open(path.base(),
|
||||
Vfs::Directory_service::OPEN_MODE_RDONLY,
|
||||
&handle);
|
||||
|
||||
Vfs::Vfs_handle::Guard handle_guard(handle);
|
||||
|
||||
if (open_result != Vfs::Directory_service::OPEN_OK) {
|
||||
PERR("could not open '%s', err=%d", path.base(), open_result);
|
||||
throw Nonexistent_subsystem_config();
|
||||
}
|
||||
|
||||
Vfs::file_size out_count = 0;
|
||||
Vfs::File_io_service::Read_result read_result =
|
||||
handle->fs().read(handle, _config_buf, sizeof(_config_buf), out_count);
|
||||
|
||||
if (read_result != Vfs::File_io_service::READ_OK) {
|
||||
PERR("could not read '%s', err=%d", path.base(), read_result);
|
||||
throw Nonexistent_subsystem_config();
|
||||
}
|
||||
|
||||
try {
|
||||
Genode::Xml_node subsystem_node(_config_buf, out_count);
|
||||
fn(subsystem_node);
|
||||
|
||||
} catch (Genode::Xml_node::Invalid_syntax) {
|
||||
PERR("subsystem configuration has invalid syntax");
|
||||
throw Nonexistent_subsystem_config();
|
||||
|
||||
} catch (Genode::Xml_node::Nonexistent_sub_node) {
|
||||
PERR("invalid subsystem configuration");
|
||||
throw Nonexistent_subsystem_config();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call specified functor for each subsystem config
|
||||
*/
|
||||
template <typename FN>
|
||||
void for_each_config(FN const &fn)
|
||||
{
|
||||
/* iterate over the directory entries */
|
||||
for (unsigned i = 0;; i++) {
|
||||
|
||||
Vfs::Directory_service::Dirent dirent;
|
||||
|
||||
Vfs::Directory_service::Dirent_result dirent_result =
|
||||
_fs.dirent(_subsystems_path(), i, dirent);
|
||||
|
||||
if (dirent_result != Vfs::Directory_service::DIRENT_OK) {
|
||||
PERR("could not access directory '%s'", _subsystems_path());
|
||||
return;
|
||||
}
|
||||
|
||||
if (dirent.type == Vfs::Directory_service::DIRENT_TYPE_END)
|
||||
return;
|
||||
|
||||
unsigned const subsystem_suffix = _subsystem_suffix(dirent);
|
||||
|
||||
/* if file has a matching suffix, apply 'fn' */
|
||||
if (subsystem_suffix) {
|
||||
|
||||
/* subsystem name is file name without the suffix */
|
||||
char name[sizeof(dirent.name)];
|
||||
Genode::strncpy(name, dirent.name, subsystem_suffix + 1);
|
||||
|
||||
try {
|
||||
for_config(name, fn);
|
||||
} catch (Nonexistent_subsystem_config) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _PROCESS_ARG_REGISTRY_H_ */
|
@ -1,6 +1,6 @@
|
||||
TARGET = cli_monitor
|
||||
SRC_CC = main.cc
|
||||
LIBS = base cli_monitor config
|
||||
LIBS = base cli_monitor config vfs ld
|
||||
INC_DIR += $(PRG_DIR)
|
||||
|
||||
ifeq ($(findstring arm, $(SPECS)), arm)
|
||||
|
@ -16,23 +16,30 @@
|
||||
|
||||
/* local includes */
|
||||
#include <child_registry.h>
|
||||
#include <process_arg_registry.h>
|
||||
|
||||
struct Yield_command : Command
|
||||
{
|
||||
Child_registry &_children;
|
||||
Process_arg_registry &_process_args;
|
||||
|
||||
Yield_command(Child_registry &children, Process_arg_registry &process_args)
|
||||
Yield_command(Child_registry &children)
|
||||
:
|
||||
Command("yield", "instruct subsystem to yield resources"),
|
||||
_children(children),
|
||||
_process_args(process_args)
|
||||
_children(children)
|
||||
{
|
||||
add_parameter(new Parameter("--ram", Parameter::NUMBER, "RAM quota to free"));
|
||||
add_parameter(new Parameter("--greedy", Parameter::VOID, "withdraw yielded RAM quota"));
|
||||
}
|
||||
|
||||
void _for_each_argument(Argument_fn const &fn) const override
|
||||
{
|
||||
auto child_name_fn = [&] (char const *child_name) {
|
||||
Argument arg(child_name, "");
|
||||
fn(arg);
|
||||
};
|
||||
|
||||
_children.for_each_child_name(child_name_fn);
|
||||
}
|
||||
|
||||
void execute(Command_line &cmd, Terminal::Session &terminal)
|
||||
{
|
||||
char label[128];
|
||||
@ -64,8 +71,6 @@ struct Yield_command : Command
|
||||
tprint_bytes(terminal, ram);
|
||||
tprintf(terminal, "\n");
|
||||
}
|
||||
|
||||
List<Argument> &arguments() { return _process_args.list; }
|
||||
};
|
||||
|
||||
#endif /* _YIELD_COMMAND_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user