From 6184a276191250054c38af91fdcd4345f8528d06 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Fri, 30 Jun 2017 15:21:29 +0200 Subject: [PATCH] init: defer forwarded session requests when needed This patch changes init's service forwarding such that pending requests are kept unanswered as long as the requested service is not present (yet). In dynamic-init scenarios, this is needed in situtions where the dynamic init is known to eventually provide the service but the internal subsystem is not ready yet. Previously, a client that attempted to request a session in this early phase would get a 'Service_denied' exception. By deferring the forwarding in this situation, the behaviour becomes deterministic. If a matching '' exists but there is no matching policy sub node, the request is answered with 'Service_denied' - as expected. --- repos/os/src/init/server.cc | 26 +++++++++++++++++++++----- repos/os/src/init/server.h | 5 +++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/repos/os/src/init/server.cc b/repos/os/src/init/server.cc index 7a321a326f..5a112e4375 100644 --- a/repos/os/src/init/server.cc +++ b/repos/os/src/init/server.cc @@ -109,7 +109,7 @@ Init::Server::_resolve_session_request(Service::Name const &service_name, matching_service = &service; }); if (!matching_service) - throw Service_denied(); + throw Service_not_present(); return matching_service->resolve_session_request(label); } @@ -169,6 +169,16 @@ void Init::Server::session_closed(Session_state &session) void Init::Server::_handle_create_session_request(Xml_node request, Parent::Client::Id id) { + /* + * Ignore requests that are already successfully forwarded (by a prior call + * of '_handle_create_session_request') but still remain present in the + * 'session_requests' ROM because the server child has not responded yet. + */ + try { + _client_id_space.apply(id, [&] (Parent::Client const &) { }); + return; + } catch (Id_space::Unknown_id) { /* normal case */ } + if (!request.has_sub_node("args")) return; @@ -257,6 +267,7 @@ void Init::Server::_handle_create_session_request(Xml_node request, catch (Insufficient_cap_quota) { _env.parent().session_response(Parent::Server::Id { id.value }, Parent::INSUFFICIENT_CAP_QUOTA); } + catch (Service_not_present) { /* keep request pending */ } } @@ -356,11 +367,15 @@ void Init::Server::apply_config(Xml_node config) _session_request_handler.construct(_env.ep(), *this, &Server::_handle_session_requests); _session_requests->sigh(*_session_request_handler); - - if (_session_requests.constructed()) - _handle_session_requests(); } + /* + * Try to resolve pending session requests that may become serviceable with + * the new configuration. + */ + if (services_provided && _session_requests.constructed()) + _handle_session_requests(); + /* * Re-validate routes of existing sessions, close sessions whose routes * changed. @@ -375,6 +390,7 @@ void Init::Server::apply_config(Xml_node config) if (!route_unchanged) throw Service_denied(); } - catch (Service_denied) { close_session(session); } + catch (Service_denied) { close_session(session); } + catch (Service_not_present) { close_session(session); } }); } diff --git a/repos/os/src/init/server.h b/repos/os/src/init/server.h index ef908bdc57..93b079380a 100644 --- a/repos/os/src/init/server.h +++ b/repos/os/src/init/server.h @@ -51,6 +51,11 @@ class Init::Server : Session_state::Ready_callback, */ Id_space _client_id_space; + /** + * Exception type + */ + class Service_not_present : Exception { }; + /** * Meta data of service provided to our parent */