Emery Hemingway
82a683eccc
Reduce the size and forward compatibility of VFS file-system constructors by passing an object holding accessors for 'Genode::Env', 'Genode::Allocator', response handlers, and the root file-system. Fix #2742
227 lines
6.1 KiB
C++
227 lines
6.1 KiB
C++
/*
|
|
* \brief Simple command-line interface for managing Genode subsystems
|
|
* \author Norman Feske
|
|
* \date 2013-03-18
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2013-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/attached_rom_dataspace.h>
|
|
#include <vfs/simple_env.h>
|
|
#include <base/component.h>
|
|
|
|
/* public CLI-monitor includes */
|
|
#include <cli_monitor/ram.h>
|
|
|
|
/* local includes */
|
|
#include <line_editor.h>
|
|
#include <command_line.h>
|
|
#include <format_util.h>
|
|
#include <status_command.h>
|
|
#include <kill_command.h>
|
|
#include <start_command.h>
|
|
#include <help_command.h>
|
|
#include <yield_command.h>
|
|
#include <ram_command.h>
|
|
|
|
namespace Cli_monitor {
|
|
|
|
struct Main;
|
|
using namespace Genode;
|
|
}
|
|
|
|
|
|
/******************
|
|
** Main program **
|
|
******************/
|
|
|
|
struct Cli_monitor::Main
|
|
{
|
|
Genode::Env &_env;
|
|
|
|
Terminal::Connection _terminal { _env };
|
|
|
|
Command_registry _commands { };
|
|
|
|
Child_registry _children { };
|
|
|
|
Command *_lookup_command(char const *buf)
|
|
{
|
|
Token token(buf);
|
|
for (Command *curr = _commands.first(); curr; curr = curr->next())
|
|
if (strcmp(token.start(), curr->name().string(), token.len()) == 0
|
|
&& strlen(curr->name().string()) == token.len())
|
|
return curr;
|
|
return 0;
|
|
}
|
|
|
|
enum { COMMAND_MAX_LEN = 1000 };
|
|
char _command_buf[COMMAND_MAX_LEN];
|
|
Line_editor _line_editor {
|
|
"genode> ", _command_buf, sizeof(_command_buf), _terminal, _commands };
|
|
|
|
void _handle_terminal_read_avail();
|
|
|
|
Signal_handler<Main> _terminal_read_avail_handler {
|
|
_env.ep(), *this, &Main::_handle_terminal_read_avail };
|
|
|
|
/**
|
|
* Handler for child yield responses, or RAM resource-avail signals
|
|
*/
|
|
void _handle_yield_response()
|
|
{
|
|
for (Child *child = _children.first(); child; child = child->next())
|
|
child->try_response_to_resource_request();
|
|
}
|
|
|
|
Signal_handler<Main> _yield_response_handler {
|
|
_env.ep(), *this, &Main::_handle_yield_response };
|
|
|
|
void _handle_child_exit()
|
|
{
|
|
Child *next = nullptr;
|
|
for (Child *child = _children.first(); child; child = next) {
|
|
next = child->next();
|
|
if (child->exited()) {
|
|
_children.remove(child);
|
|
Genode::destroy(_heap, child);
|
|
}
|
|
}
|
|
}
|
|
|
|
Signal_handler<Main> _child_exit_handler {
|
|
_env.ep(), *this, &Main::_handle_child_exit };
|
|
|
|
void _handle_yield_broadcast()
|
|
{
|
|
/*
|
|
* Compute argument of yield request to be broadcasted to all
|
|
* processes.
|
|
*/
|
|
size_t amount = 0;
|
|
|
|
/* amount needed to reach preservation limit */
|
|
Ram::Status ram_status = _ram.status();
|
|
if (ram_status.avail < ram_status.preserve)
|
|
amount += ram_status.preserve - ram_status.avail;
|
|
|
|
/* sum of pending resource requests */
|
|
for (Child *child = _children.first(); child; child = child->next())
|
|
amount += child->requested_ram_quota();
|
|
|
|
for (Child *child = _children.first(); child; child = child->next())
|
|
child->yield(amount, true);
|
|
}
|
|
|
|
Signal_handler<Main> _yield_broadcast_handler {
|
|
_env.ep(), *this, &Main::_handle_yield_broadcast };
|
|
|
|
Genode::Attached_rom_dataspace _config { _env, "config" };
|
|
|
|
Xml_node _vfs_config() const
|
|
{
|
|
try { return _config.xml().sub_node("vfs"); }
|
|
catch (Genode::Xml_node::Nonexistent_sub_node) {
|
|
Genode::error("missing '<vfs>' configuration");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
size_t _ram_preservation_from_config() const
|
|
{
|
|
if (!_config.xml().has_sub_node("preservation"))
|
|
return 0;
|
|
|
|
return _config.xml().sub_node("preservation")
|
|
.attribute_value("name", Genode::Number_of_bytes(0));
|
|
}
|
|
|
|
Ram _ram { _env.ram(), _env.ram_session_cap(), _ram_preservation_from_config(),
|
|
_yield_broadcast_handler, _yield_response_handler };
|
|
|
|
Heap _heap { _env.ram(), _env.rm() };
|
|
|
|
Vfs::Simple_env _vfs_env { _env, _heap, _vfs_config() };
|
|
|
|
Subsystem_config_registry _subsystem_config_registry { _vfs_env.root_dir(), _heap, _env.ep() };
|
|
|
|
template <typename T>
|
|
struct Registered : T
|
|
{
|
|
template <typename... ARGS>
|
|
Registered(Command_registry &commands, ARGS &&... args)
|
|
: T(args...) { commands.insert(this); }
|
|
};
|
|
|
|
/* initialize generic commands */
|
|
Registered<Help_command> _help_command { _commands };
|
|
Registered<Kill_command> _kill_command { _commands, _children, _heap };
|
|
Registered<Start_command> _start_command { _commands, _ram, _heap,
|
|
_env.pd(), _env.pd_session_cap(),
|
|
_env.ram(), _env.ram_session_cap(),
|
|
_env.rm(), _children,
|
|
_subsystem_config_registry,
|
|
_yield_response_handler,
|
|
_child_exit_handler };
|
|
Registered<Status_command> _status_command { _commands, _ram, _children };
|
|
Registered<Yield_command> _yield_command { _commands, _children };
|
|
Registered<Ram_command> _ram_command { _commands, _children, _ram };
|
|
|
|
Main(Env &env) : _env(env)
|
|
{
|
|
_terminal.read_avail_sigh(_terminal_read_avail_handler);
|
|
}
|
|
};
|
|
|
|
|
|
void Cli_monitor::Main::_handle_terminal_read_avail()
|
|
{
|
|
/* supply pending terminal input to line editor */
|
|
while (_terminal.avail() && !_line_editor.completed()) {
|
|
char c = 0;
|
|
_terminal.read(&c, 1);
|
|
_line_editor.submit_input(c);
|
|
}
|
|
|
|
if (!_line_editor.completed())
|
|
return;
|
|
|
|
Command *command = _lookup_command(_command_buf);
|
|
if (!command) {
|
|
Token cmd_name(_command_buf);
|
|
tprintf(_terminal, "Error: unknown command \"");
|
|
_terminal.write(cmd_name.start(), cmd_name.len());
|
|
tprintf(_terminal, "\"\n");
|
|
_line_editor.reset();
|
|
return;
|
|
}
|
|
|
|
/* validate parameters against command meta data */
|
|
Command_line cmd_line(_command_buf, *command);
|
|
Token unexpected = cmd_line.unexpected_parameter();
|
|
if (unexpected) {
|
|
tprintf(_terminal, "Error: unexpected parameter \"");
|
|
_terminal.write(unexpected.start(), unexpected.len());
|
|
tprintf(_terminal, "\"\n");
|
|
_line_editor.reset();
|
|
return;
|
|
}
|
|
command->execute(cmd_line, _terminal);
|
|
|
|
/*
|
|
* The command might result in a change of the RAM usage. Validate
|
|
* that the preservation is satisfied.
|
|
*/
|
|
_ram.validate_preservation();
|
|
_line_editor.reset();
|
|
}
|
|
|
|
|
|
void Component::construct(Genode::Env &env) { static Cli_monitor::Main main(env); }
|