base/child.h: remove Nonexistent_id_space exception

This exception got introduced as a mere convenience for implementers of
'Child_policy' but required a special case in the base library.
Following the goal of eliminating exceptions from the base system,
this patch removes it by making a server_id_space mandatory.

Issue #5245
This commit is contained in:
Norman Feske 2024-06-11 11:52:16 +02:00
parent 8b0a16d750
commit ef385696f6
10 changed files with 132 additions and 115 deletions

View File

@ -162,14 +162,10 @@ struct Genode::Child_policy
*/ */
virtual void init(Pd_session &, Capability<Pd_session>) { } virtual void init(Pd_session &, Capability<Pd_session>) { }
class Nonexistent_id_space : Exception { };
/** /**
* ID space for sessions provided by the child * ID space for sessions provided by the child
*
* \throw Nonexistent_id_space
*/ */
virtual Id_space<Parent::Server> &server_id_space() { throw Nonexistent_id_space(); } virtual Id_space<Parent::Server> &server_id_space() = 0;
/** /**
* Notification hook invoked each time a session state is modified * Notification hook invoked each time a session state is modified

View File

@ -121,6 +121,8 @@ class Core_child : public Child_policy
Cap_quota const _cap_quota; Cap_quota const _cap_quota;
Ram_quota const _ram_quota; Ram_quota const _ram_quota;
Id_space<Parent::Server> _server_ids { };
Child _child; Child _child;
public: public:
@ -183,6 +185,8 @@ class Core_child : public Child_policy
Pd_session_capability ref_pd_cap() const override { return _core_pd_cap; } Pd_session_capability ref_pd_cap() const override { return _core_pd_cap; }
size_t session_alloc_batch_size() const override { return 128; } size_t session_alloc_batch_size() const override { return 128; }
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
}; };

View File

@ -506,133 +506,127 @@ void Child::session_closed(Session_state &session)
void Child::session_response(Server::Id id, Session_response response) void Child::session_response(Server::Id id, Session_response response)
{ {
try { _policy.server_id_space().apply<Session_state>(id, [&] (Session_state &session) {
_policy.server_id_space().apply<Session_state>(id, [&] (Session_state &session) {
switch (response) { switch (response) {
case Parent::SESSION_CLOSED: case Parent::SESSION_CLOSED:
session.phase = Session_state::CLOSED; session.phase = Session_state::CLOSED;
/*
* If the client exists, reflect the response to the client
* via the 'closed_callback'. If the client has vanished,
* i.e., if the close request was issued by ourself while
* killing a child, we drop the session state immediately.
*/
if (session.closed_callback) {
session.closed_callback->session_closed(session);
} else {
/* /*
* If the client exists, reflect the response to the client * The client no longer exists. So we cannot take the
* via the 'closed_callback'. If the client has vanished, * regular path of executing '_revert_quota_and_destroy' in
* i.e., if the close request was issued by ourself while * the context of the client. Instead, we immediately
* killing a child, we drop the session state immediately. * withdraw the session quota from the server ('this') to
* the reference account, and destroy the session object.
*/ */
if (session.closed_callback) { Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap());
session.closed_callback->session_closed(session); Ram_transfer::Account &service_ram_account = session.service();
} else { Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap());
Cap_transfer::Account &service_cap_account = session.service();
/* try {
* The client no longer exists. So we cannot take the /* transfer session quota from the service to ourself */
* regular path of executing '_revert_quota_and_destroy' in Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
* the context of the client. Instead, we immediately service_ram_account, ref_ram_account);
* withdraw the session quota from the server ('this') to
* the reference account, and destroy the session object.
*/
Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap());
Ram_transfer::Account &service_ram_account = session.service();
Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap()); Cap_transfer cap_donation_from_service(session.donated_cap_quota(),
Cap_transfer::Account &service_cap_account = session.service(); service_cap_account, ref_cap_account);
try { ram_donation_from_service.acknowledge();
/* transfer session quota from the service to ourself */ cap_donation_from_service.acknowledge();
Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
service_ram_account, ref_ram_account);
Cap_transfer cap_donation_from_service(session.donated_cap_quota(),
service_cap_account, ref_cap_account);
ram_donation_from_service.acknowledge();
cap_donation_from_service.acknowledge();
}
catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), " failed to return session RAM quota "
"(", session.donated_ram_quota(), ")"); }
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), " failed to return session cap quota "
"(", session.donated_cap_quota(), ")"); }
session.destroy();
_policy.session_state_changed();
} }
break; catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), " failed to return session RAM quota "
"(", session.donated_ram_quota(), ")"); }
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), " failed to return session cap quota "
"(", session.donated_cap_quota(), ")"); }
case Parent::SERVICE_DENIED: session.destroy();
session.phase = Session_state::SERVICE_DENIED; _policy.session_state_changed();
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::INSUFFICIENT_RAM_QUOTA:
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA;
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::INSUFFICIENT_CAP_QUOTA:
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA;
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::SESSION_OK:
if (session.phase == Session_state::UPGRADE_REQUESTED) {
session.phase = Session_state::CAP_HANDED_OUT;
if (session.ready_callback)
session.ready_callback->session_ready(session);
}
break;
} }
}, break;
[&] /* missing ID */ {
warning("unexpected session response for unknown session"); case Parent::SERVICE_DENIED:
}); session.phase = Session_state::SERVICE_DENIED;
} if (session.ready_callback)
catch (Child_policy::Nonexistent_id_space) { } session.ready_callback->session_ready(session);
break;
case Parent::INSUFFICIENT_RAM_QUOTA:
session.phase = Session_state::INSUFFICIENT_RAM_QUOTA;
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::INSUFFICIENT_CAP_QUOTA:
session.phase = Session_state::INSUFFICIENT_CAP_QUOTA;
if (session.ready_callback)
session.ready_callback->session_ready(session);
break;
case Parent::SESSION_OK:
if (session.phase == Session_state::UPGRADE_REQUESTED) {
session.phase = Session_state::CAP_HANDED_OUT;
if (session.ready_callback)
session.ready_callback->session_ready(session);
}
break;
}
},
[&] /* missing ID */ {
warning("unexpected session response for unknown session");
});
} }
void Child::deliver_session_cap(Server::Id id, Session_capability cap) void Child::deliver_session_cap(Server::Id id, Session_capability cap)
{ {
try { _policy.server_id_space().apply<Session_state>(id, [&] (Session_state &session) {
_policy.server_id_space().apply<Session_state>(id, [&] (Session_state &session) {
/* ignore responses after 'close_all_sessions' of the client */ /* ignore responses after 'close_all_sessions' of the client */
if (session.phase != Session_state::CREATE_REQUESTED) if (session.phase != Session_state::CREATE_REQUESTED)
return; return;
if (session.cap.valid()) { if (session.cap.valid()) {
_error("attempt to assign session cap twice"); _error("attempt to assign session cap twice");
return; return;
} }
/* /*
* If the client vanished during the session creation, the * If the client vanished during the session creation, the
* session-close state change must be reflected to the server * session-close state change must be reflected to the server
* as soon as the session becomes available. This enables the * as soon as the session becomes available. This enables the
* server to wind down the session. If we just discarded the * server to wind down the session. If we just discarded the
* session, the server's ID space would become inconsistent * session, the server's ID space would become inconsistent
* with ours. * with ours.
*/ */
if (!session.client_exists()) { if (!session.client_exists()) {
session.phase = Session_state::CLOSE_REQUESTED; session.phase = Session_state::CLOSE_REQUESTED;
session.service().initiate_request(session); session.service().initiate_request(session);
return; return;
} }
session.cap = cap; session.cap = cap;
session.phase = Session_state::AVAILABLE; session.phase = Session_state::AVAILABLE;
if (session.ready_callback) if (session.ready_callback)
session.ready_callback->session_ready(session); session.ready_callback->session_ready(session);
}, },
[&] /* missing ID */ { }); [&] /* missing ID */ { });
}
catch (Child_policy::Nonexistent_id_space) { }
} }
@ -866,11 +860,8 @@ void Child::close_all_sessions()
* with the server. So the added complexity of reverting the session quotas * with the server. So the added complexity of reverting the session quotas
* would be to no benefit. * would be to no benefit.
*/ */
try { auto lambda = [&] (Session_state &s) { _revert_quota_and_destroy(s); };
auto lambda = [&] (Session_state &s) { _revert_quota_and_destroy(s); }; while (_policy.server_id_space().apply_any<Session_state>(lambda));
while (_policy.server_id_space().apply_any<Session_state>(lambda));
}
catch (Child_policy::Nonexistent_id_space) { }
/* /*
* Issue close requests to the providers of the environment sessions, * Issue close requests to the providers of the environment sessions,

View File

@ -174,6 +174,7 @@ class Test_child_policy : public Child_policy
Env &_env; Env &_env;
Parent_services &_parent_services; Parent_services &_parent_services;
Id_space<Parent::Server> _server_ids { };
Signal_context_capability const _fault_handler_sigh; Signal_context_capability const _fault_handler_sigh;
Signal_context_capability const _fault_handler_stack_sigh; Signal_context_capability const _fault_handler_stack_sigh;
@ -239,6 +240,8 @@ class Test_child_policy : public Child_policy
.label = label, .label = label,
.diag = diag }; .diag = diag };
} }
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
}; };

View File

@ -428,6 +428,8 @@ struct Libc::Forked_child : Child_policy, Child_ready
Local_clone_service _local_clone_service; Local_clone_service _local_clone_service;
Local_rom_service _config_rom_service; Local_rom_service _config_rom_service;
Id_space<Parent::Server> _server_ids { };
pid_t pid() const { return _pid; } pid_t pid() const { return _pid; }
bool running() const { return _state == State::RUNNING; } bool running() const { return _state == State::RUNNING; }
@ -539,6 +541,8 @@ struct Libc::Forked_child : Child_policy, Child_ready
Signal_transmitter(_exit_handler).submit(); Signal_transmitter(_exit_handler).submit();
} }
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
Child _child; Child _child;
Forked_child(Env &env, Forked_child(Env &env,

View File

@ -70,6 +70,8 @@ struct Sequence::Child : Genode::Child_policy
Registry<Parent_service> _parent_services { }; Registry<Parent_service> _parent_services { };
Id_space<Parent::Server> _server_ids { };
/* queue a child reload from the async Parent interface */ /* queue a child reload from the async Parent interface */
Signal_transmitter _exit_transmitter; Signal_transmitter _exit_transmitter;
@ -205,6 +207,8 @@ struct Sequence::Child : Genode::Child_policy
ref_pd().transfer_quota(pd_cap, Cap_quota{_env.pd().avail_caps().value >> 1}); ref_pd().transfer_quota(pd_cap, Cap_quota{_env.pd().avail_caps().value >> 1});
ref_pd().transfer_quota(pd_cap, Ram_quota{_env.pd().avail_ram().value >> 1}); ref_pd().transfer_quota(pd_cap, Ram_quota{_env.pd().avail_ram().value >> 1});
} }
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
}; };

