sculpt: separate launchers from deploy config

The most important route of each launcher is at the top of routes and
will be used to layout the graph topology of the runtime view.

By caching the state reports generated by the runtime init, the sculpt
manager becomes able to quickly check for the presence of components. So
we can apply routing-dependency checks not only prior starting
components but also while components are running.

Fixes #2938
Fixes #2912
This commit is contained in:
Norman Feske 2018-08-15 17:39:08 +02:00 committed by Christian Helmuth
parent 240e70d989
commit 25ee872703
29 changed files with 548 additions and 261 deletions

View File

@ -45,3 +45,4 @@ _/src/zlib
_/src/menu_view
_/src/gpt_write
_/src/sculpt_manager
_/src/fs_query

View File

@ -110,6 +110,7 @@ install_config {
<rom name="de_ch.chargen"/>
<rom name="special.chargen"/>
<rom name="vimrc"/>
<tar name="launcher.tar"/>
<inline name="system">} [config_system_content] {
</inline>
</import>
@ -514,7 +515,7 @@ close $fd
#
# Manual configuration of deploy runtime
# Configuration of deploy runtime
#
# This configuration is not provided as a file at run/sculpt/ because some
# parts need to be filled in at run-script execution time, in particular the
@ -532,200 +533,24 @@ append manual_deploy_config {
<service name="Timer"> <parent/> </service>
</common_routes>
<!--
<start name="fonts_fs" pkg="} [depot_user]/pkg/[current_pkg fonts_fs] {">
<route>
<service name="ROM" label="config"> <parent label="config -> managed/fonts"/> </service>
</route>
</start>
<start name="wm" pkg="} [depot_user]/pkg/[current_pkg themed_wm] {">
<route>
<service name="Nitpicker" label="wm -> "> <parent label="focus"/> </service>
<service name="Nitpicker"> <parent/> </service>
</route>
</start>
<start name="backdrop" pkg="} [depot_user]/pkg/[current_pkg sticks_blue_backdrop] {">
<route>
<service name="Nitpicker"> <parent label="backdrop"/> </service>
</route>
</start>
-->
<!--
<start name="nano3d" pkg="} [depot_user]/pkg/[current_pkg nano3d] {">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</start>
-->
<!--
<start name="noux" pkg="} [depot_user]/pkg/[current_pkg noux-system] {">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="File_system" label="config">
<parent label="config"/> </service>
<service name="File_system" label="report">
<parent label="report"/> </service>
<service name="File_system" label="fonts">
<child name="fonts_fs"/> </service>
<service name="File_system" label="target">
<child name="default_fs_rw"/> </service>
<service name="ROM" label_last="vimrc">
<parent label="config -> vimrc"/> </service>
</route>
</start>
-->
<!--
<start name="shared_fs" pkg="} [depot_user]/pkg/[current_pkg chroot] {">
<route>
<service name="File_system"> <child name="default_fs_rw"/> </service>
</route>
<config> <default-policy path="/shared" writeable="yes"/> </config>
</start>
<start name="usb_devices_rom" pkg="} [depot_user]/pkg/[current_pkg rom_filter] {">
<config>
<output node="devices">
<inline>
</inline>
</output>
</config>
</start>
-->
<!--
<start name="vm_fs" pkg="} [depot_user]/pkg/[current_pkg chroot] {">
<route>
<service name="File_system"> <child name="default_fs_rw"/> </service>
</route>
<config> <default-policy path="/vm/debian" writeable="yes"/> </config>
</start>
-->
<!--
<start name="download_debian" pkg="cnuke/pkg/download_debian/2018-06-13">
<route>
<service name="File_system" label="fonts"> <child name="fonts_fs"/> </service>
<service name="File_system" label="target"> <child name="vm_fs"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="RM"> <parent/> </service>
</route>
</start>
-->
<!--
<start name="vm" ram="4300M" pkg="} [depot_user]/pkg/[current_pkg vbox5-nova-sculpt] {">
<route>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="ROM" label="usb_devices"> <child name="usb_devices_rom"/> </service>
<service name="Report" label="shape"> <parent label="wm -> wm -> vm -> shape"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="Report"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Usb"> <parent/> </service>
<service name="File_system" label="vm"> <child name="vm_fs"/> </service>
<service name="File_system" label="shared"> <child name="shared_fs"/> </service>
</route>
</start>
-->
<!--
<start name="top_view" pkg="alex-ab/pkg/top_view/2018-06-27">
<route>
<service name="TRACE"> <parent/> </service>
<service name="Timer"> <parent/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="File_system" label="fonts">
<child name="fonts_fs"/> </service>
</route>
</start>
-->
<!--
<start name="2048" pkg="ehmry/pkg/2048/18.05">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</start>
-->
<!--
<start name="vbox5-tc-browser" pkg="alex-ab/pkg/vbox5-tc-firefox-nova-sculpt/2018-07-13">
<route>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="Report" label="shape"> <parent label="wm -> wm -> vbox5-tc-browser -> shape"/> </service>
<service name="RM"> <parent/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="File_system" label="shared"> <child name="shared_fs"/> </service>
</route>
</start>
-->
<!--
<start name="seoul-vmm-browser" pkg="alex-ab/pkg/seoul-nova-sculpt/2018-07-13">
<route>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
</route>
</start>
-->
<!--
<start name="qt5_textedit" pkg="genodelabs/pkg/qt5_textedit/2018-06-12">
<route>
<service name="File_system" label="rw"> <parent label="config"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Report" label="shape"> <parent label="wm -> wm -> qt5_textedit -> shape"/> </service>
</route>
</start>
-->
<!--
<start name="report_dump" pkg="} [depot_user]/pkg/[current_pkg report_dump] {">
<route>
<service name="File_system" label="report">
<parent label="report"/> </service>
<service name="File_system" label="target">
<child name="default_fs_rw"/> </service>
</route>
</start>
-->
<!--
<start name="acpica" pkg="} [depot_user]/pkg/[current_pkg acpica] {">
<config reset="no" poweroff="no" report="yes" act_as_acpi_drv="no"/>
<route>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="Platform"> <parent/> </service>
<service name="IO_MEM"> <parent/> </service>
<service name="IO_PORT"> <parent/> </service>
<service name="IRQ"> <parent/> </service>
<service name="Report"> <parent/> </service>
</route>
</start>
-->
<!--
<start name="gambatte" pkg="ehmry/pkg/gambatte/2018-07-08">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</start>
-->
<!-- <start name="shared_fs"/> -->
<!-- <start name="usb_devices_rom"/> -->
<!-- <start name="vm_fs"/> -->
<!-- <start name="fonts_fs"/> -->
<!-- <start name="wm"/> -->
<!-- <start name="backdrop"/> -->
<!-- <start name="nano3d"/> -->
<!-- <start name="noux" launcher="noux-system"/> -->
<!-- <start name="download_debian"/> -->
<!-- <start name="vm"/> -->
<!-- <start name="top_view"/> -->
<!-- <start name="2048"/> -->
<!-- <start name="vbox5-tc-browser"/> -->
<!-- <start name="seoul-vmm-browser"/> -->
<!-- <start name="config_editor"/> -->
<!-- <start name="report_dump"/> -->
<!-- <start name="acpica"/> -->
<!-- <start name="gambatte"/> -->
</config>}
@ -734,6 +559,51 @@ puts $fd $manual_deploy_config
close $fd
#
# Install launcher snippets
#
# The launcher snippets are wrapped into a tar archive to be loaded as boot
# module. This procedure involves the following steps:
#
# The launcher snippets are copied from run/sculpt/launcher/ to
# [run_dir]/genode/launcher. Each launcher is inspected regarding its 'pkg'
# attribute. If its 'pkg' attribute contains a single identifier (rather than
# a valid pkg path), the attribute value is replaced by a valid pkg path
# referring to the current version of the pkg and the [depot_user]. The
# filtered launchers are archived into 'launcher.tar' and removed from the
# [run_dir].
#
set launchers [glob -tails -directory [genode_dir]/repos/gems/run/sculpt/launcher/ *]
foreach file $launchers {
# skip backup files
if {[regexp {~$} $file dummy]} { continue }
set fd [open [genode_dir]/repos/gems/run/sculpt/launcher/$file r]
set content [read $fd]
close $fd
# filter 'pkg' attribute
set pattern {(\<launcher[^\>]+?pkg=")([^/]+)(")}
if {[regexp $pattern $content dummy head pkg tail]} {
set pkg_path [depot_user]/pkg/[current_pkg $pkg]
regsub $pattern $content "$head$pkg_path$tail" content
}
# write filtered launcher snippet
file mkdir [run_dir]/genode/launcher
set fd [open [run_dir]/genode/launcher/$file w]
puts $fd $content
close $fd
}
# wrap launcher snippets into tar archive and remove individual snippets
exec tar cf [run_dir]/genode/launcher.tar -C [run_dir]/genode launcher
exec rm -r [run_dir]/genode/launcher
#
# Create boot image
#

View File

@ -0,0 +1,5 @@
<launcher pkg="ehmry/pkg/2048/18.05">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,11 @@
<launcher pkg="acpica">
<config reset="no" poweroff="no" report="yes" act_as_acpi_drv="no"/>
<route>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="Platform"> <parent/> </service>
<service name="IO_MEM"> <parent/> </service>
<service name="IO_PORT"> <parent/> </service>
<service name="IRQ"> <parent/> </service>
<service name="Report"> <parent/> </service>
</route>
</launcher>

View File

@ -0,0 +1,5 @@
<launcher pkg="sticks_blue_backdrop">
<route>
<service name="Nitpicker"> <parent label="backdrop"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,7 @@
<launcher pkg="qt5_textedit">
<route>
<service name="File_system" label="rw"> <parent label="config"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Report" label="shape"> <parent label="wm -> wm -> qt5_textedit -> shape"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,9 @@
<launcher pkg="cnuke/pkg/download_debian/2018-06-13">
<route>
<service name="File_system" label="target"> <child name="vm_fs"/> </service>
<service name="File_system" label="fonts"> <child name="fonts_fs"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="RM"> <parent/> </service>
</route>
</launcher>

View File

@ -0,0 +1,5 @@
<launcher pkg="fonts_fs">
<route>
<service name="ROM" label="config"> <parent label="config -> managed/fonts"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,5 @@
<launcher pkg="ehmry/pkg/gambatte/2018-07-08">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,5 @@
<launcher pkg="nano3d">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,15 @@
<launcher pkg="noux-system">
<route>
<service name="File_system" label="target">
<child name="default_fs_rw"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="File_system" label="config">
<parent label="config"/> </service>
<service name="File_system" label="report">
<parent label="report"/> </service>
<service name="File_system" label="fonts">
<child name="fonts_fs"/> </service>
<service name="ROM" label_last="vimrc">
<parent label="config -> vimrc"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,8 @@
<launcher pkg="report_dump">
<route>
<service name="File_system" label="report">
<parent label="report"/> </service>
<service name="File_system" label="target">
<child name="default_fs_rw"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,9 @@
<launcher pkg="alex-ab/pkg/seoul-nova-sculpt/2018-07-13">
<route>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,6 @@
<launcher pkg="chroot">
<route>
<service name="File_system"> <child name="default_fs_rw"/> </service>
</route>
<config> <default-policy path="/shared" writeable="yes"/> </config>
</launcher>

View File

@ -0,0 +1,9 @@
<launcher pkg="alex-ab/pkg/top_view/2018-06-27">
<route>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="TRACE"> <parent/> </service>
<service name="Timer"> <parent/> </service>
<service name="File_system" label="fonts">
<child name="fonts_fs"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,8 @@
<launcher pkg="rom_filter">
<config>
<output node="devices">
<inline>
</inline>
</output>
</config>
</launcher>

View File

@ -0,0 +1,12 @@
<launcher pkg="alex-ab/pkg/vbox5-tc-firefox-nova-sculpt/2018-07-13">
<route>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="Report" label="shape"> <parent label="wm -> wm -> vbox5-tc-browser -> shape"/> </service>
<service name="RM"> <parent/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="File_system" label="shared"> <child name="shared_fs"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,16 @@
<launcher ram="4300M" pkg="vbox5-nova-sculpt">
<route>
<service name="File_system" label="vm"> <child name="vm_fs"/> </service>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info"> <parent/> </service>
<service name="ROM" label="usb_devices"> <child name="usb_devices_rom"/> </service>
<service name="Report" label="shape"> <parent label="wm -> wm -> vm -> shape"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="Nic"> <child name="nic_router"/> </service>
<service name="Report"> <parent/> </service>
<service name="RM"> <parent/> </service>
<service name="Rtc"> <parent/> </service>
<service name="Usb"> <parent/> </service>
<service name="File_system" label="shared"> <child name="shared_fs"/> </service>
</route>
</launcher>

View File

@ -0,0 +1,6 @@
<launcher pkg="chroot">
<route>
<service name="File_system"> <child name="default_fs_rw"/> </service>
</route>
<config> <default-policy path="/vm/debian" writeable="yes"/> </config>
</launcher>

View File

@ -0,0 +1,6 @@
<launcher pkg="themed_wm">
<route>
<service name="Nitpicker" label="wm -> "> <parent label="focus"/> </service>
<service name="Nitpicker"> <parent/> </service>
</route>
</launcher>

View File

@ -35,13 +35,15 @@ class Depot_deploy::Child : public List_model<Child>::Element
typedef String<80> Binary_name;
typedef String<80> Config_name;
typedef String<32> Depot_rom_server;
typedef String<100> Launcher_name;
private:
Allocator &_alloc;
Reconstructible<Buffered_xml> _start_xml; /* from config */
Constructible<Buffered_xml> _pkg_xml { }; /* from blueprint */
Reconstructible<Buffered_xml> _start_xml; /* from config */
Constructible<Buffered_xml> _launcher_xml { };
Constructible<Buffered_xml> _pkg_xml { }; /* from blueprint */
/*
* State of the condition check for generating the start node of
@ -55,11 +57,34 @@ class Depot_deploy::Child : public List_model<Child>::Element
Name const _name;
bool _defined_by_launcher() const
{
/*
* If the <start> node lacks a 'pkg' attribute, we expect the
* policy to be defined by a launcher XML snippet.
*/
return _start_xml.constructed() && !_start_xml->xml().has_attribute("pkg");
}
Archive::Path _config_pkg_path() const
{
if (_defined_by_launcher() && _launcher_xml.constructed())
return _launcher_xml->xml().attribute_value("pkg", Archive::Path());
return _start_xml->xml().attribute_value("pkg", Archive::Path());
}
Launcher_name _launcher_name() const
{
if (!_defined_by_launcher())
return Launcher_name();
if (_start_xml->xml().has_attribute("launcher"))
return _start_xml->xml().attribute_value("launcher", Launcher_name());
return _start_xml->xml().attribute_value("name", Launcher_name());
}
/*
* The pkg-archive path of the current blueprint query, which may
* deviate from pkg path given in the config, once the config is
@ -67,8 +92,12 @@ class Depot_deploy::Child : public List_model<Child>::Element
*/
Archive::Path _blueprint_pkg_path = _config_pkg_path();
Ram_quota _ram_quota { 0 };
Cap_quota _cap_quota { 0 };
/*
* Quota definitions obtained from the blueprint
*/
Number_of_bytes _pkg_ram_quota { 0 };
unsigned long _pkg_cap_quota { 0 };
Binary_name _binary_name { };
Config_name _config_name { };
@ -131,20 +160,21 @@ class Depot_deploy::Child : public List_model<Child>::Element
if (!start_node_changed)
return;
Archive::Path const pkg =
start_node.attribute_value("pkg", Archive::Path());
/* invalidate blueprint if 'pkg' attribute of start node changed */
if (pkg != _config_pkg_path())
_pkg_xml.destruct();
_blueprint_pkg_path = pkg;
Archive::Path const old_pkg_path = _config_pkg_path();
/* import new start node */
_start_xml.construct(_alloc, start_node);
/* reset error state, attempt to obtain the blueprint again */
_pkg_incomplete = false;
Archive::Path const new_pkg_path = _config_pkg_path();
/* invalidate blueprint if 'pkg' path changed */
if (old_pkg_path != new_pkg_path) {
_blueprint_pkg_path = new_pkg_path;
_pkg_xml.destruct();
/* reset error state, attempt to obtain the blueprint again */
_pkg_incomplete = false;
}
}
void apply_blueprint(Xml_node pkg)
@ -157,11 +187,8 @@ class Depot_deploy::Child : public List_model<Child>::Element
Xml_node const runtime = pkg.sub_node("runtime");
Number_of_bytes const ram { runtime.attribute_value("ram", Number_of_bytes()) };
_ram_quota = Ram_quota { _start_xml->xml().attribute_value("ram", ram) };
unsigned long const caps = runtime.attribute_value("caps", 0UL);
_cap_quota = Cap_quota { _start_xml->xml().attribute_value("caps", caps) };
_pkg_ram_quota = runtime.attribute_value("ram", Number_of_bytes());
_pkg_cap_quota = runtime.attribute_value("caps", 0UL);
_binary_name = runtime.attribute_value("binary", Binary_name());
_config_name = runtime.attribute_value("config", Config_name());
@ -170,22 +197,57 @@ class Depot_deploy::Child : public List_model<Child>::Element
_pkg_xml.construct(_alloc, pkg);
}
template <typename COND_FN>
void apply_condition(COND_FN const &fn)
void apply_launcher(Launcher_name const &name, Xml_node launcher)
{
/* don't check the condition twice */
if (_condition == SATISFIED)
if (!_defined_by_launcher())
return;
if (_launcher_name() != name)
return;
if (_launcher_xml.constructed()) {
bool const launcher_changed =
(launcher.size() != _launcher_xml->xml().size()) ||
(strcmp(launcher.addr(), _launcher_xml->xml().addr(),
launcher.size()) != 0);
if (!launcher_changed)
return;
}
_launcher_xml.construct(_alloc, launcher);
_blueprint_pkg_path = _config_pkg_path();
}
/*
* \return true if condition changed
*/
template <typename COND_FN>
bool apply_condition(COND_FN const &fn)
{
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()) ? SATISFIED : UNSATISFIED;
_condition = fn(_start_xml->xml(), launcher_xml)
? SATISFIED : UNSATISFIED;
return _condition != orig_condition;
}
template <typename FN>
void apply_if_unsatisfied(FN const &fn) const
{
Xml_node launcher_xml = _launcher_xml.constructed()
? _launcher_xml->xml()
: Xml_node("<empty/>");
if (_condition == UNSATISFIED && _start_xml.constructed())
fn(_start_xml->xml());
fn(_start_xml->xml(), launcher_xml);
}
void mark_as_incomplete(Xml_node missing)
@ -219,6 +281,9 @@ class Depot_deploy::Child : public List_model<Child>::Element
if (_configured() || _pkg_incomplete)
return;
if (_defined_by_launcher() && !_launcher_xml.constructed())
return;
xml.node("blueprint", [&] () {
xml.attribute("pkg", _blueprint_pkg_path); });
}
@ -264,6 +329,9 @@ void Depot_deploy::Child::gen_start_node(Xml_generator &xml, Xml_node common,
if (!_configured() || _condition == UNSATISFIED)
return;
if (_defined_by_launcher() && !_launcher_xml.constructed())
return;
if (!_pkg_xml->xml().has_sub_node("runtime")) {
warning("blueprint for '", _name, "' lacks runtime information");
return;
@ -272,7 +340,13 @@ void Depot_deploy::Child::gen_start_node(Xml_generator &xml, Xml_node common,
xml.node("start", [&] () {
xml.attribute("name", _name);
xml.attribute("caps", _cap_quota.value);
unsigned long caps = _pkg_cap_quota;
if (_defined_by_launcher())
caps = _launcher_xml->xml().attribute_value("caps", caps);
caps = _start_xml->xml().attribute_value("caps", caps);
xml.attribute("caps", caps);
typedef String<64> Version;
Version const version = _start_xml->xml().attribute_value("version", Version());
@ -281,22 +355,32 @@ void Depot_deploy::Child::gen_start_node(Xml_generator &xml, Xml_node common,
xml.node("binary", [&] () { xml.attribute("name", _binary_name); });
Number_of_bytes ram = _pkg_ram_quota;
if (_defined_by_launcher())
ram = _launcher_xml->xml().attribute_value("ram", ram);
ram = _start_xml->xml().attribute_value("ram", ram);
xml.node("resource", [&] () {
xml.attribute("name", "RAM");
xml.attribute("quantum", String<32>(Number_of_bytes(_ram_quota.value)));
xml.attribute("quantum", String<32>(ram));
});
Xml_node const runtime = _pkg_xml->xml().sub_node("runtime");
/*
* Insert inline '<config>' node if provided by the start node or the
* Insert inline '<config>' node if provided by the start node,
* the launcher definition (if a launcher is user), or the
* blueprint. The former is preferred over the latter.
*/
if (_start_xml->xml().has_sub_node("config")) {
_gen_copy_of_sub_node(xml, _start_xml->xml(), "config");
} else {
if (runtime.has_sub_node("config"))
_gen_copy_of_sub_node(xml, runtime, "config");
if (_defined_by_launcher() && _launcher_xml->xml().has_sub_node("config")) {
_gen_copy_of_sub_node(xml, _launcher_xml->xml(), "config");
} else {
if (runtime.has_sub_node("config"))
_gen_copy_of_sub_node(xml, runtime, "config");
}
}
/*
@ -344,6 +428,14 @@ void Depot_deploy::Child::_gen_routes(Xml_generator &xml, Xml_node common,
xml.append(route.content_base(), route.content_size());
}
/*
* Add routes given in the launcher definition.
*/
if (_launcher_xml.constructed() && _launcher_xml->xml().has_sub_node("route")) {
Xml_node const route = _launcher_xml->xml().sub_node("route");
xml.append(route.content_base(), route.content_size());
}
/**
* Return name of depot-ROM server used for obtaining the 'path'
*

View File

@ -67,6 +67,12 @@ class Depot_deploy::Children
_children.update_from_xml(_model_update_policy, config);
}
void apply_launcher(Child::Launcher_name const &name, Xml_node launcher)
{
_children.for_each([&] (Child &child) {
child.apply_launcher(name, launcher); });
}
void apply_blueprint(Xml_node blueprint)
{
blueprint.for_each_sub_node("pkg", [&] (Xml_node pkg) {
@ -78,11 +84,16 @@ class Depot_deploy::Children
child.mark_as_incomplete(missing); }); });
}
/*
* \return true if the condition of any child changed
*/
template <typename COND_FN>
void apply_condition(COND_FN const &fn)
bool apply_condition(COND_FN const &fn)
{
bool any_condition_changed = false;
_children.for_each([&] (Child &child) {
child.apply_condition(fn); });
any_condition_changed |= child.apply_condition(fn); });
return any_condition_changed;
}
/**

View File

@ -17,33 +17,30 @@
bool Sculpt::Deploy::update_child_conditions()
{
/* track whether any condition changed for the better */
bool result = false;
/* return true if any condition changed */
return _children.apply_condition([&] (Xml_node start, Xml_node launcher) {
_children.apply_condition([&] (Xml_node start) {
/* the child cannot be started as long as any dependency is missing */
/* the child cannot run as long as any dependency is missing */
bool condition = true;
_for_each_missing_server(start, [&] (Start_name const &) {
condition = false; });
_for_each_missing_server(launcher, [&] (Start_name const &) {
condition = false; });
result |= condition;
return condition;
});
return result;
}
void Sculpt::Deploy::_gen_missing_dependencies(Xml_generator &xml,
void Sculpt::Deploy::_gen_missing_dependencies(Xml_generator &xml, Start_name const &name,
Xml_node start, int &count) const
{
Start_name const child = start.attribute_value("name", Start_name());
_for_each_missing_server(start, [&] (Start_name const &server) {
gen_named_node(xml, "hbox", String<20>(count++), [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(child, " requires ", server));
xml.attribute("text", String<64>(name, " requires ", server));
xml.attribute("font", "annotation/regular");
});
});
@ -55,7 +52,7 @@ void Sculpt::Deploy::_gen_missing_dependencies(Xml_generator &xml,
void Sculpt::Deploy::gen_child_diagnostics(Xml_generator &xml) const
{
bool all_children_ok = true;
_children.for_each_unsatisfied_child([&] (Xml_node) {
_children.for_each_unsatisfied_child([&] (Xml_node, Xml_node) {
all_children_ok = false; });
if (all_children_ok)
@ -70,8 +67,13 @@ void Sculpt::Deploy::gen_child_diagnostics(Xml_generator &xml) const
xml.node("float", [&] () {
xml.node("vbox", [&] () {
_children.for_each_unsatisfied_child([&] (Xml_node start) {
_gen_missing_dependencies(xml, start, count); }); }); });
_children.for_each_unsatisfied_child([&] (Xml_node start, Xml_node launcher) {
Start_name const name = start.attribute_value("name", Start_name());
_gen_missing_dependencies(xml, name, start, count);
_gen_missing_dependencies(xml, name, launcher, count);
});
});
});
});
});
}
@ -90,6 +92,31 @@ void Sculpt::Deploy::handle_deploy()
catch (...) {
error("spurious exception during deploy update (apply_config)"); }
/*
* Apply launchers
*/
Xml_node const launcher_listing = _launcher_listing_rom.xml();
launcher_listing.for_each_sub_node("dir", [&] (Xml_node dir) {
typedef String<20> Path;
Path const path = dir.attribute_value("path", Path());
if (path != "/launcher")
return;
dir.for_each_sub_node("file", [&] (Xml_node file) {
if (file.attribute_value("xml", false) == false)
return;
typedef Depot_deploy::Child::Launcher_name Name;
Name const name = file.attribute_value("name", Name());
file.for_each_sub_node("launcher", [&] (Xml_node launcher) {
_children.apply_launcher(name, launcher); });
});
});
/* update query for blueprints of all unconfigured start nodes */
if (_arch.valid()) {
_depot_query_reporter.generate([&] (Xml_generator &xml) {

View File

@ -54,6 +54,8 @@ struct Sculpt::Deploy
Attached_rom_dataspace _manual_deploy_rom { _env, "config -> deploy" };
Attached_rom_dataspace _launcher_listing_rom { _env, "report -> /runtime/launcher_query/listing" };
Attached_rom_dataspace _blueprint_rom { _env, "report -> runtime/depot_query/blueprint" };
Expanding_reporter _depot_query_reporter { _env, "query", "depot_query"};
@ -81,6 +83,7 @@ struct Sculpt::Deploy
void _handle_manual_deploy()
{
_manual_deploy_rom.update();
_launcher_listing_rom.update();
_query_version.value++;
handle_deploy();
}
@ -125,7 +128,7 @@ struct Sculpt::Deploy
*/
bool update_child_conditions();
void _gen_missing_dependencies(Xml_generator &, Xml_node, int &) const;
void _gen_missing_dependencies(Xml_generator &, Start_name const &, Xml_node, int &) const;
void gen_child_diagnostics(Xml_generator &xml) const;
@ -134,6 +137,9 @@ struct Sculpt::Deploy
Signal_handler<Deploy> _manual_deploy_handler {
_env.ep(), *this, &Deploy::_handle_manual_deploy };
Signal_handler<Deploy> _launcher_listing_handler {
_env.ep(), *this, &Deploy::_handle_manual_deploy };
Signal_handler<Deploy> _blueprint_handler {
_env.ep(), *this, &Deploy::_handle_blueprint };
@ -160,6 +166,7 @@ struct Sculpt::Deploy
_runtime_config_generator(runtime_config_generator)
{
_manual_deploy_rom.sigh(_manual_deploy_handler);
_launcher_listing_rom.sigh(_launcher_listing_handler);
_blueprint_rom.sigh(_blueprint_handler);
}
};

View File

@ -22,11 +22,11 @@
#include <children.h>
/* local includes */
#include <model/runtime_state.h>
#include <model/child_exit_state.h>
#include <view/download_status.h>
#include <gui.h>
#include <nitpicker.h>
#include <runtime.h>
#include <keyboard_focus.h>
#include <network.h>
#include <storage.h>
@ -38,7 +38,6 @@ namespace Sculpt { struct Main; }
struct Sculpt::Main : Input_event_handler,
Dialog::Generator,
Runtime_config_generator,
Runtime_info,
Storage::Target_user
{
Env &_env;
@ -155,7 +154,7 @@ struct Sculpt::Main : Input_event_handler,
}
Network _network { _env, _heap, *this, *this, *this, _pci_info };
Network _network { _env, _heap, *this, *this, _runtime_state, _pci_info };
/************
@ -175,7 +174,7 @@ struct Sculpt::Main : Input_event_handler,
&& _network.ready()
&& _deploy.update_needed(); };
Deploy _deploy { _env, _heap, *this, *this, *this };
Deploy _deploy { _env, _heap, _runtime_state, *this, *this };
@ -242,19 +241,9 @@ struct Sculpt::Main : Input_event_handler,
});
}
Attached_rom_dataspace _runtime_state { _env, "report -> runtime/state" };
Attached_rom_dataspace _runtime_state_rom { _env, "report -> runtime/state" };
/**
* Runtime_info interface
*/
bool present_in_runtime(Start_name const &name) const override
{
bool present = false;
_runtime_state.xml().for_each_sub_node("child", [&] (Xml_node child) {
if (child.attribute_value("name", Start_name()) == name)
present = true; });
return present;
}
Runtime_state _runtime_state { _heap };
Managed_config<Main> _runtime_config {
_env, "config", "runtime", *this, &Main::_handle_runtime };
@ -372,7 +361,7 @@ struct Sculpt::Main : Input_event_handler,
Main(Env &env) : _env(env)
{
_runtime_state.sigh(_runtime_state_handler);
_runtime_state_rom.sigh(_runtime_state_handler);
_nitpicker_displays.sigh(_nitpicker_displays_handler);
/*
@ -631,9 +620,11 @@ void Sculpt::Main::_handle_update_state()
void Sculpt::Main::_handle_runtime_state()
{
_runtime_state.update();
_runtime_state_rom.update();
Xml_node state = _runtime_state.xml();
Xml_node state = _runtime_state_rom.xml();
_runtime_state.update_from_state_report(state);
bool reconfigure_runtime = false;
@ -861,8 +852,12 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
xml.node("start", [&] () {
gen_update_start_content(xml); });
if (_storage._sculpt_partition.valid() && !_prepare_in_progress())
if (_storage._sculpt_partition.valid() && !_prepare_in_progress()) {
xml.node("start", [&] () {
gen_launcher_query_start_content(xml); });
_deploy.gen_runtime_start_nodes(xml);
}
}

View File

@ -0,0 +1,87 @@
/*
* \brief State of the components hosted in the runtime subsystem
* \author Norman Feske
* \date 2018-08-22
*/
/*
* 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 _MODEL__RUNTIME_STATE_H_
#define _MODEL__RUNTIME_STATE_H_
/* Genode includes */
#include <util/xml_node.h>
#include <util/list_model.h>
/* local includes */
#include <types.h>
#include <runtime.h>
namespace Sculpt { class Runtime_state; }
class Sculpt::Runtime_state : public Runtime_info
{
private:
Allocator &_alloc;
struct Child : List_model<Child>::Element
{
Start_name const name;
Child(Start_name const &name) : name(name) { }
};
List_model<Child> _children { };
struct Update_policy : List_model<Child>::Update_policy
{
Allocator &_alloc;
Update_policy(Allocator &alloc) : _alloc(alloc) { }
void destroy_element(Child &elem) { destroy(_alloc, &elem); }
Child &create_element(Xml_node node)
{
return *new (_alloc)
Child(node.attribute_value("name", Start_name()));
}
void update_element(Child &, Xml_node) { }
static bool element_matches_xml_node(Child const &elem, Xml_node node)
{
return node.attribute_value("name", Start_name()) == elem.name;
}
};
public:
Runtime_state(Allocator &alloc) : _alloc(alloc) { }
void update_from_state_report(Xml_node state)
{
Update_policy policy(_alloc);
_children.update_from_xml(policy, state);
}
/**
* Runtime_info interface
*/
bool present_in_runtime(Start_name const &name) const override
{
bool result = false;
_children.for_each([&] (Child const &child) {
if (!result && child.name == name)
result = true; });
return result;
}
};
#endif /* _MODEL__RUNTIME_STATE_H_ */

View File

@ -16,6 +16,7 @@
#include <runtime/chroot.cc>
#include <runtime/depot_query.cc>
#include <runtime/launcher_query.cc>
#include <runtime/e2fs.cc>
#include <runtime/file_browser.cc>
#include <runtime/file_system.cc>

View File

@ -39,6 +39,7 @@ namespace Sculpt {
Path const &, Writeable);
void gen_depot_query_start_content(Xml_generator &);
void gen_launcher_query_start_content(Xml_generator &);
struct File_browser_version { unsigned value; };
void gen_file_browser(Xml_generator &, Storage_devices const &,

View File

@ -0,0 +1,48 @@
/*
* \brief XML configuration for the fs-query tool for obtaining the launchers
* \author Norman Feske
* \date 2018-08-21
*/
/*
* 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.
*/
#include <runtime.h>
void Sculpt::gen_launcher_query_start_content(Xml_generator &xml)
{
gen_common_start_content(xml, "launcher_query",
Cap_quota{200}, Ram_quota{2*1024*1024});
gen_named_node(xml, "binary", "fs_query");
xml.node("config", [&] () {
xml.attribute("query", "rom");
xml.node("vfs", [&] () {
xml.node("fs", [&] () {}); });
xml.node("query", [&] () {
xml.attribute("path", "/launcher");
xml.attribute("content", "yes");
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "fs_query");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Report::Session> (xml);
gen_service_node<::File_system::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", "config"); }); });
});
}