From ec50c008bbaf4ac38f4dd1388ec238988b702798 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 2 Sep 2024 17:20:12 +0200 Subject: [PATCH] wm: account session resources With this patch, the wm accounts RAM and caps consumed on behalf of its clients to the respective client's session quota instead of paying out of its own pocket. This should make the wm resilient against resource exhaustion and lowers the quota requirements. Issue #5340 --- .../gems/recipes/pkg/window_layouter/runtime | 4 +- repos/gems/recipes/pkg/wm/runtime | 2 +- repos/gems/recipes/raw/motif_wm/wm.config | 6 +- repos/gems/recipes/raw/wm/wm.config | 4 +- repos/gems/run/wm.run | 4 +- repos/gems/sculpt/leitzentrale/default | 8 +- repos/gems/src/server/wm/decorator_gui.h | 87 +++--- repos/gems/src/server/wm/gui.h | 291 ++++++++++++------ repos/gems/src/server/wm/main.cc | 7 +- repos/gems/src/server/wm/real_gui.h | 4 +- repos/gems/src/server/wm/types.h | 72 +++++ 11 files changed, 330 insertions(+), 159 deletions(-) create mode 100644 repos/gems/src/server/wm/types.h diff --git a/repos/gems/recipes/pkg/window_layouter/runtime b/repos/gems/recipes/pkg/window_layouter/runtime index c4034a9062..15ffb76358 100644 --- a/repos/gems/recipes/pkg/window_layouter/runtime +++ b/repos/gems/recipes/pkg/window_layouter/runtime @@ -1,4 +1,4 @@ - + @@ -49,7 +49,7 @@ - + diff --git a/repos/gems/recipes/pkg/wm/runtime b/repos/gems/recipes/pkg/wm/runtime index d37fdf039f..4545d796c0 100644 --- a/repos/gems/recipes/pkg/wm/runtime +++ b/repos/gems/recipes/pkg/wm/runtime @@ -1,4 +1,4 @@ - + diff --git a/repos/gems/recipes/raw/motif_wm/wm.config b/repos/gems/recipes/raw/motif_wm/wm.config index 7a31d0009c..006af7a5ef 100644 --- a/repos/gems/recipes/raw/motif_wm/wm.config +++ b/repos/gems/recipes/raw/motif_wm/wm.config @@ -46,8 +46,8 @@ - - + + @@ -70,7 +70,7 @@ - + diff --git a/repos/gems/recipes/raw/wm/wm.config b/repos/gems/recipes/raw/wm/wm.config index a967d99475..56235b11c2 100644 --- a/repos/gems/recipes/raw/wm/wm.config +++ b/repos/gems/recipes/raw/wm/wm.config @@ -74,8 +74,8 @@ - - + + diff --git a/repos/gems/run/wm.run b/repos/gems/run/wm.run index 9db7234587..3cf51763a3 100644 --- a/repos/gems/run/wm.run +++ b/repos/gems/run/wm.run @@ -108,7 +108,7 @@ install_config { - + @@ -127,7 +127,7 @@ install_config { - + diff --git a/repos/gems/sculpt/leitzentrale/default b/repos/gems/sculpt/leitzentrale/default index 323b127b96..13c7801756 100644 --- a/repos/gems/sculpt/leitzentrale/default +++ b/repos/gems/sculpt/leitzentrale/default @@ -142,8 +142,8 @@ - - + + @@ -160,7 +160,7 @@ - + @@ -264,7 +264,7 @@ - + diff --git a/repos/gems/src/server/wm/decorator_gui.h b/repos/gems/src/server/wm/decorator_gui.h index 6941181810..7020efd52e 100644 --- a/repos/gems/src/server/wm/decorator_gui.h +++ b/repos/gems/src/server/wm/decorator_gui.h @@ -21,12 +21,12 @@ #include /* local includes */ +#include #include #include #include namespace Wm { class Main; - using Genode::size_t; using Genode::Allocator; using Genode::Arg_string; using Genode::Object_pool; @@ -59,7 +59,8 @@ struct Wm::Decorator_content_callback : Interface struct Wm::Decorator_gui_session : Genode::Session_object, - private List::Element + private List::Element, + private Upgradeable { friend class List; using List::Element::next; @@ -82,13 +83,15 @@ struct Wm::Decorator_gui_session : Genode::Session_object, Genode::Env &_env; - Genode::Heap _heap { _env.ram(), _env.rm() }; + Genode::Constrained_ram_allocator _ram { _env.ram(), _ram_quota_guard(), _cap_quota_guard() }; - Genode::Ram_allocator &_ram; + Genode::Sliced_heap _session_alloc { _ram, _env.rm() }; - Real_gui _gui { _env, "decorator" }; + Slab _content_view_ref_alloc { _session_alloc }; - Input::Session_client _input_session { _env.rm(), _gui.session.input() }; + Real_gui _real_gui { _env, "decorator" }; + + Input::Session_client _input_session { _env.rm(), _real_gui.session.input() }; Genode::Signal_context_capability _mode_sigh { }; @@ -102,8 +105,6 @@ struct Wm::Decorator_gui_session : Genode::Session_object, Decorator_content_callback &_content_callback; - Allocator &_md_alloc; - /* Gui::Connection requires a valid input session */ Input::Session_component _dummy_input_component { _env, _env.ram() }; Input::Session_capability _dummy_input_component_cap = @@ -120,22 +121,18 @@ struct Wm::Decorator_gui_session : Genode::Session_object, } Decorator_gui_session(Genode::Env &env, - Genode::Ram_allocator &ram, Resources const &resources, Label const &label, Diag const &diag, - Allocator &md_alloc, Pointer::Tracker &pointer_tracker, Input::Session_component &window_layouter_input, Decorator_content_callback &content_callback) : Session_object(env.ep(), resources, label, diag), _env(env), - _ram(ram), _pointer_state(pointer_tracker), _window_layouter_input(window_layouter_input), - _content_callback(content_callback), - _md_alloc(md_alloc) + _content_callback(content_callback) { _input_session.sigh(_input_handler); } @@ -145,6 +142,11 @@ struct Wm::Decorator_gui_session : Genode::Session_object, _env.ep().dissolve(_dummy_input_component); } + void upgrade_local_or_remote(Resources const &resources) + { + _upgrade_local_or_remote(resources, *this, _real_gui); + } + void _handle_input() { while (_input_session.pending()) @@ -170,7 +172,7 @@ struct Wm::Decorator_gui_session : Genode::Session_object, [&] { }); /* forward command */ - _gui.enqueue(cmd); + _real_gui.enqueue(cmd); return; case Command::OFFSET: @@ -181,7 +183,7 @@ struct Wm::Decorator_gui_session : Genode::Session_object, */ _content_view_ids.apply(cmd.geometry.view, [&] (Content_view_ref const &) { }, - [&] { _gui.enqueue(cmd); }); + [&] { _real_gui.enqueue(cmd); }); return; case Command::FRONT: @@ -194,23 +196,18 @@ struct Wm::Decorator_gui_session : Genode::Session_object, _content_callback.update_content_child_views(view_ref.win_id); }, [&] { }); - _gui.enqueue(cmd); + _real_gui.enqueue(cmd); return; case Command::TITLE: case Command::BACKGROUND: case Command::NOP: - _gui.enqueue(cmd); + _real_gui.enqueue(cmd); return; } } - void upgrade(const char *args) - { - _gui.connection.upgrade(Genode::session_resources_from_args(args)); - } - Pointer::Position last_observed_pointer_pos() const { return _pointer_state.last_observed_pos(); @@ -223,7 +220,7 @@ struct Wm::Decorator_gui_session : Genode::Session_object, Framebuffer::Session_capability framebuffer() override { - return _gui.session.framebuffer(); + return _real_gui.session.framebuffer(); } Input::Session_capability input() override @@ -245,13 +242,13 @@ struct Wm::Decorator_gui_session : Genode::Session_object, Window_registry::Id const win_id = _win_id_from_title(attr.title); if (win_id.valid()) { try { - Content_view_ref &view_ref_ptr = *new (_heap) + Content_view_ref &view_ref_ptr = *new (_content_view_ref_alloc) Content_view_ref(Window_registry::Id(win_id), _content_view_ids, id); View_capability view_cap = _content_callback.content_view(win_id); - Associate_result result = _gui.session.associate(id, view_cap); + Associate_result result = _real_gui.session.associate(id, view_cap); if (result != Associate_result::OK) - destroy(_heap, &view_ref_ptr); + destroy(_content_view_ref_alloc, &view_ref_ptr); switch (result) { case Associate_result::OUT_OF_RAM: return View_result::OUT_OF_RAM; @@ -260,15 +257,21 @@ struct Wm::Decorator_gui_session : Genode::Session_object, case Associate_result::INVALID: break; /* fall back to regular view */ }; } - catch (Genode::Out_of_ram) { return View_result::OUT_OF_RAM; } - catch (Genode::Out_of_caps) { return View_result::OUT_OF_CAPS; } + catch (Genode::Out_of_ram) { + _starved_for_ram = true; + return View_result::OUT_OF_RAM; + } + catch (Genode::Out_of_caps) { + _starved_for_caps = true; + return View_result::OUT_OF_CAPS; + } } - return _gui.session.view(id, attr); + return _real_gui.session.view(id, attr); } Child_view_result child_view(View_id id, View_id parent, View_attr const &attr) override { - return _gui.session.child_view(id, parent, attr); + return _real_gui.session.child_view(id, parent, attr); } void destroy_view(View_id view) override @@ -282,33 +285,33 @@ struct Wm::Decorator_gui_session : Genode::Session_object, _content_callback.hide_content_child_views(view_ref.win_id); Gui::Rect rect(Gui::Point(0, 0), Gui::Area(0, 0)); - _gui.enqueue(view, rect); - _gui.execute(); + _real_gui.enqueue(view, rect); + _real_gui.execute(); - destroy(_heap, &view_ref); + destroy(_content_view_ref_alloc, &view_ref); }, [&] { }); - _gui.session.destroy_view(view); + _real_gui.session.destroy_view(view); } Associate_result associate(View_id id, View_capability view_cap) override { - return _gui.session.associate(id, view_cap); + return _real_gui.session.associate(id, view_cap); } View_capability_result view_capability(View_id view) override { - return _gui.session.view_capability(view); + return _real_gui.session.view_capability(view); } void release_view_id(View_id view) override { _content_view_ids.apply(view, - [&] (Content_view_ref &view_ref) { destroy(_heap, &view_ref); }, + [&] (Content_view_ref &view_ref) { destroy(_content_view_ref_alloc, &view_ref); }, [&] { }); - _gui.session.release_view_id(view); + _real_gui.session.release_view_id(view); } Genode::Dataspace_capability command_dataspace() override @@ -321,12 +324,12 @@ struct Wm::Decorator_gui_session : Genode::Session_object, for (unsigned i = 0; i < _client_command_buffer.num(); i++) _execute_command(_client_command_buffer.get(i)); - _gui.execute(); + _real_gui.execute(); } Framebuffer::Mode mode() override { - return _gui.session.mode(); + return _real_gui.session.mode(); } void mode_sigh(Genode::Signal_context_capability sigh) override @@ -336,12 +339,12 @@ struct Wm::Decorator_gui_session : Genode::Session_object, * transitive delegations of the capability. */ _mode_sigh = sigh; - _gui.session.mode_sigh(sigh); + _real_gui.session.mode_sigh(sigh); } Buffer_result buffer(Framebuffer::Mode mode, bool use_alpha) override { - return _gui.session.buffer(mode, use_alpha); + return _real_gui.session.buffer(mode, use_alpha); } void focus(Genode::Capability) override { } diff --git a/repos/gems/src/server/wm/gui.h b/repos/gems/src/server/wm/gui.h index a6055e05d3..290ce34e09 100644 --- a/repos/gems/src/server/wm/gui.h +++ b/repos/gems/src/server/wm/gui.h @@ -246,6 +246,10 @@ class Wm::Gui::View : private Genode::Weak_object, class Wm::Gui::Top_level_view : public View, private List::Element { + public: + + using View_result = Gui::Session::View_result; + private: friend class List; @@ -268,6 +272,15 @@ class Wm::Gui::Top_level_view : public View, private List::Eleme Session_label const _session_label; + View_result _init_real_view() + { + return _real_gui.session.view(_real_view.id(), { .title = _title, + .rect = { }, + .front = false }); + } + + View_result const _real_view_result = _init_real_view(); + using Command = Gui::Session::Command; public: @@ -281,14 +294,7 @@ class Wm::Gui::Top_level_view : public View, private List::Eleme _window_registry(window_registry), _input_origin_changed_handler(input_origin_changed_handler), _session_label(real_gui.label) - { - /* - * Create and configure physical GUI view. - */ - _real_gui.session.view(_real_view.id(), { .title = _title, - .rect = { }, - .front = false }); - } + { } ~Top_level_view() { @@ -298,6 +304,8 @@ class Wm::Gui::Top_level_view : public View, private List::Eleme View::lock_for_destruction(); } + View_result real_view_result() const { return _real_view_result; } + using List::Element::next; void _propagate_view_geometry() override { } @@ -372,6 +380,10 @@ class Wm::Gui::Top_level_view : public View, private List::Eleme class Wm::Gui::Child_view : public View, private List::Element { + public: + + using View_result = Gui::Session::Child_view_result; + private: friend class List; @@ -380,6 +392,8 @@ class Wm::Gui::Child_view : public View, private List::Element bool _visible = false; + View_result _real_view_result = try_to_init_real_view(); + public: Child_view(Real_gui &real_gui, @@ -387,15 +401,15 @@ class Wm::Gui::Child_view : public View, private List::Element Weak_ptr parent) : View(real_gui, real_gui.label, has_alpha), _parent(parent) - { - try_to_init_real_view(); - } + { } ~Child_view() { View::lock_for_destruction(); } + View_result real_view_result() const { return _real_view_result; } + using List::Element::next; void _propagate_view_geometry() override @@ -426,11 +440,15 @@ class Wm::Gui::Child_view : public View, private List::Element return Point(); } - void try_to_init_real_view() + View_result try_to_init_real_view() { + using Child_view_result = Gui::Session::Child_view_result; + + Child_view_result result = Child_view_result::INVALID; + Locked_ptr parent(_parent); if (!parent.valid()) - return; + return result; _with_temporary_view_id(parent->real_view_cap(), [&] (View_id parent_id) { @@ -441,15 +459,13 @@ class Wm::Gui::Child_view : public View, private List::Element .rect = _geometry, .front = false }; - switch (_real_gui.session.child_view(_real_view.id(), parent_id, attr)) { - case Gui::Session::Child_view_result::OUT_OF_RAM: - case Gui::Session::Child_view_result::OUT_OF_CAPS: - case Gui::Session::Child_view_result::INVALID: + result = _real_gui.session.child_view(_real_view.id(), parent_id, attr); + + if (result != Child_view_result::OK) { warning("unable to create child view"); return; - case Gui::Session::Child_view_result::OK: - break; - }; + } + _visible = true; }); @@ -457,6 +473,8 @@ class Wm::Gui::Child_view : public View, private List::Element _unsynchronized_apply_view_config(parent); else _apply_view_config(); + + return result; } void update_child_stacking() @@ -474,7 +492,8 @@ class Wm::Gui::Child_view : public View, private List::Element class Wm::Gui::Session_component : public Session_object, private List::Element, - private Input_origin_changed_handler + private Input_origin_changed_handler, + private Upgradeable { private: @@ -513,17 +532,33 @@ class Wm::Gui::Session_component : public Session_object, Genode::Env &_env; - Genode::Ram_allocator &_ram; + Genode::Constrained_ram_allocator _ram { + _env.ram(), _ram_quota_guard(), _cap_quota_guard() }; + + Genode::Sliced_heap _session_alloc { _ram, _env.rm() }; Real_gui _real_gui { _env, _label }; Window_registry &_window_registry; - Tslab _top_level_view_alloc; - Tslab _child_view_alloc; - Tslab _view_ref_alloc; + Slab _top_level_view_alloc { _session_alloc }; + Slab _child_view_alloc { _session_alloc }; + Slab _view_ref_alloc { _session_alloc }; List _top_level_views { }; List _child_views { }; View_ids _view_ids { }; - Input::Session_component _input_session { _env, _ram }; - Input::Session_capability _input_session_cap; + + struct Input_session : Input::Session_component + { + Entrypoint &_ep; + + Input_session(Env &env, Ram_allocator &ram) + : Input::Session_component(env, ram), _ep(env.ep()) + { + _ep.manage(*this); + } + + ~Input_session() { _ep.dissolve(*this); } + }; + + Input_session _input_session { _env, _ram }; Click_handler &_click_handler; Signal_context_capability _mode_sigh { }; Area _requested_size { }; @@ -701,17 +736,25 @@ class Wm::Gui::Session_component : public Session_object, _input_session.submit(Input::Absolute_motion { pos.x, pos.y }); } + void _dissolve_view_from_ep(View &view) + { + if (view.cap().valid()) { + _env.ep().dissolve(view); + replenish(Cap_quota { 1 }); + } + } + void _destroy_top_level_view(Top_level_view &view) { _top_level_views.remove(&view); - _env.ep().dissolve(view); + _dissolve_view_from_ep(view); Genode::destroy(&_top_level_view_alloc, &view); } void _destroy_child_view(Child_view &view) { _child_views.remove(&view); - _env.ep().dissolve(view); + _dissolve_view_from_ep(view); Genode::destroy(&_child_view_alloc, &view); } @@ -782,24 +825,17 @@ class Wm::Gui::Session_component : public Session_object, public: - Session_component(Genode::Env &env, - Genode::Ram_allocator &ram, - Resources const &resources, - Label const &label, - Diag const diag, - Window_registry &window_registry, - Allocator &session_alloc, - Pointer::Tracker &pointer_tracker, - Click_handler &click_handler) + Session_component(Genode::Env &env, + Resources const &resources, + Label const &label, + Diag const diag, + Window_registry &window_registry, + Pointer::Tracker &pointer_tracker, + Click_handler &click_handler) : Session_object(env.ep(), resources, label, diag), _env(env), - _ram(ram), _window_registry(window_registry), - _top_level_view_alloc(&session_alloc), - _child_view_alloc(&session_alloc), - _view_ref_alloc(&session_alloc), - _input_session_cap(env.ep().manage(_input_session)), _click_handler(click_handler), _pointer_state(pointer_tracker) { @@ -818,15 +854,13 @@ class Wm::Gui::Session_component : public Session_object, while (Child_view *view = _child_views.first()) _destroy_child_view(*view); - - _env.ep().dissolve(_input_session); } using List::Element::next; - void upgrade(char const *args) + void upgrade_local_or_remote(Resources const &resources) { - _real_gui.connection.upgrade(Genode::session_resources_from_args(args)); + _upgrade_local_or_remote(resources, *this, _real_gui); } void try_to_init_real_child_views() @@ -930,39 +964,64 @@ class Wm::Gui::Session_component : public Session_object, Input::Session_capability input() override { - return _input_session_cap; + return _input_session.cap(); } template - View_result _create_view_with_id(auto &dealloc, View_id id, View_attr const &attr, auto const &create_fn) + VIEW::View_result _create_view_with_id(auto &dealloc, View_id id, View_attr const &attr, auto const &create_fn) { + using Result = VIEW::View_result; + + /* precondition for obtaining 'real_view_cap' */ + if (!try_withdraw(Cap_quota { 1 })) { + _starved_for_caps = true; + return Result::OUT_OF_CAPS; + } + release_view_id(id); - View_result error { }; + Result error { }; VIEW *view_ptr = nullptr; try { view_ptr = &create_fn(); } - catch (Out_of_ram) { error = View_result::OUT_OF_RAM; } - catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + error = Result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + error = Result::OUT_OF_CAPS; + } if (!view_ptr) return error; + /* _real_gui view creation may return OUT_OF_RAM or OUT_OF_CAPS */ + if (view_ptr->real_view_result() != Result::OK) { + error = view_ptr->real_view_result(); + destroy(dealloc, view_ptr); + return error; + } + View_ref *view_ref_ptr = nullptr; try { view_ref_ptr = new (_view_ref_alloc) View_ref(view_ptr->weak_ptr(), _view_ids, id); } - catch (Out_of_ram) { error = View_result::OUT_OF_RAM; } - catch (Out_of_caps) { error = View_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + error = Result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + error = Result::OUT_OF_CAPS; + } if (!view_ref_ptr) { destroy(dealloc, view_ptr); return error; } - _env.ep().manage(*view_ptr); - /* apply initial view attributes */ _execute_command(Command::Title { id, attr.title }); _execute_command(Command::Geometry { id, attr.rect }); @@ -971,7 +1030,7 @@ class Wm::Gui::Session_component : public Session_object, _window_registry.flush(); } - return View_result::OK; + return Result::OK; } View_result view(View_id id, View_attr const &attr) override @@ -1001,7 +1060,7 @@ class Wm::Gui::Session_component : public Session_object, Child_view *view_ptr = nullptr; - View_result const result = + Child_view_result const result = _create_view_with_id(_child_view_alloc, id, attr, [&] () -> Child_view & { view_ptr = new (_child_view_alloc) @@ -1009,16 +1068,10 @@ class Wm::Gui::Session_component : public Session_object, return *view_ptr; }); - switch (result) { - case View_result::OUT_OF_RAM: return Child_view_result::OUT_OF_RAM; - case View_result::OUT_OF_CAPS: return Child_view_result::OUT_OF_CAPS; - case View_result::OK: break; - } - - if (view_ptr) + if (result == Child_view_result::OK && view_ptr) _child_views.insert(view_ptr); - return Child_view_result::OK; + return result; }, [&] () -> Child_view_result { return Child_view_result::INVALID; }); } @@ -1030,11 +1083,13 @@ class Wm::Gui::Session_component : public Session_object, for (Child_view *v = _child_views.first(); v; v = v->next()) if (&view == v) { _destroy_child_view(*v); + replenish(Cap_quota { 1 }); return; } for (Top_level_view *v = _top_level_views.first(); v; v = v->next()) if (&view == v) { _destroy_top_level_view(*v); + replenish(Cap_quota { 1 }); return; } }, @@ -1056,16 +1111,32 @@ class Wm::Gui::Session_component : public Session_object, new (_view_ref_alloc) View_ref(view_ptr->weak_ptr(), _view_ids, id); return Associate_result::OK; } - catch (Out_of_ram) { return Associate_result::OUT_OF_RAM; } - catch (Out_of_caps) { return Associate_result::OUT_OF_CAPS; } + catch (Out_of_ram) { + _starved_for_ram = true; + return Associate_result::OUT_OF_RAM; + } + catch (Out_of_caps) { + _starved_for_caps = true; + return Associate_result::OUT_OF_CAPS; + } }); } View_capability_result view_capability(View_id id) override { return _with_view(id, - [&] (View &view) { return view.cap(); }, - [&] /* view does not exist */ { return View_capability(); }); + [&] (View &view) -> View_capability_result + { + if (!view.cap().valid()) { + if (!try_withdraw(Cap_quota { 1 })) { + _starved_for_caps = true; + return View_capability_error::OUT_OF_CAPS; + } + _env.ep().manage(view); + } + return view.cap(); + }, + [&] () -> View_capability_result { return View_capability(); }); } void release_view_id(View_id id) override @@ -1166,9 +1237,7 @@ class Wm::Gui::Root : public Genode::Rpc_object Genode::Attached_rom_dataspace _config { _env, "config" }; - Allocator &_md_alloc; - - Genode::Ram_allocator &_ram; + Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; enum { STACK_SIZE = 1024*sizeof(long) }; @@ -1224,14 +1293,11 @@ class Wm::Gui::Root : public Genode::Rpc_object /** * Constructor */ - Root(Genode::Env &env, - Window_registry &window_registry, Allocator &md_alloc, - Genode::Ram_allocator &ram, + Root(Genode::Env &env, Window_registry &window_registry, Pointer::Tracker &pointer_tracker, Reporter &focus_request_reporter, Gui::Connection &focus_gui_session) : _env(env), - _md_alloc(md_alloc), _ram(ram), _pointer_tracker(pointer_tracker), _focus_request_reporter(focus_request_reporter), _window_registry(window_registry), @@ -1265,12 +1331,14 @@ class Wm::Gui::Root : public Genode::Rpc_object ** Root interface ** ********************/ + static_assert(Gui::Session::CAP_QUOTA == 9); + Genode::Session_capability session(Session_args const &args, Affinity const &) override { - Genode::Session::Label const label = Genode::label_from_args(args.string()); - Genode::Session::Resources const resources = Genode::session_resources_from_args(args.string()); - Genode::Session::Diag const diag = Genode::session_diag_from_args(args.string()); + Genode::Session::Label label = Genode::label_from_args(args.string()); + Genode::Session::Resources resources = Genode::session_resources_from_args(args.string()); + Genode::Session::Diag diag = Genode::session_diag_from_args(args.string()); enum Role { ROLE_DECORATOR, ROLE_LAYOUTER, ROLE_REGULAR, ROLE_DIRECT }; Role role = ROLE_REGULAR; @@ -1290,34 +1358,65 @@ class Wm::Gui::Root : public Genode::Rpc_object } catch (...) { } + if (role == ROLE_REGULAR || role == ROLE_DECORATOR) { + + size_t const needed_ram = Real_gui::RAM_QUOTA + + sizeof(Session_component) + + _sliced_heap.overhead(sizeof(Session_component)) + + 8*1024; + + if (resources.ram_quota.value < needed_ram) + throw Insufficient_ram_quota(); + resources.ram_quota.value -= needed_ram; + + static constexpr unsigned needed_caps = + 1 + /* Sliced_heap alloc of Session_component */ + 1 + /* Session_component RPC cap */ + 9 + /* Wrapped nitpicker GUI session (_real_gui) */ + 1 + /* Input_session RPC cap (_input_session) */ + 1 + /* Input_session events dataspace (_input_session) */ + 1 + /* Command buffer (_command_buffer) */ + 1 + /* Input signal handler (_input_handler) */ + 1 + /* Mode signal handler (_mode_handler) */ + 1; /* Content-view capability */ + + if (resources.cap_quota.value < needed_caps) + throw Insufficient_cap_quota(); + /* preserve caps for content_view and command buffer ds */ + resources.cap_quota.value -= needed_caps - 2; + } + switch (role) { case ROLE_REGULAR: - { - Session_component &session = *new (_md_alloc) - Session_component(_env, _ram, resources, label, diag, - _window_registry, _md_alloc, + try { + Session_component &session = *new (_sliced_heap) + Session_component(_env, resources, label, diag, + _window_registry, _pointer_tracker, _click_handler); _sessions.insert(&session); return session.cap(); } + catch (Out_of_ram) { throw Insufficient_ram_quota(); } + catch (Out_of_caps) { throw Insufficient_cap_quota(); } case ROLE_DECORATOR: - { - Decorator_gui_session &session = *new (_md_alloc) - Decorator_gui_session(_env, _ram, resources, label, diag, - _md_alloc, + try { + Decorator_gui_session &session = *new (_sliced_heap) + Decorator_gui_session(_env, resources, label, diag, _pointer_tracker, _window_layouter_input, *this); _decorator_sessions.insert(&session); return session.cap(); } + catch (Out_of_ram) { throw Insufficient_ram_quota(); } + catch (Out_of_caps) { throw Insufficient_cap_quota(); } case ROLE_LAYOUTER: { - _layouter_session = new (_md_alloc) + _layouter_session = new (_sliced_heap) Layouter_gui_session(_env, resources, label, diag, _window_layouter_input_cap); @@ -1326,7 +1425,7 @@ class Wm::Gui::Root : public Genode::Rpc_object case ROLE_DIRECT: { - Direct_gui_session &session = *new (_md_alloc) + Direct_gui_session &session = *new (_sliced_heap) Direct_gui_session(_env, resources, label, diag); return session.cap(); @@ -1350,13 +1449,13 @@ class Wm::Gui::Root : public Genode::Rpc_object dynamic_cast(session); if (regular_session) - regular_session->upgrade(args.string()); + regular_session->upgrade_local_or_remote(session_resources_from_args(args.string())); Decorator_gui_session *decorator_session = dynamic_cast(session); if (decorator_session) - decorator_session->upgrade(args.string()); + decorator_session->upgrade_local_or_remote(session_resources_from_args(args.string())); Direct_gui_session *direct_session = dynamic_cast(session); @@ -1378,7 +1477,7 @@ class Wm::Gui::Root : public Genode::Rpc_object return session; }); if (regular_session) { - Genode::destroy(_md_alloc, regular_session); + Genode::destroy(_sliced_heap, regular_session); return; } @@ -1387,7 +1486,7 @@ class Wm::Gui::Root : public Genode::Rpc_object return session; }); if (direct_session) { - Genode::destroy(_md_alloc, direct_session); + Genode::destroy(_sliced_heap, direct_session); return; } @@ -1398,7 +1497,7 @@ class Wm::Gui::Root : public Genode::Rpc_object return session; }); if (decorator_session) { - Genode::destroy(_md_alloc, decorator_session); + Genode::destroy(_sliced_heap, decorator_session); return; } @@ -1408,7 +1507,7 @@ class Wm::Gui::Root : public Genode::Rpc_object }; if (ep.apply(session_cap, layouter_lambda) == _layouter_session) { - Genode::destroy(_md_alloc, _layouter_session); + Genode::destroy(_sliced_heap, _layouter_session); return; } } diff --git a/repos/gems/src/server/wm/main.cc b/repos/gems/src/server/wm/main.cc index 82d0fdbd49..9518188310 100644 --- a/repos/gems/src/server/wm/main.cc +++ b/repos/gems/src/server/wm/main.cc @@ -29,11 +29,6 @@ namespace Wm { class Main; - using Genode::size_t; - using Genode::Rom_session_client; - using Genode::Rom_connection; - using Genode::Xml_node; - using Genode::Attached_rom_dataspace; } @@ -62,7 +57,7 @@ struct Wm::Main : Pointer::Tracker Gui::Connection focus_gui_session { env }; - Gui::Root gui_root { env, window_registry, heap, env.ram(), + Gui::Root gui_root { env, window_registry, *this, focus_request_reporter, focus_gui_session }; diff --git a/repos/gems/src/server/wm/real_gui.h b/repos/gems/src/server/wm/real_gui.h index f41af24b0e..0cdcb382e9 100644 --- a/repos/gems/src/server/wm/real_gui.h +++ b/repos/gems/src/server/wm/real_gui.h @@ -34,6 +34,8 @@ struct Wm::Real_gui using Command_buffer = Gui::Session::Command_buffer; + static constexpr Genode::size_t RAM_QUOTA = 36*1024; + public: Real_gui(Genode::Env &env, Genode::Session_label const &label) @@ -42,7 +44,7 @@ struct Wm::Real_gui { } Genode::Connection connection { - _env, label, Genode::Ram_quota { 36*1024 }, /* Args */ { } }; + _env, label, Genode::Ram_quota { RAM_QUOTA }, /* Args */ { } }; Gui::Session_client session { connection.cap() }; diff --git a/repos/gems/src/server/wm/types.h b/repos/gems/src/server/wm/types.h new file mode 100644 index 0000000000..7f88379c23 --- /dev/null +++ b/repos/gems/src/server/wm/types.h @@ -0,0 +1,72 @@ +/* + * \brief Common types used within the window manager + * \author Norman Feske + * \date 2024-09-04 + */ + +/* + * Copyright (C) 2024 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 _TYPES_H_ +#define _TYPES_H_ + +/* Genode includes */ +#include +#include + +namespace Wm { + + using Genode::uint8_t; + using Genode::size_t; + using Genode::Rom_connection; + using Genode::Xml_node; + using Genode::Attached_rom_dataspace; + using Genode::Tslab; + using Genode::Cap_quota; + using Genode::Ram_quota; + + /* + * Slab allocator that includes an initial block as member + */ + template + struct Initial_slab_block { uint8_t buf[BLOCK_SIZE]; }; + template + struct Slab : private Initial_slab_block, Tslab + { + Slab(Allocator &block_alloc) + : Tslab(block_alloc, Initial_slab_block::buf) { }; + }; + + struct Upgradeable : Genode::Noncopyable + { + bool _starved_for_ram = false, _starved_for_caps = false; + + void _upgrade_local_or_remote(auto const &resources, auto &session_obj, auto &real_gui) + { + Ram_quota ram = resources.ram_quota; + Cap_quota caps = resources.cap_quota; + + if (_starved_for_caps && caps.value) { + session_obj.upgrade(caps); + _starved_for_caps = false; + caps = { }; + } + + if (_starved_for_ram && ram.value) { + session_obj.upgrade(ram); + _starved_for_ram = false; + ram = { }; + } + + if (ram.value || caps.value) { + real_gui.connection.upgrade({ ram, caps }); + } + } + }; +} + +#endif /* _TYPES_H_ */