View File

@ -57,6 +57,8 @@ class Shim::Main : public Child_policy
Parent_services _parent_services { }; Parent_services _parent_services { };
Id_space<Parent::Server> _server_ids { };
Child _child { _env.rm(), _env.ep().rpc_ep(), *this }; Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
Service &_matching_service(Service::Name const &name) Service &_matching_service(Service::Name const &name)
@ -125,6 +127,8 @@ class Shim::Main : public Child_policy
label.length()), label.length()),
.diag = diag }; .diag = diag };
} }
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
}; };

View File

@ -37,6 +37,8 @@ class Bomb_child : public Child_policy
Registry<Registered<Parent_service> > &_parent_services; Registry<Registered<Parent_service> > &_parent_services;
Id_space<Parent::Server> _server_ids { };
Child_policy_dynamic_rom_file _config_policy { _env.rm(), "config", _env.ep().rpc_ep(), &_env.ram() }; Child_policy_dynamic_rom_file _config_policy { _env.rm(), "config", _env.ep().rpc_ep(), &_env.ram() };
Child _child { _env.rm(), _env.ep().rpc_ep(), *this }; Child _child { _env.rm(), _env.ep().rpc_ep(), *this };
@ -108,6 +110,8 @@ class Bomb_child : public Child_policy
.label = label, .label = label,
.diag = diag }; .diag = diag };
} }
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
}; };

