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
This commit is contained in:
Norman Feske 2024-09-02 17:20:12 +02:00
parent cf507a0b86
commit ec50c008bb
11 changed files with 330 additions and 159 deletions

View File

@ -1,4 +1,4 @@
<runtime ram="7M" caps="400" binary="init">
<runtime ram="10M" caps="450" binary="init">
<requires>
<gui/>
@ -49,7 +49,7 @@
</route>
</start>
<start name="window_layouter">
<start name="window_layouter" caps="120">
<resource name="RAM" quantum="6M"/>
<route>
<service name="ROM" label="config">

View File

@ -1,4 +1,4 @@
<runtime ram="20M" caps="500" binary="init" config="wm.config">
<runtime ram="12M" caps="350" binary="init" config="wm.config">
<requires>
<gui label="focus"/>

View File

@ -46,8 +46,8 @@
</config>
</start>
<start name="wm" caps="250">
<resource name="RAM" quantum="6M"/>
<start name="wm" caps="100">
<resource name="RAM" quantum="2M"/>
<provides>
<service name="Gui"/> <service name="Report"/> <service name="ROM"/>
</provides>
@ -70,7 +70,7 @@
</route>
</start>
<start name="layouter">
<start name="layouter" caps="120">
<binary name="window_layouter"/>
<resource name="RAM" quantum="4M"/>
<route>

View File

@ -74,8 +74,8 @@
</config>
</start>
<start name="wm" caps="250">
<resource name="RAM" quantum="8M"/>
<start name="wm" caps="150">
<resource name="RAM" quantum="2M"/>
<provides>
<service name="Gui"/> <service name="Report"/> <service name="ROM"/>
</provides>

View File

