mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-20 08:03:56 +00:00
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:
@ -121,6 +121,8 @@ class Core_child : public Child_policy
|
||||
Cap_quota const _cap_quota;
|
||||
Ram_quota const _ram_quota;
|
||||
|
||||
Id_space<Parent::Server> _server_ids { };
|
||||
|
||||
Child _child;
|
||||
|
||||
public:
|
||||
@ -183,6 +185,8 @@ class Core_child : public Child_policy
|
||||
Pd_session_capability ref_pd_cap() const override { return _core_pd_cap; }
|
||||
|
||||
size_t session_alloc_batch_size() const override { return 128; }
|
||||
|
||||
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -506,133 +506,127 @@ void Child::session_closed(Session_state &session)
|
||||
|
||||
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:
|
||||
session.phase = Session_state::CLOSED;
|
||||
case Parent::SESSION_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
|
||||
* 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.
|
||||
* The client no longer exists. So we cannot take the
|
||||
* regular path of executing '_revert_quota_and_destroy' in
|
||||
* the context of the client. Instead, we immediately
|
||||
* withdraw the session quota from the server ('this') to
|
||||
* the reference account, and destroy the session object.
|
||||
*/
|
||||
if (session.closed_callback) {
|
||||
session.closed_callback->session_closed(session);
|
||||
Ram_transfer::Remote_account ref_ram_account(_policy.ref_pd(), _policy.ref_pd_cap());
|
||||
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();
|
||||
|
||||
/*
|
||||
* The client no longer exists. So we cannot take the
|
||||
* regular path of executing '_revert_quota_and_destroy' in
|
||||
* the context of the client. Instead, we immediately
|
||||
* 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();
|
||||
try {
|
||||
/* transfer session quota from the service to ourself */
|
||||
Ram_transfer ram_donation_from_service(session.donated_ram_quota(),
|
||||
service_ram_account, ref_ram_account);
|
||||
|
||||
Cap_transfer::Remote_account ref_cap_account(_policy.ref_pd(), _policy.ref_pd_cap());
|
||||
Cap_transfer::Account &service_cap_account = session.service();
|
||||
Cap_transfer cap_donation_from_service(session.donated_cap_quota(),
|
||||
service_cap_account, ref_cap_account);
|
||||
|
||||
try {
|
||||
/* transfer session quota from the service to ourself */
|
||||
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();
|
||||
ram_donation_from_service.acknowledge();
|
||||
cap_donation_from_service.acknowledge();
|
||||
}
|
||||
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.phase = Session_state::SERVICE_DENIED;
|
||||
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;
|
||||
session.destroy();
|
||||
_policy.session_state_changed();
|
||||
}
|
||||
},
|
||||
[&] /* missing ID */ {
|
||||
warning("unexpected session response for unknown session");
|
||||
});
|
||||
}
|
||||
catch (Child_policy::Nonexistent_id_space) { }
|
||||
break;
|
||||
|
||||
case Parent::SERVICE_DENIED:
|
||||
session.phase = Session_state::SERVICE_DENIED;
|
||||
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;
|
||||
}
|
||||
},
|
||||
[&] /* missing ID */ {
|
||||
warning("unexpected session response for unknown session");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
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 */
|
||||
if (session.phase != Session_state::CREATE_REQUESTED)
|
||||
return;
|
||||
/* ignore responses after 'close_all_sessions' of the client */
|
||||
if (session.phase != Session_state::CREATE_REQUESTED)
|
||||
return;
|
||||
|
||||
if (session.cap.valid()) {
|
||||
_error("attempt to assign session cap twice");
|
||||
return;
|
||||
}
|
||||
if (session.cap.valid()) {
|
||||
_error("attempt to assign session cap twice");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the client vanished during the session creation, the
|
||||
* session-close state change must be reflected to the server
|
||||
* as soon as the session becomes available. This enables the
|
||||
* server to wind down the session. If we just discarded the
|
||||
* session, the server's ID space would become inconsistent
|
||||
* with ours.
|
||||
*/
|
||||
if (!session.client_exists()) {
|
||||
session.phase = Session_state::CLOSE_REQUESTED;
|
||||
session.service().initiate_request(session);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If the client vanished during the session creation, the
|
||||
* session-close state change must be reflected to the server
|
||||
* as soon as the session becomes available. This enables the
|
||||
* server to wind down the session. If we just discarded the
|
||||
* session, the server's ID space would become inconsistent
|
||||
* with ours.
|
||||
*/
|
||||
if (!session.client_exists()) {
|
||||
session.phase = Session_state::CLOSE_REQUESTED;
|
||||
session.service().initiate_request(session);
|
||||
return;
|
||||
}
|
||||
|
||||
session.cap = cap;
|
||||
session.phase = Session_state::AVAILABLE;
|
||||
session.cap = cap;
|
||||
session.phase = Session_state::AVAILABLE;
|
||||
|
||||
if (session.ready_callback)
|
||||
session.ready_callback->session_ready(session);
|
||||
},
|
||||
[&] /* missing ID */ { });
|
||||
}
|
||||
catch (Child_policy::Nonexistent_id_space) { }
|
||||
if (session.ready_callback)
|
||||
session.ready_callback->session_ready(session);
|
||||
},
|
||||
[&] /* missing ID */ { });
|
||||
}
|
||||
|
||||
|
||||
@ -866,11 +860,8 @@ void Child::close_all_sessions()
|
||||
* with the server. So the added complexity of reverting the session quotas
|
||||
* would be to no benefit.
|
||||
*/
|
||||
try {
|
||||
auto lambda = [&] (Session_state &s) { _revert_quota_and_destroy(s); };
|
||||
while (_policy.server_id_space().apply_any<Session_state>(lambda));
|
||||
}
|
||||
catch (Child_policy::Nonexistent_id_space) { }
|
||||
auto lambda = [&] (Session_state &s) { _revert_quota_and_destroy(s); };
|
||||
while (_policy.server_id_space().apply_any<Session_state>(lambda));
|
||||
|
||||
/*
|
||||
* Issue close requests to the providers of the environment sessions,
|
||||
|
@ -174,6 +174,7 @@ class Test_child_policy : public Child_policy
|
||||
|
||||
Env &_env;
|
||||
Parent_services &_parent_services;
|
||||
Id_space<Parent::Server> _server_ids { };
|
||||
Signal_context_capability const _fault_handler_sigh;
|
||||
Signal_context_capability const _fault_handler_stack_sigh;
|
||||
|
||||
@ -239,6 +240,8 @@ class Test_child_policy : public Child_policy
|
||||
.label = label,
|
||||
.diag = diag };
|
||||
}
|
||||
|
||||
Id_space<Parent::Server> &server_id_space() override { return _server_ids; }
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user