gui_session: split alloc_view_handle, view_handle

Express the allocation of a new view handle by a dedicated RPC function
instead of passing an invalid view handle to the existing 'view_handle'
function.

This eliminates the notion of invalid view handles at the GUI session
interface, clearing the way for managing view handles via an Id_space.

Issue #5242
This commit is contained in:
Norman Feske 2024-08-06 16:44:04 +02:00 committed by Christian Helmuth
parent f274ed549e
commit 4e711d4738
15 changed files with 116 additions and 31 deletions

View File

@ -130,6 +130,9 @@ struct Gui::Session_component : Rpc_object<Gui::Session>
void destroy_view(View_handle view) override {
_gui_session.destroy_view(view); }
Alloc_view_handle_result alloc_view_handle(View_capability view_cap) override {
return _gui_session.alloc_view_handle(view_cap); }
View_handle_result view_handle(View_capability view_cap, View_handle handle) override {
return _gui_session.view_handle(view_cap, handle); }

View File

@ -172,7 +172,7 @@ class Decorator::Window : public Window_base, public Animator::Item
Gui::View_capability view_cap = remote_gui.view_capability(handle);
/* import remote view into local GUI session */
return _gui.view_handle(view_cap);
return _gui.alloc_view_handle(view_cap);
}
/**

View File

@ -134,6 +134,9 @@ struct Sandboxed_runtime::Gui_session : Session_object<Gui::Session>
void destroy_view(View_handle view) override {
_gui_session.destroy_view(view); }
Alloc_view_handle_result alloc_view_handle(View_capability view_cap) override {
return _gui_session.alloc_view_handle(view_cap); }
View_handle_result view_handle(View_capability view_cap, View_handle handle) override {
return _gui_session.view_handle(view_cap, handle); }

View File

@ -364,10 +364,16 @@ class Gui_fader::Gui_session_component
return _gui.destroy_view(handle);
}
Alloc_view_handle_result alloc_view_handle(View_capability view_cap) override
{
return _gui.alloc_view_handle(view_cap);
}
View_handle_result view_handle(View_capability view_cap,
View_handle handle) override
{
return _gui.view_handle(view_cap, handle);
_gui.view_handle(view_cap, handle);
return View_handle_result::OK;
}
View_capability view_capability(View_handle handle) override

View File

@ -386,6 +386,11 @@ struct Wm::Decorator_gui_session : Genode::Rpc_object<Gui::Session>,
_gui.session.destroy_view(view);
}
Alloc_view_handle_result alloc_view_handle(View_capability view_cap) override
{
return _gui.session.alloc_view_handle(view_cap);
}
View_handle_result view_handle(View_capability view_cap, View_handle handle) override
{
return _gui.session.view_handle(view_cap, handle);

View File

@ -80,6 +80,11 @@ class Wm::Direct_gui_session : public Genode::Rpc_object<Gui::Session>
_session.destroy_view(view);
}
Alloc_view_handle_result alloc_view_handle(Gui::View_capability view_cap) override
{
return _session.alloc_view_handle(view_cap);
}
View_handle_result view_handle(Gui::View_capability view_cap, View_handle handle) override
{
return _session.view_handle(view_cap, handle);

View File

@ -153,7 +153,7 @@ class Wm::Gui::View : private Genode::Weak_object<View>,
View_handle real_neighbor_handle;
if (neighbor.valid())
_real_gui.session.view_handle(neighbor->real_view_cap()).with_result(
_real_gui.session.alloc_view_handle(neighbor->real_view_cap()).with_result(
[&] (View_handle handle) { real_neighbor_handle = handle; },
[&] (auto) { warning("unable to obtain real_neighbor_handle"); }
);
@ -451,9 +451,9 @@ class Wm::Gui::Child_view : public View, private List<Child_view>::Element
return;
View_handle parent_handle { };
_real_gui.session.view_handle(parent->real_view_cap()).with_result(
_real_gui.session.alloc_view_handle(parent->real_view_cap()).with_result(
[&] (View_handle handle) { parent_handle = handle; },
[&] (Gui::Session::View_handle_error) { }
[&] (Gui::Session::Alloc_view_handle_error) { }
);
if (!parent_handle.valid()) {
warning("try_to_init_real_view failed to obtain parent handle");
@ -1005,15 +1005,27 @@ class Wm::Gui::Session_component : public Rpc_object<Gui::Session>,
} catch (View_handle_registry::Lookup_failed) { }
}
View_handle_result view_handle(View_capability view_cap, View_handle handle) override
Alloc_view_handle_result alloc_view_handle(View_capability view_cap) override
{
try {
return _env.ep().rpc_ep().apply(view_cap, [&] (View *view) {
return (view) ? _view_handle_registry.alloc(*view, handle)
return (view) ? _view_handle_registry.alloc(*view)
: View_handle(); });
}
catch (Out_of_ram) { return View_handle_error::OUT_OF_RAM; }
catch (Out_of_caps) { return View_handle_error::OUT_OF_CAPS; }
catch (Out_of_ram) { return Alloc_view_handle_error::OUT_OF_RAM; }
catch (Out_of_caps) { return Alloc_view_handle_error::OUT_OF_CAPS; }
}
View_handle_result view_handle(View_capability view_cap, View_handle handle) override
{
try {
_env.ep().rpc_ep().apply(view_cap, [&] (View *view) {
if (view)
_view_handle_registry.alloc(*view, handle); });
return View_handle_result::OK;
}
catch (Out_of_ram) { return View_handle_result::OUT_OF_RAM; }
catch (Out_of_caps) { return View_handle_result::OUT_OF_CAPS; }
}
View_capability view_capability(View_handle handle) override

View File

@ -68,11 +68,16 @@ struct Wm::Layouter_gui_session : Genode::Rpc_object<Gui::Session>
void destroy_view(View_handle) override { }
View_handle_result view_handle(View_capability, View_handle) override
Alloc_view_handle_result alloc_view_handle(View_capability) override
{
return View_handle();
}
View_handle_result view_handle(View_capability, View_handle) override
{
return View_handle_result::OK;
}
View_capability view_capability(View_handle) override
{
return View_capability();

View File

@ -222,7 +222,7 @@ void QGenodeViewWidget::paintEvent(QPaintEvent *event)
dynamic_cast<QGenodePlatformWindow*>(window()->windowHandle()->handle());
Gui::Session::View_handle const neighbor_handle =
gui->view_handle(platform_window->view_cap());
gui->alloc_view_handle(platform_window->view_cap());
gui->enqueue<Command::Front_of>(view_handle, neighbor_handle);
gui->execute();

View File

@ -39,8 +39,12 @@ struct Gui::Session_client : Rpc_client<Session>
void destroy_view(View_handle view) override {
call<Rpc_destroy_view>(view); }
View_handle_result view_handle(View_capability view,
View_handle handle = View_handle()) override
Alloc_view_handle_result alloc_view_handle(View_capability view) override
{
return call<Rpc_alloc_view_handle>(view);
}
View_handle_result view_handle(View_capability view, View_handle handle) override
{
return call<Rpc_view_handle>(view, handle);
}

View File

@ -120,18 +120,20 @@ class Gui::Connection : private Genode::Connection<Session>
return _client.view_capability(handle);
}
View_handle view_handle(View_capability view, View_handle handle = { })
View_handle alloc_view_handle(View_capability view)
{
View_handle result { };
for (bool retry = false; ; ) {
using Error = Session_client::View_handle_error;
_client.view_handle(view, handle).with_result(
using Error = Session_client::Alloc_view_handle_error;
_client.alloc_view_handle(view).with_result(
[&] (View_handle handle) { result = handle; },
[&] (Error e) {
switch (e) {
case Error::OUT_OF_RAM: upgrade_ram(8*1024); retry = true; return;
case Error::OUT_OF_CAPS: upgrade_caps(2); retry = true; return;
case Error::INVALID: break;
}
warning("attempt to alloc handle for invalid view");
});
if (!retry)
break;
@ -139,6 +141,21 @@ class Gui::Connection : private Genode::Connection<Session>
return result;
}
void view_handle(View_capability view, View_handle handle)
{
using Result = Session::View_handle_result;
for (;;) {
switch (_client.view_handle(view, handle)) {
case Result::OUT_OF_RAM: upgrade_ram(8*1024); break;
case Result::OUT_OF_CAPS: upgrade_caps(2); break;
case Result::OK: return;
case Result::INVALID:
warning("attempt to create handle for invalid view");
return;
}
}
}
void buffer(Framebuffer::Mode mode, bool use_alpha)
{
size_t const needed = Session_client::ram_quota(mode, use_alpha);

View File

@ -201,20 +201,23 @@ struct Gui::Session : Genode::Session
*/
virtual void destroy_view(View_handle) = 0;
enum class View_handle_error { OUT_OF_RAM, OUT_OF_CAPS };
using View_handle_result = Attempt<View_handle, View_handle_error>;
enum class Alloc_view_handle_error { OUT_OF_RAM, OUT_OF_CAPS, INVALID };
using Alloc_view_handle_result = Attempt<View_handle, Alloc_view_handle_error>;
/**
* Return session-local handle for the specified view
*
* The handle returned by this method can be used to issue commands
* via the 'execute' method.
*
* \param handle designated view handle to be assigned to the imported
* view. By default, a new handle will be allocated.
*/
virtual View_handle_result view_handle(View_capability,
View_handle handle = View_handle()) = 0;
virtual Alloc_view_handle_result alloc_view_handle(View_capability) = 0;
enum class View_handle_result { OK, OUT_OF_RAM, OUT_OF_CAPS, INVALID };
/**
* Associate view with the specified handle
*/
virtual View_handle_result view_handle(View_capability, View_handle) = 0;
/**
* Request view capability for a given handle
@ -293,6 +296,7 @@ struct Gui::Session : Genode::Session
GENODE_RPC(Rpc_create_view, Create_view_result, create_view);
GENODE_RPC(Rpc_create_child_view, Create_child_view_result, create_child_view, View_handle);
GENODE_RPC(Rpc_destroy_view, void, destroy_view, View_handle);
GENODE_RPC(Rpc_alloc_view_handle, Alloc_view_handle_result, alloc_view_handle, View_capability);
GENODE_RPC(Rpc_view_handle, View_handle_result, view_handle, View_capability, View_handle);
GENODE_RPC(Rpc_view_capability, View_capability, view_capability, View_handle);
GENODE_RPC(Rpc_release_view_handle, void, release_view_handle, View_handle);
@ -306,7 +310,8 @@ struct Gui::Session : Genode::Session
GENODE_RPC_INTERFACE(Rpc_framebuffer, Rpc_input,
Rpc_create_view, Rpc_create_child_view, Rpc_destroy_view,
Rpc_view_handle, Rpc_view_capability, Rpc_release_view_handle,
Rpc_alloc_view_handle, Rpc_view_handle,
Rpc_view_capability, Rpc_release_view_handle,
Rpc_command_dataspace, Rpc_execute, Rpc_mode,
Rpc_mode_sigh, Rpc_buffer, Rpc_focus);
};

View File

@ -355,17 +355,35 @@ void Gui_session::destroy_view(View_handle handle)
}
Gui_session::Alloc_view_handle_result
Gui_session::alloc_view_handle(View_capability view_cap)
{
try {
return _env.ep().rpc_ep().apply(view_cap, [&] (View *view_ptr) -> Alloc_view_handle_result {
if (!view_ptr)
return Alloc_view_handle_error::INVALID;
return _view_handle_registry.alloc(*view_ptr); });
}
catch (View_handle_registry::Out_of_memory) { return Alloc_view_handle_error::OUT_OF_RAM; }
catch (Out_of_ram) { return Alloc_view_handle_error::OUT_OF_RAM; }
catch (Out_of_caps) { return Alloc_view_handle_error::OUT_OF_RAM; }
}
Gui_session::View_handle_result
Gui_session::view_handle(View_capability view_cap, View_handle handle)
{
try {
return _env.ep().rpc_ep().apply(view_cap, [&] (View *view) {
return (view) ? _view_handle_registry.alloc(*view, handle)
: View_handle(); });
return _env.ep().rpc_ep().apply(view_cap, [&] (View *view_ptr) -> View_handle_result {
if (!view_ptr)
return View_handle_result::INVALID;
_view_handle_registry.alloc(*view_ptr, handle);
return View_handle_result::OK;
});
}
catch (View_handle_registry::Out_of_memory) { return View_handle_error::OUT_OF_RAM; }
catch (Out_of_ram) { return View_handle_error::OUT_OF_RAM; }
catch (Out_of_caps) { return View_handle_error::OUT_OF_RAM; }
catch (View_handle_registry::Out_of_memory) { return View_handle_result::OUT_OF_RAM; }
catch (Out_of_ram) { return View_handle_result::OUT_OF_RAM; }
catch (Out_of_caps) { return View_handle_result::OUT_OF_RAM; }
}

View File

@ -354,6 +354,8 @@ class Nitpicker::Gui_session : public Session_object<Gui::Session>,
void destroy_view(View_handle handle) override;
Alloc_view_handle_result alloc_view_handle(View_capability view_cap) override;
View_handle_result view_handle(View_capability view_cap, View_handle handle) override;
View_capability view_capability(View_handle handle) override;

View File

@ -114,7 +114,7 @@ struct Test::Child_view : View
View(gui, attr,
[&] /* create_fn */ {
using View_handle = Gui::Session::View_handle;
View_handle const parent_handle = gui.view_handle(parent.view_cap());
View_handle const parent_handle = gui.alloc_view_handle(parent.view_cap());
View_handle const handle = gui.create_child_view(parent_handle);
gui.release_view_handle(parent_handle);
return handle;