View File

@ -75,6 +75,7 @@ class Test_child : public Genode::Child_policy
Parent_service _pd_service { _env, Pd_session::service_name() }; Parent_service _pd_service { _env, Pd_session::service_name() };
Parent_service _log_service { _env, Log_session::service_name() }; Parent_service _log_service { _env, Log_session::service_name() };
Parent_service _rom_service { _env, Rom_session::service_name() }; Parent_service _rom_service { _env, Rom_session::service_name() };
Id_space<Parent::Server> _server_ids { };
Child _child; Child _child;
public: public:
@ -134,6 +135,8 @@ class Test_child : public Genode::Child_policy
throw Service_denied(); throw Service_denied();
} }
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
}; };

View File

@ -288,6 +288,8 @@ class Test::Parent
Ram_quota const _ram_quota { 10*1024*1024 }; Ram_quota const _ram_quota { 10*1024*1024 };
Binary_name const _binary_name { "test-resource_yield" }; Binary_name const _binary_name { "test-resource_yield" };
Id_space<Genode::Parent::Server> _server_ids { };
/* /*
* Config ROM service * Config ROM service
*/ */
@ -353,6 +355,8 @@ class Test::Parent
return route(*service_ptr); return route(*service_ptr);
} }
Id_space<Genode::Parent::Server> &server_id_space() override { return _server_ids; }
}; };
Policy _policy { *this, _env }; Policy _policy { *this, _env };