diff --git a/repos/ealanos/include/ealanos/laucher/client.h b/repos/ealanos/include/ealanos/laucher/client.h new file mode 100644 index 0000000000..a3f3ad2819 --- /dev/null +++ b/repos/ealanos/include/ealanos/laucher/client.h @@ -0,0 +1,21 @@ +#ifndef __EALANOS__INCLUDE__LAUNCHER__CLIENT_H_ +#define __EALANOS__INCLUDE__LAUNCHER__CLIENT_H_ + +#include +#include + +namespace Ealan { + struct Launcher_client; + using Launcher_capability = Genode::Capability; +} + +struct Ealan::Launcher_client : Genode::Rpc_client +{ + explicit Launcher_client(Launcher_capability session) : Rpc_client(session) {} + + void launch(Genode::String<640> start_node) override { + call(start_node); + } +}; + +#endif // __EALANOS__INCLUDE__LAUNCHER__CLIENT_H_ \ No newline at end of file diff --git a/repos/ealanos/include/ealanos/laucher/component.h b/repos/ealanos/include/ealanos/laucher/component.h new file mode 100644 index 0000000000..68e9519fde --- /dev/null +++ b/repos/ealanos/include/ealanos/laucher/component.h @@ -0,0 +1,37 @@ +#ifndef __EALANOS__INCLUDE__LAUNCHER__COMPONENT_H_ +#define __EALANOS__INCLUDE__LAUNCHER__COMPONENT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace Ealan { + class Launcher_session_component; + class Launcher_root; + class Hoitaja; +} + +class Ealan::Launcher_session_component : public Genode::Session_object +{ + private: + Genode::Entrypoint &_ep; + Ealan::Hoitaja &_hoitaja; + + public: + template + Launcher_session_component(Hoitaja &hoitaja, Genode::Entrypoint &ep, Genode::Session::Resources const &res, ARGS &&...args) + : Session_object(ep, res, args...), _ep(ep), _hoitaja(hoitaja) { Genode::log("Creating new launcher session"); } + + void launch(Genode::String<640> start_node) override; +}; + +#endif // __EALANOS__INCLUDE__LAUNCHER__COMPONENT_H_ \ No newline at end of file diff --git a/repos/ealanos/include/ealanos/laucher/connection.h b/repos/ealanos/include/ealanos/laucher/connection.h new file mode 100644 index 0000000000..622836f577 --- /dev/null +++ b/repos/ealanos/include/ealanos/laucher/connection.h @@ -0,0 +1,25 @@ +#ifndef __EALANOS__INCLUDE__LAUNCHER__CONNECTION_H_ +#define __EALANOS__INCLUDE__LAUNCHER__CONNECTION_H_ + +#include +#include +#include + + +#include + +namespace Ealan { + struct Launcher_connection; +} + +struct Ealan::Launcher_connection : Genode::Connection, Launcher_client +{ + Launcher_connection(Genode::Env &env, Genode::Affinity &affinity, Label const &label = Label()) + : Connection(env, label, Genode::Ram_quota { RAM_QUOTA }, affinity, Args("")), Launcher_client(cap()) {} + + void launch(Genode::String<640> start_node) override + { + Launcher_client::launch(start_node); + } +}; +#endif // __EALANOS__INCLUDE__LAUNCHER__CONNECTION_H_ \ No newline at end of file diff --git a/repos/ealanos/include/ealanos/laucher/session.h b/repos/ealanos/include/ealanos/laucher/session.h new file mode 100644 index 0000000000..830f30b8a2 --- /dev/null +++ b/repos/ealanos/include/ealanos/laucher/session.h @@ -0,0 +1,28 @@ +#ifndef __EALANOS__INCLUDE__LAUNCHER__SESSION_H_ +#define __EALANOS__INCLUDE__LAUNCHER__SESSION_H_ + +#include +#include +#include + +namespace Ealan { + struct Launcher_session; +} + +struct Ealan::Launcher_session : Genode::Session +{ + static const char *service_name() { return "Launcher"; } + + enum + { + CAP_QUOTA = 1, + RAM_QUOTA = 1024 + }; + + virtual void launch(Genode::String<640> start_node) = 0; + + GENODE_RPC(Rpc_launch, void, launch, Genode::String<640>); + GENODE_RPC_INTERFACE(Rpc_launch); +}; + +#endif // __EALANOS__INCLUDE__LAUNCHER__SESSION_H_ \ No newline at end of file diff --git a/repos/ealanos/include/sandbox/sandbox.h b/repos/ealanos/include/sandbox/sandbox.h index 1502d5b1ce..622e39f1b8 100644 --- a/repos/ealanos/include/sandbox/sandbox.h +++ b/repos/ealanos/include/sandbox/sandbox.h @@ -26,6 +26,8 @@ namespace Sandbox { class Child; } +namespace Ealan { class Hoitaja; } + class Genode::Sandbox : Noncopyable { public: @@ -81,6 +83,7 @@ class Genode::Sandbox : Noncopyable private: friend class Local_service_base; + friend class Ealan::Hoitaja; Heap _heap; @@ -112,7 +115,7 @@ class Genode::Sandbox : Noncopyable */ void generate_state_report(Xml_generator &) const; - void update(::Sandbox::Child &child); + Xml_node* update(::Sandbox::Child &child, Xml_node *config); }; class Genode::Sandbox::Local_service_base : public Service diff --git a/repos/ealanos/run/launcher_test.run b/repos/ealanos/run/launcher_test.run new file mode 100644 index 0000000000..6d0a099d8e --- /dev/null +++ b/repos/ealanos/run/launcher_test.run @@ -0,0 +1,79 @@ +set build_components { + core init hoitaja timer lib/ld lib/libm lib/libc lib/stdcxx lib/vfs app/launcher_test app/allocating_cell +} + +build $build_components +create_boot_directory + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2022-07-20 14:30 + + + + + + + + + + + +} + +build_boot_image [build_artifacts] + +append qemu_args " -nographic " + +set succeeded 0 +set failed 0 + +for {set i 0} { $i < 3000 } { incr i } { + if { ! [catch {run_genode_until ".*Changing cell .* affinity to .*0,0,32.*" 120} result ] } { + incr succeeded + puts "\n $succeeded of 3000 succeeded" + kill_spawned $qemu_spawn_id + } else { + incr failed + kill_spawned $qemu_spawn_id + } +} + +puts "\n $succeeded of $i succeeded. $failed of $i failed." \ No newline at end of file diff --git a/repos/ealanos/src/app/launcher_test/launcher.cc b/repos/ealanos/src/app/launcher_test/launcher.cc new file mode 100644 index 0000000000..701f345046 --- /dev/null +++ b/repos/ealanos/src/app/launcher_test/launcher.cc @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +#include + + +#define Cell(name) static const char *name = \ + "\n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " 2022-07-20 14:30\n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + "\n"; + +Cell(allocator1); +Cell(allocator2); +Cell(allocator3); +Cell(allocator4); +Cell(allocator5); +Cell(allocator6); +Cell(allocator7); +Cell(allocator8); + +static const char *cells[8] = {allocator1, allocator2, allocator3, allocator4, allocator5, allocator6, allocator7, allocator8}; + +void Libc::Component::construct(Libc::Env &env) +{ + Genode::Thread *myself = Genode::Thread::myself(); + Genode::Affinity::Location loc = myself->affinity(); + Genode::Affinity affinity(env.cpu().affinity_space(), loc); + + Timer::Connection _timer{env}; + + Libc::with_libc([&]() + { + Ealan::Launcher_connection _launcher{env, affinity}; + for (int i = 0; i < 8; i++) { + + bool repeat = false; + do + { + try { + Genode::Xml_node xml(cells[i]); + _launcher.launch(xml); + } catch (Genode::Xml_attribute::Invalid_syntax) { + Genode::error("Invalid XML start node"); + } catch (Genode::Ipc_error) { + repeat = true; + } + } while (repeat); + //_timer.msleep(1000); + } + Genode::log("Launched dummy"); }); + while(true) + ; +} \ No newline at end of file diff --git a/repos/ealanos/src/app/launcher_test/target.mk b/repos/ealanos/src/app/launcher_test/target.mk new file mode 100644 index 0000000000..2f276e6755 --- /dev/null +++ b/repos/ealanos/src/app/launcher_test/target.mk @@ -0,0 +1,7 @@ +SRC_CC += launcher +TARGET = launcher + +INC_DIR += $(call select_from_repositories,src/lib/libc)/spec/x86_64 +INC_DIR += $(call select_from_repositories,src/lib/libc) + +LIBS = base libc stdcxx diff --git a/repos/ealanos/src/hoitaja/main.cc b/repos/ealanos/src/hoitaja/main.cc index 03d6045a9c..231426cb1c 100644 --- a/repos/ealanos/src/hoitaja/main.cc +++ b/repos/ealanos/src/hoitaja/main.cc @@ -19,110 +19,193 @@ #include #include #include -namespace Init { + +#include +namespace Ealan { using namespace Genode; - struct Main; + struct Hoitaja; } -struct Init::Main : Genode::Sandbox::State_handler +class Ealan::Hoitaja : Genode::Sandbox::State_handler, Genode::Sandbox::Local_service_base::Wakeup { - Env &_env; + private: + Env &_env; - Genode::Sandbox _sandbox { _env, *this }; + Genode::Sandbox _sandbox { _env, *this }; - Attached_rom_dataspace _config { _env, "config" }; + Attached_rom_dataspace _config { _env, "config" }; - void _handle_resource_avail() { } + Genode::Xml_node *_habitat_config{nullptr}; - Signal_handler
_resource_avail_handler { - _env.ep(), *this, &Main::_handle_resource_avail }; + char *_config_dataspace{nullptr}; - Constructible _reporter { }; + void _handle_resource_avail() { } - size_t _report_buffer_size = 0; + Signal_handler _resource_avail_handler { + _env.ep(), *this, &Hoitaja::_handle_resource_avail }; - void _handle_config() - { - _config.update(); + Constructible _reporter { }; - Xml_node const config = _config.xml(); + Genode::Rpc_entrypoint _ep{&_env.pd(), 4096, "launcher_ep", Genode::Affinity::Location(0, 0, 1, 1)}; - bool reporter_enabled = false; - config.with_optional_sub_node("report", [&] (Xml_node report) { + Genode::Entrypoint _launcher_ep{_env, 4*4096, "launcher", Genode::Affinity::Location()}; - reporter_enabled = true; + Genode::Sliced_heap _md_alloc{_env.ram(), _env.rm()}; - /* (re-)construct reporter whenever the buffer size is changed */ - Number_of_bytes const buffer_size = - report.attribute_value("buffer", Number_of_bytes(4096)); + Genode::Heap _heap{_env.ram(), _env.rm()}; - if (buffer_size != _report_buffer_size || !_reporter.constructed()) { - _report_buffer_size = buffer_size; - _reporter.construct(_env, "state", "state", _report_buffer_size); + using Launcher_service = Genode::Sandbox::Local_service; + Launcher_service _launcher_service{_sandbox, *this}; + + size_t _report_buffer_size = 0; + + void _handle_config() + { + _config.update(); + + if (_habitat_config) { + delete _habitat_config; + delete _config_dataspace; } - }); - if (_reporter.constructed()) - _reporter->enabled(reporter_enabled); + _config_dataspace = static_cast(_heap.alloc(_config.size()*32)); + Genode::memcpy(_config_dataspace, _config.local_addr(), _config.size()); + _habitat_config = new (_sandbox._heap) Genode::Xml_node(_config_dataspace); - _sandbox.apply_config(config); - } + Xml_node const config = *_habitat_config; - Signal_handler
_config_handler { - _env.ep(), *this, &Main::_handle_config }; + bool reporter_enabled = false; + config.with_optional_sub_node("report", [&] (Xml_node report) { - /** - * Sandbox::State_handler interface - */ - void handle_sandbox_state() override - { - try { - Reporter::Xml_generator xml(*_reporter, [&] () { - _sandbox.generate_state_report(xml); }); + reporter_enabled = true; + + /* (re-)construct reporter whenever the buffer size is changed */ + Number_of_bytes const buffer_size = + report.attribute_value("buffer", Number_of_bytes(4096)); + + if (buffer_size != _report_buffer_size || !_reporter.constructed()) { + _report_buffer_size = buffer_size; + _reporter.construct(_env, "state", "state", _report_buffer_size); + } + }); + + if (_reporter.constructed()) + _reporter->enabled(reporter_enabled); + + _sandbox.apply_config(config); } - catch (Xml_generator::Buffer_exceeded) { - error("state report exceeds maximum size"); + Signal_handler _config_handler { + _env.ep(), *this, &Hoitaja::_handle_config }; - /* try to reflect the error condition as state report */ - try { + Hoitaja(const Hoitaja &); + + Hoitaja &operator=(const Hoitaja &); + + public: + + /** + * Sandbox::State_handler interface + */ + void handle_sandbox_state() override + { + Genode::log("Sandbox state changed"); + try + { Reporter::Xml_generator xml(*_reporter, [&] () { - xml.attribute("error", "report buffer exceeded"); }); + _sandbox.generate_state_report(xml); }); + } + catch (Xml_generator::Buffer_exceeded) { + + error("state report exceeds maximum size"); + + /* try to reflect the error condition as state report */ + try { + Reporter::Xml_generator xml(*_reporter, [&] () { + xml.attribute("error", "report buffer exceeded"); }); + } + catch (...) { } } - catch (...) { } } - } - void handle_child_state(::Sandbox::Child &child) override { - try { - Genode::log("Updating sandbox state"); - _sandbox.update(child); - } catch (Genode::Quota_guard::Limit_exceeded) { - Genode::log("Caps exceeded while handling child state"); - _env.parent().exit(1); + void handle_child_state(::Sandbox::Child &child) override { + bool repeat = false; + do + { + try { + Genode::log("Updating state of child ", child.name()); + _habitat_config = _sandbox.update(child, _habitat_config); + Genode::log("Updated config length:", _habitat_config->content_size()); + } + catch (Genode::Quota_guard::Limit_exceeded) + { + Genode::log("Caps exceeded while handling child state"); + _env.parent().exit(1); + } + catch (Genode::Ipc_error) + { + Genode::error("Failed to update child state for <", child.name(), ">"); + repeat = true; + } + } while (repeat); } - } - Main(Env &env) : _env(env) - { - _config.sigh(_config_handler); + void wakeup_local_service() override { + _launcher_service.for_each_requested_session([&](Launcher_service::Request &req) + { req.deliver_session(*new (_md_alloc) Ealan::Launcher_session_component(*this, _env.ep() , req.resources, "", req.diag)); }); + } - Genode::log("Hoitaja starting ..."); + void add_cell_from_xml(const char *start_node){ + char *dest = nullptr; - /* prevent init to block for resource upgrades (never satisfied by core) */ - _env.parent().resource_avail_sigh(_resource_avail_handler); + _habitat_config->with_raw_content([&](char const *content, Genode::size_t) + { dest = const_cast(content); }); + dest += _habitat_config->content_size(); - Tukija::Tip const *tip = Tukija::Tip::tip(); - Genode::log("Found topology model of size ", tip->length, " at ", static_cast(tip)); + Genode::memcpy(dest, start_node, Genode::strlen(start_node)); + dest += Genode::strlen(start_node); + Genode::memcpy(dest, "", sizeof("")); - _handle_config(); - } + _sandbox._heap.free(_habitat_config, sizeof(Xml_node)); + + _habitat_config = new (_sandbox._heap) Xml_node(_config_dataspace); + + bool repeat = false; + do { + try { + _sandbox.apply_config(*_habitat_config); + } catch (Genode::Ipc_error) { + Genode::error("IPC error while creating cell. Retrying."); + repeat = true; + } + } while (repeat); + } + + Hoitaja(Env &env) : _env(env) + { + _config.sigh(_config_handler); + + Genode::log("Hoitaja starting ..."); + + /* prevent init to block for resource upgrades (never satisfied by core) */ + _env.parent().resource_avail_sigh(_resource_avail_handler); + + Tukija::Tip const *tip = Tukija::Tip::tip(); + + Genode::log("Found topology model of size ", tip->length, " at ", static_cast(tip)); + + _handle_config(); + } }; +void Ealan::Launcher_session_component::launch(Genode::String<640> start_node) +{ + _hoitaja.add_cell_from_xml(start_node.string()); +} -void Component::construct(Genode::Env &env) { static Init::Main main(env); } +void Component::construct(Genode::Env &env) { static Ealan::Hoitaja main(env); } diff --git a/repos/ealanos/src/lib/sandbox/child.cc b/repos/ealanos/src/lib/sandbox/child.cc index 9de8c8f83f..de5dc8bf73 100644 --- a/repos/ealanos/src/lib/sandbox/child.cc +++ b/repos/ealanos/src/lib/sandbox/child.cc @@ -779,7 +779,7 @@ Sandbox::Child::Child(Env &env, _local_services(local_services), _session_requester(_env.ep().rpc_ep(), _env.ram(), _env.rm()), _habitat(habitat){ - log("Creating new cell <", _unique_name, ">"); + //log("Creating new cell <", _unique_name, ">"); if (_verbose.enabled()) { log("child \"", _unique_name, "\""); log(" RAM quota: ", _resources.effective_ram_quota()); diff --git a/repos/ealanos/src/lib/sandbox/child.h b/repos/ealanos/src/lib/sandbox/child.h index 70084ed7dd..fa2ee2e6c3 100644 --- a/repos/ealanos/src/lib/sandbox/child.h +++ b/repos/ealanos/src/lib/sandbox/child.h @@ -739,12 +739,12 @@ class Sandbox::Child : Child_policy, Routed_service::Wakeup struct Resources &resources() { return _resources; } void update(Genode::Affinity affinity) { - Genode::log("Updating affinity to ", affinity.location(), " in space ", affinity.space()); + //Genode::log("Updating affinity to ", affinity.location(), " in space ", affinity.space()); _resources.affinity = affinity; //Genode::log("Moving CPU session ", _env.cpu_session_cap()); if (_child.active()) { Ealan::Cell_client cell(_cell_cap); - Genode::log("Updating cell ", _cell_cap); + //Genode::log("Updating cell ", _cell_cap); cell.update(affinity); } } diff --git a/repos/ealanos/src/lib/sandbox/library.cc b/repos/ealanos/src/lib/sandbox/library.cc index f71a641de9..e84b75a735 100644 --- a/repos/ealanos/src/lib/sandbox/library.cc +++ b/repos/ealanos/src/lib/sandbox/library.cc @@ -257,6 +257,7 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, */ Parent_service &create_parent_service(Service::Name const &name) override { + Genode::log("Creating parent service ", name); return *new (_heap) Parent_service(_parent_services, _env, name); } @@ -309,13 +310,56 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer, void maintain_cells(); - void update(Child &child) { + Genode::Xml_node* update(Child &child, Genode::Xml_node *config) { if (child.exited()) { _children.remove(&child); _core_allocator->free_cores_from_cell(child); - Genode::log("Starting new maintenance cycle"); + /* Remove child from config */ + try { + /* Find XML node for the child */ + Xml_node node = config->sub_node("start"); + while (node.attribute_value("name", Genode::Child_policy::Name()) != child.name()) + { + node = node.next("start"); + } + + /* Get pointer to start of node in its parent's buffer and its length */ + char *node_ptr = nullptr; + Genode::size_t len = 0; + node.with_raw_node([&](char const *ptr, Genode::size_t size) + { node_ptr = const_cast(ptr); len = size; }); + char *node_end = node_ptr + len; + + /* Determine start and end address of config's buffer */ + Genode::size_t config_len = config->size(); + char *config_ptr = nullptr; + config->with_raw_node([&](char const *ptr, Genode::size_t) + { config_ptr = const_cast(ptr); }); + char *config_end = config_ptr + config_len; + + /* Determine length of the tail after the child's start node */ + Genode::size_t tail_len = static_cast(config_end - node_end); + + /* Remove child's start node with memmove */ + Genode::memmove(node_ptr-1, node_end, tail_len); + *(node_ptr + tail_len) = '\0'; + + /* Reparse changed buffer */ + Xml_node *new_config = new (_heap) Xml_node(config_ptr, config_len - len); + _heap.free(config, sizeof(Xml_node)); + config = new_config; + } + catch (Genode::Xml_node::Nonexistent_sub_node) + { + Genode::error("Could not find child's start node"); + return config; + }; + + Genode::log("Removed child ", child.name()); + apply_config(*config); maintain_cells(); } + return config; } }; @@ -504,7 +548,7 @@ void Genode::Sandbox::Library::apply_config(Xml_node const &config) _children.for_each_child([&] (Child &child) { - if (child.abandoned()) + if (child.abandoned()) return; if (child.restart_scheduled()) { @@ -557,7 +601,6 @@ void Genode::Sandbox::Library::maintain_cells() int lower_limit = _affinity_space->total() - _core_allocator->cores_available(); _children.for_each_child([&](Child &child) { - log(child.name(), " ram: ", child.ram_quota()); if (!(child.is_brick())) _core_allocator->update(child, &xpos, &lower_limit); }); } @@ -688,8 +731,9 @@ Genode::Sandbox::Local_service_base::Local_service_base(Sandbox &sandbox, _session_factory(sandbox._heap, Session_state::Factory::Batch_size{16}), _async_wakeup(wakeup), _async_service(name, _server_id_space, _session_factory, _async_wakeup) -{ } - +{ + Genode::log("Adding local service ", name); +} /************* ** Sandbox ** @@ -706,9 +750,9 @@ void Genode::Sandbox::generate_state_report(Xml_generator &xml) const _library.generate_state_report(xml); } -void Genode::Sandbox::update(::Sandbox::Child &child) +Genode::Xml_node* Genode::Sandbox::update(::Sandbox::Child &child, Genode::Xml_node *config) { - _library.update(child); + return _library.update(child, config); } Genode::Sandbox::Sandbox(Env &env, State_handler &state_handler, Pd_intrinsics &pd_intrinsics) diff --git a/repos/ealanos/src/lib/sandbox/utils.h b/repos/ealanos/src/lib/sandbox/utils.h index 9962f7e1a1..cc71780bfc 100644 --- a/repos/ealanos/src/lib/sandbox/utils.h +++ b/repos/ealanos/src/lib/sandbox/utils.h @@ -145,19 +145,23 @@ namespace Sandbox { FILTER_FN const &filter_fn) { T *service = nullptr; - services.for_each([&] (T &s) { - + services.for_each([&](T &s) + { if (service || s.name() != name || filter_fn(s)) return; - service = &s; - }); + service = &s; }); - if (!service) + if (!service) { + Genode::log("Service ", name, " not found"); throw Service_denied(); + } if (service->abandoned()) + { + Genode::log("Service ", name, " abandoned."); throw Service_denied(); + } return *service; } diff --git a/repos/os/src/init/config.xsd b/repos/os/src/init/config.xsd index 015e2d6f8f..58e8d66e2c 100644 --- a/repos/os/src/init/config.xsd +++ b/repos/os/src/init/config.xsd @@ -7,6 +7,7 @@ +