@ -108,7 +108,7 @@ install_config {
</route>
</start>
<start name="backdrop" priority="-1">
<start name="backdrop" priority="-1" caps="120">
<resource name="RAM" quantum="24M"/>
<config>
<libc/>
@ -127,7 +127,7 @@ install_config {
</route>
</start>
<start name="wm_backdrop" priority="-1">
<start name="wm_backdrop" priority="-1" caps="120">
<binary name="backdrop" />
<resource name="RAM" quantum="32M"/>
<config>

View File

@ -142,8 +142,8 @@
</config>
</start>
<start name="wm" caps="300" priority="-1">
<resource name="RAM" quantum="4M"/>
<start name="wm" caps="150" priority="-1">
<resource name="RAM" quantum="2M"/>
<provides>
<service name="Gui"/> <service name="Report"/> <service name="ROM"/>
</provides>
@ -160,7 +160,7 @@
</route>
</start>
<start name="decorator" caps="400" priority="-1">
<start name="decorator" caps="450" priority="-1">
<binary name="themed_decorator"/>
<resource name="RAM" quantum="20M"/>
<resource name="CPU" quantum="20"/>
@ -264,7 +264,7 @@
</route>
</start>
<start name="log_terminal" priority="-1">
<start name="log_terminal" priority="-1" caps="120">
<binary name="terminal"/>
<resource name="RAM" quantum="8M"/>
<provides> <service name="Terminal"/> </provides>

View File

@ -21,12 +21,12 @@
#include <input/component.h>
/* local includes */
#include <types.h>
#include <window_registry.h>
#include <pointer.h>
#include <real_gui.h>
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<Gui::Session>,
private List<Decorator_gui_session>::Element
private List<Decorator_gui_session>::Element,
private Upgradeable
{
friend class List<Decorator_gui_session>;
using List<Decorator_gui_session>::Element::next;
@ -82,13 +83,15 @@ struct Wm::Decorator_gui_session : Genode::Session_object<Gui::Session>,
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, 4000> _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<Gui::Session>,
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<Gui::Session>,
}
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<Gui::Session>(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<Gui::Session>,
_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<Gui::Session>,
[&] { });
/* 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<Gui::Session>,
*/
_content_view_ids.apply<Content_view_ref const>(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<Gui::Session>,
_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<Gui::Session>,
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<Gui::Session>,
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<Gui::Session>,
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<Gui::Session>,
_content_callback.hide_content_child_views(view_ref.win_id);
Gui::Rect rect(Gui::Point(0, 0), Gui::Area(0, 0));
_gui.enqueue<Gui::Session::Command::Geometry>(view, rect);
_gui.execute();
_real_gui.enqueue<Gui::Session::Command::Geometry>(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<Content_view_ref>(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<Gui::Session>,
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<Gui::Session>,
* 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<Gui::Session>) override { }

View File

@ -246,6 +246,10 @@ class Wm::Gui::View : private Genode::Weak_object<View>,
class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Element
{
public:
using View_result = Gui::Session::View_result;
private:
friend class List<Top_level_view>;
@ -268,6 +272,15 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::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<Top_level_view>::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<Top_level_view>::Eleme
View::lock_for_destruction();
}
View_result real_view_result() const { return _real_view_result; }
using List<Top_level_view>::Element::next;
void _propagate_view_geometry() override { }
@ -372,6 +380,10 @@ class Wm::Gui::Top_level_view : public View, private List<Top_level_view>::Eleme
class Wm::Gui::Child_view : public View, private List<Child_view>::Element
{
public:
using View_result = Gui::Session::Child_view_result;
private:
friend class List<Child_view>;
@ -380,6 +392,8 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::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<Child_view>::Element
Weak_ptr<View> 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<Child_view>::Element::next;
void _propagate_view_geometry() override
@ -426,11 +440,15 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::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<View> 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<Child_view>::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<Child_view>::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<Child_view>::Element
class Wm::Gui::Session_component : public Session_object<Gui::Session>,
private List<Session_component>::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<Gui::Session>,
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, 8000> _top_level_view_alloc;
Tslab<Child_view, 7000> _child_view_alloc;
Tslab<View_ref, 4000> _view_ref_alloc;
Slab<Top_level_view, 8000> _top_level_view_alloc { _session_alloc };
Slab<Child_view, 7000> _child_view_alloc { _session_alloc };
Slab<View_ref, 4000> _view_ref_alloc { _session_alloc };
List<Top_level_view> _top_level_views { };
List<Child_view> _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<Gui::Session>,
_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<Gui::Session>,
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<Gui::Session>(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<Gui::Session>,
while (Child_view *view = _child_views.first())
_destroy_child_view(*view);
_env.ep().dissolve(_input_session);
}
using List<Session_component>::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<Gui::Session>,
Input::Session_capability input() override
{
return _input_session_cap;
return _input_session.cap();
}
template <typename VIEW>
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<Gui::Session>,
_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<Gui::Session>,
Child_view *view_ptr = nullptr;
View_result const result =
Child_view_result const result =
_create_view_with_id<Child_view>(_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<Gui::Session>,
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<Gui::Session>,
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<Gui::Session>,
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::Typed_root<Gui::Session>
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<Genode::Typed_root<Gui::Session>
/**
* 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<Genode::Typed_root<Gui::Session>
** 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<Genode::Typed_root<Gui::Session>
}
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<Genode::Typed_root<Gui::Session>
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<Genode::Typed_root<Gui::Session>
dynamic_cast<Session_component *>(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<Decorator_gui_session *>(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<Direct_gui_session *>(session);
@ -1378,7 +1477,7 @@ class Wm::Gui::Root : public Genode::Rpc_object<Genode::Typed_root<Gui::Session>
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<Genode::Typed_root<Gui::Session>
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<Genode::Typed_root<Gui::Session>
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<Genode::Typed_root<Gui::Session>
};
if (ep.apply(session_cap, layouter_lambda) == _layouter_session) {
Genode::destroy(_md_alloc, _layouter_session);
Genode::destroy(_sliced_heap, _layouter_session);
return;
}
}

View File

@ -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 };

View File

@ -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<Gui::Session> connection {
_env, label, Genode::Ram_quota { 36*1024 }, /* Args */ { } };
_env, label, Genode::Ram_quota { RAM_QUOTA }, /* Args */ { } };
Gui::Session_client session { connection.cap() };

View File

@ -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 <base/tslab.h>
#include <base/attached_rom_dataspace.h>
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 <size_t BLOCK_SIZE>
struct Initial_slab_block { uint8_t buf[BLOCK_SIZE]; };
template <typename T, size_t BLOCK_SIZE>
struct Slab : private Initial_slab_block<BLOCK_SIZE>, Tslab<T, BLOCK_SIZE>
{
Slab(Allocator &block_alloc)
: Tslab<T, BLOCK_SIZE>(block_alloc, Initial_slab_block<BLOCK_SIZE>::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_ */