322 lines
8.8 KiB
C++
322 lines
8.8 KiB
C++
/*
|
|
* \brief Child representation
|
|
* \author Norman Feske
|
|
* \date 2018-01-23
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2018 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.
|
|
*/
|
|
|
|
#ifndef _CHILD_H_
|
|
#define _CHILD_H_
|
|
|
|
/* Genode includes */
|
|
#include <base/log.h>
|
|
#include <util/list_model.h>
|
|
#include <base/service.h>
|
|
#include <os/reporter.h>
|
|
#include <os/buffered_xml.h>
|
|
#include <depot/archive.h>
|
|
#include <timer_session/connection.h>
|
|
#include <log_session/log_session.h>
|
|
|
|
/* local includes */
|
|
#include <list.h>
|
|
|
|
namespace Depot_deploy {
|
|
|
|
using namespace Depot;
|
|
|
|
struct Result
|
|
{
|
|
Genode::size_t failed { 0 };
|
|
Genode::size_t succeeded { 0 };
|
|
Genode::size_t skipped { 0 };
|
|
|
|
|
|
/*********
|
|
** log **
|
|
*********/
|
|
|
|
void print(Genode::Output &output) const;
|
|
};
|
|
|
|
class Child;
|
|
class Event;
|
|
class Timeout_event;
|
|
class Log_event;
|
|
}
|
|
|
|
|
|
class Depot_deploy::Event
|
|
{
|
|
public:
|
|
|
|
using Meaning_string = Genode::String<12>;
|
|
|
|
struct Invalid : Genode::Exception { };
|
|
|
|
enum class Type { LOG, TIMEOUT };
|
|
|
|
private:
|
|
|
|
Meaning_string const _meaning;
|
|
Type const _type;
|
|
|
|
public:
|
|
|
|
Event(Genode::Xml_node const &node,
|
|
Type type);
|
|
|
|
bool has_type(Type type) const { return _type == type; };
|
|
|
|
Meaning_string const &meaning() const { return _meaning; }
|
|
};
|
|
|
|
|
|
class Depot_deploy::Log_event : public Event,
|
|
public List<Log_event>::Element
|
|
{
|
|
public:
|
|
|
|
using Line = Genode::String<Log_session::MAX_STRING_LEN + 160 + 3>;
|
|
|
|
private:
|
|
|
|
char const *_base;
|
|
Genode::size_t const _size;
|
|
char const *_remaining_base;
|
|
char const *_remaining_end;
|
|
bool _reset_retry { false };
|
|
char const *_reset_to;
|
|
|
|
public:
|
|
|
|
Log_event(Genode::Xml_node const &xml);
|
|
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
Genode::size_t size() const { return _size; }
|
|
char const * base() const { return _base; }
|
|
char const * &reset_to() { return _reset_to; }
|
|
bool &reset_retry() { return _reset_retry; }
|
|
char const * &remaining_base() { return _remaining_base; }
|
|
char const * &remaining_end() { return _remaining_end; }
|
|
};
|
|
|
|
|
|
class Depot_deploy::Timeout_event : public Event,
|
|
public List<Timeout_event>::Element
|
|
{
|
|
private:
|
|
|
|
Child &_child;
|
|
Timer::Connection &_timer;
|
|
Genode::uint64_t const _sec;
|
|
Timer::One_shot_timeout<Timeout_event> _timeout;
|
|
|
|
void _handle_timeout(Duration);
|
|
|
|
public:
|
|
|
|
struct Invalid : Exception { };
|
|
|
|
Timeout_event(Timer::Connection &timer,
|
|
Child &child,
|
|
Genode::Xml_node const &event);
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
Genode::uint64_t sec() const { return _sec; }
|
|
};
|
|
|
|
|
|
class Depot_deploy::Child : public List_model<Child>::Element
|
|
{
|
|
public:
|
|
|
|
typedef String<100> Name;
|
|
typedef String<80> Binary_name;
|
|
typedef String<80> Config_name;
|
|
typedef String<32> Depot_rom_server;
|
|
typedef String<16> State_name;
|
|
typedef String<100> Launcher_name;
|
|
typedef String<128> Conclusion;
|
|
|
|
private:
|
|
|
|
/*
|
|
* State of the condition check for generating the start node of
|
|
* the child. I.e., if the child is complete and configured but
|
|
* a used server component is missing, we need to suppress the start
|
|
* node until the condition is satisfied.
|
|
*/
|
|
enum Condition { UNCHECKED, SATISFIED, UNSATISFIED };
|
|
enum State { UNFINISHED, SUCCEEDED, FAILED, SKIPPED };
|
|
|
|
bool const _skip;
|
|
Allocator &_alloc;
|
|
Reconstructible<Buffered_xml> _start_xml;
|
|
Constructible<Buffered_xml> _launcher_xml { };
|
|
Constructible<Buffered_xml> _pkg_xml { };
|
|
Condition _condition { UNCHECKED };
|
|
Name const _name;
|
|
Archive::Path _blueprint_pkg_path { _config_pkg_path() };
|
|
Number_of_bytes _pkg_ram_quota { 0 };
|
|
unsigned long _pkg_cap_quota { 0 };
|
|
Binary_name _binary_name { };
|
|
Config_name _config_name { };
|
|
bool _pkg_incomplete { false };
|
|
List<Timeout_event> _timeout_events { };
|
|
List<Log_event> _log_events { };
|
|
Timer::Connection &_timer;
|
|
State _state { UNFINISHED };
|
|
Signal_transmitter _config_handler;
|
|
bool _running { false };
|
|
Conclusion _conclusion { };
|
|
|
|
bool _defined_by_launcher() const;
|
|
|
|
Archive::Path _config_pkg_path() const;
|
|
|
|
Launcher_name _launcher_name() const;
|
|
|
|
bool _configured() const;
|
|
|
|
void _gen_routes(Xml_generator &,
|
|
Xml_node ,
|
|
Depot_rom_server const &,
|
|
Depot_rom_server const &) const;
|
|
|
|
static void _gen_provides_sub_node(Xml_generator &xml,
|
|
Xml_node service,
|
|
Xml_node::Type const &node_type,
|
|
Service::Name const &service_name);
|
|
|
|
static void _gen_copy_of_sub_node(Xml_generator &xml,
|
|
Xml_node from_node,
|
|
Xml_node::Type const &sub_node_type);
|
|
|
|
void _finished(State state,
|
|
Event const &event,
|
|
Genode::uint64_t const time_us);
|
|
|
|
State_name _padded_state_name() const;
|
|
|
|
public:
|
|
|
|
Genode::uint64_t init_time_us { 0 };
|
|
|
|
Child(Genode::Allocator &alloc,
|
|
Genode::Xml_node start_node,
|
|
Timer::Connection &timer,
|
|
Genode::Signal_context_capability const &config_handler);
|
|
|
|
~Child();
|
|
|
|
void log_session_write(Log_event::Line const &log_line);
|
|
|
|
void print_conclusion();
|
|
|
|
void conclusion(Result &result);
|
|
|
|
void event_occured(Event const &event,
|
|
Genode::uint64_t const time_us);
|
|
|
|
void apply_config(Xml_node start_node);
|
|
|
|
void apply_blueprint(Xml_node pkg);
|
|
|
|
void apply_launcher(Launcher_name const &name,
|
|
Xml_node launcher);
|
|
|
|
void mark_as_incomplete(Xml_node missing);
|
|
|
|
/**
|
|
* Reconsider deployment of child after installing missing archives
|
|
*/
|
|
void reset_incomplete();
|
|
|
|
bool gen_query(Xml_generator &xml) const;
|
|
|
|
/**
|
|
* Generate start node of init configuration
|
|
*
|
|
* \param common session routes to be added in addition to
|
|
* the ones found in the pkg blueprint
|
|
* \param cached_depot_rom name of the server that provides the depot
|
|
* content as ROM modules. If the string is
|
|
* invalid, ROM requests are routed to the
|
|
* parent.
|
|
* \param uncached_depot_rom name of the depot-ROM server used to obtain
|
|
* the content of the depot user "local", which
|
|
* is assumed to be mutable
|
|
*/
|
|
void gen_start_node(Xml_generator &,
|
|
Xml_node common,
|
|
Depot_rom_server const &cached_depot_rom,
|
|
Depot_rom_server const &uncached_depot_rom);
|
|
|
|
/**
|
|
* Generate installation entry needed for the completion of the child
|
|
*/
|
|
void gen_installation_entry(Xml_generator &xml) const;
|
|
|
|
template <typename FN>
|
|
void apply_if_unsatisfied(FN const &fn) const
|
|
{
|
|
if (_skip) {
|
|
return; }
|
|
|
|
Xml_node launcher_xml = _launcher_xml.constructed()
|
|
? _launcher_xml->xml()
|
|
: Xml_node("<empty/>");
|
|
|
|
if (_condition == UNSATISFIED && _start_xml.constructed())
|
|
fn(_start_xml->xml(), launcher_xml);
|
|
}
|
|
|
|
/*
|
|
* \return true if condition changed
|
|
*/
|
|
template <typename COND_FN>
|
|
bool apply_condition(COND_FN const &fn)
|
|
{
|
|
if (_skip) {
|
|
return false; }
|
|
|
|
Condition const orig_condition = _condition;
|
|
|
|
Xml_node launcher_xml = _launcher_xml.constructed()
|
|
? _launcher_xml->xml()
|
|
: Xml_node("<empty/>");
|
|
|
|
if (_start_xml.constructed())
|
|
_condition = fn(_start_xml->xml(), launcher_xml)
|
|
? SATISFIED : UNSATISFIED;
|
|
|
|
return _condition != orig_condition;
|
|
}
|
|
|
|
|
|
/***************
|
|
** Accessors **
|
|
***************/
|
|
|
|
Name name() const { return _name; }
|
|
bool pkg_incomplete() const { return _pkg_incomplete; }
|
|
bool running() const { return _running; }
|
|
bool finished() const { return _state != UNFINISHED; }
|
|
};
|
|
|
|
#endif /* _CHILD_H_ */
|