Remove exceptions from 'Parent' interface

Issue #5245
This commit is contained in:
Norman Feske 2024-07-01 13:36:46 +02:00
parent 19c13877ca
commit 0288cffaee
13 changed files with 278 additions and 238 deletions

View File

@ -55,8 +55,8 @@ class Genode::Local_parent : public Expanding_parent_client
** Parent interface **
**********************/
Session_capability session(Client::Id, Service_name const &, Session_args const &,
Affinity const & = Affinity()) override;
Session_result session(Client::Id, Service_name const &, Session_args const &,
Affinity const & = Affinity()) override;
Close_result close(Client::Id) override;
/**

View File

@ -40,11 +40,15 @@ struct Genode::Platform
Local_parent parent { _obtain_parent_cap(), rm, heap };
Pd_session_capability pd_cap =
static_cap_cast<Pd_session>(parent.session_cap(Parent::Env::pd()));
Capability<Pd_session> pd_cap =
parent.session_cap(Parent::Env::pd()).convert<Capability<Pd_session>>(
[&] (Capability<Session> cap) { return static_cap_cast<Pd_session>(cap); },
[&] (Parent::Session_cap_error) { return Capability<Pd_session>(); });
Cpu_session_capability cpu_cap =
static_cap_cast<Cpu_session>(parent.session_cap(Parent::Env::cpu()));
Capability<Cpu_session> cpu_cap =
parent.session_cap(Parent::Env::cpu()).convert<Capability<Cpu_session>>(
[&] (Capability<Session> cap) { return static_cap_cast<Cpu_session>(cap); },
[&] (Parent::Session_cap_error) { return Capability<Cpu_session>(); });
Local_pd_session pd { parent, pd_cap };

View File

@ -58,10 +58,10 @@ bool Region_map_mmap::_dataspace_writeable(Dataspace_capability ds)
** Local_parent **
******************/
Session_capability Local_parent::session(Parent::Client::Id id,
Service_name const &service_name,
Session_args const &args,
Affinity const &affinity)
Parent::Session_result Local_parent::session(Parent::Client::Id id,
Service_name const &service_name,
Session_args const &args,
Affinity const &affinity)
{
if (strcmp(service_name.string(), Rm_session::service_name()) == 0) {
@ -87,7 +87,7 @@ Parent::Close_result Local_parent::close(Client::Id id)
Capability<Rm_session> rm =
static_cap_cast<Rm_session>(local_session.local_session_cap());
destroy(_alloc, Local_capability<Rm_session>::deref(rm));
return CLOSE_DONE;
return Parent::Close_result::DONE;
},
[&] /* missing */ {
return Parent_client::close(id); });

View File

@ -853,9 +853,9 @@ class Genode::Child : protected Rpc_object<Parent>,
void announce(Service_name const &) override;
void session_sigh(Signal_context_capability) override;
Session_capability session(Client::Id, Service_name const &,
Session_args const &, Affinity const &) override;
Session_capability session_cap(Client::Id) override;
Session_result session(Client::Id, Service_name const &,
Session_args const &, Affinity const &) override;
Session_cap_result session_cap(Client::Id) override;
Upgrade_result upgrade(Client::Id, Upgrade_args const &) override;
Close_result close(Client::Id) override;
void exit(int) override;

View File

@ -33,13 +33,13 @@ struct Genode::Parent_client : Rpc_client<Parent>
void session_sigh(Signal_context_capability sigh) override {
call<Rpc_session_sigh>(sigh); }
Session_capability session(Client::Id id,
Service_name const &service,
Session_args const &args,
Affinity const &affinity) override {
Session_result session(Client::Id id,
Service_name const &service,
Session_args const &args,
Affinity const &affinity) override {
return call<Rpc_session>(id, service, args, affinity); }
Session_capability session_cap(Client::Id id) override {
Session_cap_result session_cap(Client::Id id) override {
return call<Rpc_session_cap>(id); }
Upgrade_result upgrade(Client::Id to_session, Upgrade_args const &args) override {

View File

@ -14,7 +14,7 @@
#ifndef _INCLUDE__PARENT__PARENT_H_
#define _INCLUDE__PARENT__PARENT_H_
#include <base/exception.h>
#include <util/attempt.h>
#include <base/rpc.h>
#include <base/rpc_args.h>
#include <base/thread.h>
@ -143,6 +143,16 @@ class Genode::Parent
*/
virtual void session_sigh(Signal_context_capability) = 0;
enum class Session_error {
OUT_OF_RAM, /* session RAM quota exceeds our resources */
OUT_OF_CAPS, /* session CAP quota exceeds our resources */
INSUFFICIENT_RAM_QUOTA, /* RAM donation does not suffice */
INSUFFICIENT_CAP_QUOTA, /* CAP donation does not suffice */
DENIED, /* parent or server denies request */
};
using Session_result = Attempt<Capability<Session>, Session_error>;
/**
* Create session to a service
*
@ -151,39 +161,35 @@ class Genode::Parent
* \param args session constructor arguments
* \param affinity preferred CPU affinity for the session
*
* \throw Service_denied parent denies session request
* \throw Insufficient_cap_quota donated cap quota does not suffice
* \throw Insufficient_ram_quota donated RAM quota does not suffice
* \throw Out_of_caps session CAP quota exceeds our resources
* \throw Out_of_ram session RAM quota exceeds our resources
*
* \return session capability if the new session is immediately
* available, or an invalid capability
* available, or an invalid capability, or an error of
* type 'Session_error'.
*
* If the returned capability is invalid, the request is pending at the
* server. The parent delivers a signal to the handler as registered
* via 'session_sigh' once the server responded to the request. Now the
* session capability can be picked up by calling 'session_cap'.
*/
virtual Session_capability session(Client::Id id,
Service_name const &service_name,
Session_args const &args,
Affinity const &affinity = Affinity()) = 0;
virtual Session_result session(Client::Id id,
Service_name const &service_name,
Session_args const &args,
Affinity const &affinity = Affinity()) = 0;
enum class Session_cap_error { INSUFFICIENT_RAM_QUOTA,
INSUFFICIENT_CAP_QUOTA, DENIED, };
using Session_cap_result = Attempt<Capability<Session>, Session_cap_error>;
/**
* Request session capability
*
* \throw Service_denied
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota
*
* See 'session' for more documentation.
*
* In the exception case, the parent implicitly closes the session.
* In the error case, the parent implicitly closes the session.
*/
virtual Session_capability session_cap(Client::Id id) = 0;
virtual Session_cap_result session_cap(Client::Id id) = 0;
enum Upgrade_result { UPGRADE_DONE, UPGRADE_PENDING };
enum class Upgrade_result { OK, PENDING, OUT_OF_RAM, OUT_OF_CAPS };
/**
* Transfer our quota to the server that provides the specified session
@ -191,16 +197,13 @@ class Genode::Parent
* \param id ID of recipient session
* \param args description of the amount of quota to transfer
*
* \throw Out_of_caps
* \throw Out_of_ram
*
* The 'args' argument has the same principle format as the 'args'
* argument of the 'session' operation.
*/
virtual Upgrade_result upgrade(Client::Id to_session,
Upgrade_args const &args) = 0;
enum [[nodiscard]] Close_result { CLOSE_DONE, CLOSE_PENDING };
enum class [[nodiscard]] Close_result { DONE, PENDING };
/**
* Close session
@ -308,19 +311,11 @@ class Genode::Parent
GENODE_RPC(Rpc_announce, void, announce,
Service_name const &);
GENODE_RPC(Rpc_session_sigh, void, session_sigh, Signal_context_capability);
GENODE_RPC_THROW(Rpc_session, Session_capability, session,
GENODE_TYPE_LIST(Service_denied, Out_of_caps,
Out_of_ram, Insufficient_cap_quota,
Insufficient_ram_quota),
Client::Id, Service_name const &, Session_args const &,
Affinity const &);
GENODE_RPC_THROW(Rpc_session_cap, Session_capability, session_cap,
GENODE_TYPE_LIST(Service_denied, Insufficient_cap_quota,
Insufficient_ram_quota),
Client::Id);
GENODE_RPC_THROW(Rpc_upgrade, Upgrade_result, upgrade,
GENODE_TYPE_LIST(Out_of_ram, Out_of_caps),
Client::Id, Upgrade_args const &);
GENODE_RPC(Rpc_session, Session_result, session,
Client::Id, Service_name const &, Session_args const &,
Affinity const &);
GENODE_RPC(Rpc_session_cap, Session_cap_result, session_cap, Client::Id);
GENODE_RPC(Rpc_upgrade, Upgrade_result, upgrade, Client::Id, Upgrade_args const &);
GENODE_RPC(Rpc_close, Close_result, close, Client::Id);
GENODE_RPC(Rpc_session_response, void, session_response,
Server::Id, Session_response);

View File

@ -113,10 +113,10 @@ class Genode::Expanding_parent_client : public Parent_client
}
}
Session_capability session(Client::Id id,
Service_name const &name,
Session_args const &args,
Affinity const &affinity) override
Session_result session(Client::Id id,
Service_name const &name,
Session_args const &args,
Affinity const &affinity) override
{
return Parent_client::session(id, name, args, affinity);
}
@ -130,39 +130,28 @@ class Genode::Expanding_parent_client : public Parent_client
*/
if (id == Env::pd()) {
resource_request(Resource_args(args.string()));
return UPGRADE_DONE;
return Upgrade_result::OK;
}
/*
* If the upgrade fails, attempt to issue a resource request twice.
*
* If the default fallback for resource-available signals is used,
* the first request will block until the resources are upgraded.
* The second attempt to upgrade will succeed.
*
* If a custom handler is installed, the resource quest will return
* immediately. The second upgrade attempt may fail too if the
* parent handles the resource request asynchronously. In this
* case, we escalate the problem to caller by propagating the
* 'Out_of_ram' or 'Out_of_caps' exception. Now, it is the job of
* the caller to issue (and respond to) a resource request.
* If the upgrade fails, attempt to issue a resource request
*/
Session::Resources const amount = session_resources_from_args(args.string());
using Arg = String<64>;
return retry<Out_of_ram>(
[&] {
return retry<Out_of_caps>(
[&] { return Parent_client::upgrade(id, args); },
[&] {
Arg cap_arg("cap_quota=", amount.cap_quota);
resource_request(Resource_args(cap_arg.string()));
});
},
[&] {
for (;;) {
Upgrade_result const result = Parent_client::upgrade(id, args);
if (result == Upgrade_result::OUT_OF_RAM) {
Arg ram_arg("ram_quota=", amount.ram_quota);
resource_request(Resource_args(ram_arg.string()));
});
}
else if (result == Upgrade_result::OUT_OF_CAPS) {
Arg cap_arg("cap_quota=", amount.cap_quota);
resource_request(Resource_args(cap_arg.string()));
}
else
return result;
}
}
void resource_avail_sigh(Signal_context_capability sigh) override

View File

@ -33,7 +33,9 @@ struct Genode::Platform : Noncopyable
template <typename T> Capability<T> _request(Parent::Client::Id id)
{
return static_cap_cast<T>(parent.session_cap(id));
return parent.session_cap(id).convert<Capability<T>>(
[&] (Capability<Session> cap) { return static_cap_cast<T>(cap); },
[&] (Parent::Session_cap_error) { return Capability<T>(); });
}
Expanding_pd_session_client pd {

View File

@ -92,34 +92,26 @@ void Child::session_sigh(Signal_context_capability sigh)
/**
* Create session-state object for a dynamically created session
*
* \throw Out_of_ram
* \throw Out_of_caps
* \throw Insufficient_cap_quota
* \throw Insufficient_ram_quota
* \throw Service_denied
* If successful, 'fn' is called with a new 'Session_state &' as argument.
*/
Session_state &
create_session(Child_policy::Name const &child_name, Service &service,
Session_label const &label, Session::Diag diag,
Session_state::Factory &factory, Id_space<Parent::Client> &id_space,
Parent::Client::Id id, Session_state::Args const &args,
Affinity const &affinity)
Parent::Session_result
with_new_session(Child_policy::Name const &child_name, Service &service,
Session_label const &label, Session::Diag diag,
Session_state::Factory &factory, Id_space<Parent::Client> &id_space,
Parent::Client::Id id, Session_state::Args const &args,
Affinity const &affinity,
auto const &fn)
{
using Error = Parent::Session_error;
Error session_error = Error::DENIED;
try {
return service.create_session(factory, id_space, id, label, diag, args, affinity); }
catch (Insufficient_ram_quota) {
error(child_name, " requested session with insufficient RAM quota");
throw; }
catch (Insufficient_cap_quota) {
error(child_name, " requested session with insufficient cap quota");
throw; }
catch (Allocator::Out_of_memory) {
error(child_name, " session meta data could not be allocated");
throw Out_of_ram(); }
return fn(service.create_session(factory, id_space, id, label, diag, args, affinity));
}
catch (Insufficient_ram_quota) { session_error = Error::INSUFFICIENT_RAM_QUOTA; }
catch (Insufficient_cap_quota) { session_error = Error::INSUFFICIENT_CAP_QUOTA; }
catch (Out_of_ram) { session_error = Error::OUT_OF_RAM; }
catch (Out_of_caps) { session_error = Error::OUT_OF_CAPS; }
catch (Id_space<Parent::Client>::Conflicting_id) {
error(child_name, " requested conflicting session ID ", id, " "
@ -129,17 +121,27 @@ create_session(Child_policy::Name const &child_name, Service &service,
[&] (Session_state &session) { error("existing session: ", session); },
[&] /* missing */ { });
}
throw Service_denied();
if (session_error == Error::OUT_OF_RAM || session_error == Error::OUT_OF_CAPS)
error(child_name, " session meta data could not be allocated");
if (session_error == Error::INSUFFICIENT_RAM_QUOTA)
error(child_name, " requested session with insufficient RAM quota");
if (session_error == Error::INSUFFICIENT_CAP_QUOTA)
error(child_name, " requested session with insufficient cap quota");
return session_error;
}
Session_capability Child::session(Parent::Client::Id id,
Parent::Service_name const &name,
Parent::Session_args const &args,
Affinity const &affinity)
Parent::Session_result Child::session(Parent::Client::Id id,
Parent::Service_name const &name,
Parent::Session_args const &args,
Affinity const &affinity)
{
if (!name.valid_string() || !args.valid_string() || _pd.closed())
throw Service_denied();
return Session_error::DENIED;
char argbuf[Parent::Session_args::MAX_SIZE];
@ -163,7 +165,7 @@ Session_capability Child::session(Parent::Client::Id id,
size_t const keep_ram_quota = _session_factory.session_costs();
if (ram_quota.value < keep_ram_quota)
throw Insufficient_ram_quota();
return Session_error::INSUFFICIENT_RAM_QUOTA;
/* ram quota to be forwarded to the server */
Ram_quota const forward_ram_quota { ram_quota.value - keep_ram_quota };
@ -171,100 +173,106 @@ Session_capability Child::session(Parent::Client::Id id,
/* adjust the session information as presented to the server */
Arg_string::set_arg(argbuf, sizeof(argbuf), "ram_quota", (int)forward_ram_quota.value);
/* may throw a 'Service_denied' exception */
Child_policy::Route route =
_policy.resolve_session_request(name.string(), label,
session_diag_from_args(argbuf));
Service &service = route.service;
/* propagate diag flag */
Arg_string::set_arg(argbuf, sizeof(argbuf), "diag", route.diag.enabled);
Session_state &session =
create_session(_policy.name(), service, route.label, route.diag,
_session_factory, _id_space, id, argbuf, filtered_affinity);
_policy.session_state_changed();
session.ready_callback = this;
session.closed_callback = this;
try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() };
/* may throw a 'Service_denied' exception */
Child_policy::Route route =
_policy.resolve_session_request(name.string(), label,
session_diag_from_args(argbuf));
Ram_transfer::Remote_account ram_account { pd(), pd_session_cap() };
Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() };
Service &service = route.service;
/* transfer the quota donation from the child's account to ourself */
Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account);
/* propagate diag flag */
Arg_string::set_arg(argbuf, sizeof(argbuf), "diag", route.diag.enabled);
/* transfer session quota from ourself to the service provider */
Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service);
Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, service);
return with_new_session(_policy.name(), service, route.label, route.diag,
_session_factory, _id_space, id, argbuf, filtered_affinity,
/* finish transaction */
ram_donation_from_child.acknowledge();
cap_donation_from_child.acknowledge();
ram_donation_to_service.acknowledge();
cap_donation_to_service.acknowledge();
[&] (Session_state &session) -> Session_result {
_policy.session_state_changed();
session.ready_callback = this;
session.closed_callback = this;
try {
Ram_transfer::Remote_account ref_ram_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Cap_transfer::Remote_account ref_cap_account { _policy.ref_pd(), _policy.ref_pd_cap() };
Ram_transfer::Remote_account ram_account { pd(), pd_session_cap() };
Cap_transfer::Remote_account cap_account { pd(), pd_session_cap() };
/* transfer the quota donation from the child's account to ourself */
Ram_transfer ram_donation_from_child(ram_quota, ram_account, ref_ram_account);
Cap_transfer cap_donation_from_child(cap_quota, cap_account, ref_cap_account);
/* transfer session quota from ourself to the service provider */
Ram_transfer ram_donation_to_service(forward_ram_quota, ref_ram_account, service);
Cap_transfer cap_donation_to_service(cap_quota, ref_cap_account, service);
/* finish transaction */
ram_donation_from_child.acknowledge();
cap_donation_from_child.acknowledge();
ram_donation_to_service.acknowledge();
cap_donation_to_service.acknowledge();
}
/*
* Release session meta data if one of the quota transfers went wrong.
*/
catch (Ram_transfer::Quota_exceeded) {
session.destroy();
return Session_error::OUT_OF_RAM;
}
catch (Cap_transfer::Quota_exceeded) {
session.destroy();
return Session_error::OUT_OF_CAPS;
}
/* try to dispatch session request synchronously */
service.initiate_request(session);
if (session.phase == Session_state::SERVICE_DENIED) {
_revert_quota_and_destroy(session);
return Session_error::DENIED;
}
if (session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) {
_revert_quota_and_destroy(session);
return Session_error::INSUFFICIENT_RAM_QUOTA;
}
if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session);
return Session_error::INSUFFICIENT_CAP_QUOTA;
}
/*
* Copy out the session cap before we are potentially kicking off the
* asynchonous request handling at the server to avoid doule-read
* issues with the session.cap, which will be asynchronously assigned
* by the server side.
*/
Session_capability cap = session.cap;
/* if request was not handled synchronously, kick off async operation */
if (session.phase == Session_state::CREATE_REQUESTED)
service.wakeup();
if (cap.valid())
session.phase = Session_state::CAP_HANDED_OUT;
return cap;
}
);
}
/*
* Release session meta data if one of the quota transfers went wrong.
*/
catch (Ram_transfer::Quota_exceeded) {
session.destroy();
throw Out_of_ram();
}
catch (Cap_transfer::Quota_exceeded) {
session.destroy();
throw Out_of_caps();
}
/* try to dispatch session request synchronously */
service.initiate_request(session);
if (session.phase == Session_state::SERVICE_DENIED) {
_revert_quota_and_destroy(session);
throw Service_denied();
}
if (session.phase == Session_state::INSUFFICIENT_RAM_QUOTA) {
_revert_quota_and_destroy(session);
throw Insufficient_ram_quota();
}
if (session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session);
throw Insufficient_cap_quota();
}
/*
* Copy out the session cap before we are potentially kicking off the
* asynchonous request handling at the server to avoid doule-read
* issues with the session.cap, which will be asynchronously assigned
* by the server side.
*/
Session_capability cap = session.cap;
/* if request was not handled synchronously, kick off async operation */
if (session.phase == Session_state::CREATE_REQUESTED)
service.wakeup();
if (cap.valid())
session.phase = Session_state::CAP_HANDED_OUT;
return cap;
catch (Service_denied) { return Session_error::DENIED; }
}
Session_capability Child::session_cap(Client::Id id)
Parent::Session_cap_result Child::session_cap(Client::Id id)
{
return _id_space.apply<Session_state>(id,
[&] (Session_state &session) -> Session_capability {
[&] (Session_state &session) -> Session_cap_result {
if (session.phase == Session_state::SERVICE_DENIED
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA
@ -280,9 +288,9 @@ Session_capability Child::session_cap(Client::Id id)
_revert_quota_and_destroy(session);
switch (phase) {
case Session_state::SERVICE_DENIED: throw Service_denied();
case Session_state::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota();
case Session_state::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota();
case Session_state::SERVICE_DENIED: return Session_cap_error::DENIED;
case Session_state::INSUFFICIENT_RAM_QUOTA: return Session_cap_error::INSUFFICIENT_RAM_QUOTA;
case Session_state::INSUFFICIENT_CAP_QUOTA: return Session_cap_error::INSUFFICIENT_CAP_QUOTA;
default: break;
}
}
@ -309,14 +317,16 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const
{
if (!args.valid_string()) {
warning("no valid session-upgrade arguments");
return UPGRADE_DONE;
return Upgrade_result::OK;
}
/* ignore suprious request that may arrive after 'close_all_sessions' */
if (_pd.closed())
return UPGRADE_PENDING;
return Upgrade_result::PENDING;
Upgrade_result result = UPGRADE_PENDING;
Upgrade_result result = Upgrade_result::PENDING;
bool session_state_changed = false;
auto upgrade_session = [&] (Session_state &session) {
@ -350,6 +360,7 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const
session.phase = Session_state::UPGRADE_REQUESTED;
session.service().initiate_request(session);
session_state_changed = true;
/* finish transaction */
ram_donation_from_child.acknowledge();
@ -359,25 +370,27 @@ Parent::Upgrade_result Child::upgrade(Client::Id id, Parent::Upgrade_args const
}
catch (Ram_transfer::Quota_exceeded) {
warning(_policy.name(), ": RAM upgrade of ", session.service().name(), " failed");
throw Out_of_ram();
result = Upgrade_result::OUT_OF_RAM;
return;
}
catch (Cap_transfer::Quota_exceeded) {
warning(_policy.name(), ": cap upgrade of ", session.service().name(), " failed");
throw Out_of_caps();
result = Upgrade_result::OUT_OF_CAPS;
return;
}
if (session.phase == Session_state::CAP_HANDED_OUT) {
result = UPGRADE_DONE;
result = Upgrade_result::OK;
_policy.session_state_changed();
return;
}
session.service().wakeup();
};
_id_space.apply<Session_state>(id, upgrade_session, [&] /* missing */ { });
_policy.session_state_changed();
if (session_state_changed)
_policy.session_state_changed();
return result;
}
@ -440,7 +453,7 @@ Child::Close_result Child::_close(Session_state &session)
|| session.phase == Session_state::INSUFFICIENT_RAM_QUOTA
|| session.phase == Session_state::INSUFFICIENT_CAP_QUOTA) {
_revert_quota_and_destroy(session);
return CLOSE_DONE;
return Close_result::DONE;
}
/* close session if alive */
@ -457,14 +470,14 @@ Child::Close_result Child::_close(Session_state &session)
if (session.phase == Session_state::CLOSED) {
_revert_quota_and_destroy(session);
return CLOSE_DONE;
return Close_result::DONE;
}
_policy.session_state_changed();
session.service().wakeup();
return CLOSE_PENDING;
return Close_result::PENDING;
}
@ -472,11 +485,11 @@ Child::Close_result Child::close(Client::Id id)
{
/* refuse to close the child's initial sessions */
if (Parent::Env::session_id(id))
return CLOSE_DONE;
return Close_result::DONE;
return _id_space.apply<Session_state>(id,
[&] (Session_state &session) -> Close_result { return _close(session); },
[&] /* missing */ { return CLOSE_DONE; });
[&] /* missing */ { return Close_result::DONE; });
}
@ -832,7 +845,7 @@ void Child::close_all_sessions()
Close_result const close_result = close(Parent::Client::Id{id_value});
/* break infinte loop if CPU session is provided by a child */
if (close_result != CLOSE_DONE)
if (close_result != Close_result::DONE)
break;
}
@ -887,7 +900,7 @@ void Child::close_all_sessions()
Close_result const close_result = _close(session);
if (close_result == CLOSE_PENDING)
if (close_result == Close_result::PENDING)
session.discard_id_at_client();
};

View File

@ -119,13 +119,36 @@ struct Genode::Component_env : Env
Mutex::Guard guard(_mutex);
Session_capability cap = _parent.session(id, name, args, affinity);
return _parent.session(id, name, args, affinity).convert<Capability<Session>>(
[&] (Capability<Session> cap) -> Capability<Session> {
if (cap.valid())
return cap;
if (cap.valid())
return cap;
_block_for_session();
_block_for_session();
return _parent.session_cap(id);
return _parent.session_cap(id).convert<Capability<Session>>(
[&] (Capability<Session> cap) { return cap; },
[&] (Parent::Session_cap_error const e) -> Capability<Session> {
using Error = Parent::Session_cap_error;
switch (e) {
case Error::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota();
case Error::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota();
case Error::DENIED: break;
}
throw Service_denied(); }
);
},
[&] (Parent::Session_error const e) -> Capability<Session> {
using Error = Parent::Session_error;
switch (e) {
case Error::OUT_OF_RAM: throw Out_of_ram();
case Error::OUT_OF_CAPS: throw Out_of_caps();
case Error::INSUFFICIENT_RAM_QUOTA: throw Insufficient_ram_quota();
case Error::INSUFFICIENT_CAP_QUOTA: throw Insufficient_cap_quota();
case Error::DENIED: break;
}
throw Service_denied();
});
}
Session_capability session(Parent::Service_name const &name,
@ -194,7 +217,7 @@ struct Genode::Component_env : Env
{
Mutex::Guard guard(_mutex);
if (_parent.upgrade(id, args) == Parent::UPGRADE_PENDING)
if (_parent.upgrade(id, args) == Parent::Upgrade_result::PENDING)
_block_for_session();
}
@ -202,7 +225,7 @@ struct Genode::Component_env : Env
{
Mutex::Guard guard(_mutex);
if (_parent.close(id) == Parent::CLOSE_PENDING)
if (_parent.close(id) == Parent::Close_result::PENDING)
_block_for_session();
}

View File

@ -34,8 +34,12 @@ namespace {
{
Log_session_client _client;
static Session_capability _cap(Parent &parent) {
return parent.session_cap(Parent::Env::log()); }
static Session_capability _cap(Parent &parent)
{
return parent.session_cap(Parent::Env::log()).convert<Capability<Session>>(
[&] (Capability<Session> cap) { return cap; },
[&] (Parent::Session_cap_error) { return Capability<Session>(); });
}
Back_end(Parent &parent)
: _client(reinterpret_cap_cast<Log_session>(_cap(parent))) { }

View File

@ -102,18 +102,22 @@ struct Linker::Elf_file : File
Rom_dataspace_capability _rom_dataspace(Name const &name)
{
/* request the linker and binary from the component environment */
Session_capability cap;
Parent::Session_cap_result cap = Parent::Session_cap_error::DENIED;
if (name == binary_name())
cap = env.parent().session_cap(Parent::Env::binary());
if (name == linker_name())
cap = env.parent().session_cap(Parent::Env::linker());
if (cap.valid()) {
Rom_session_client client(reinterpret_cap_cast<Rom_session>(cap));
return client.dataspace();
}
rom_connection.construct(env, name.string());
return rom_connection->dataspace();
return cap.convert<Rom_dataspace_capability>(
[&] (Capability<Session> cap) {
Rom_session_client client(reinterpret_cap_cast<Rom_session>(cap));
return client.dataspace();
},
[&] (Parent::Session_cap_error) {
rom_connection.construct(env, name.string());
return rom_connection->dataspace();
}
);
}
void _allocate_region_within_linker_area(Name const &name)

View File

@ -33,15 +33,21 @@ class Vfs::Log_file_system : public Single_file_system
Genode::Log_session & _log_session(Genode::Env &env)
{
using namespace Genode;
if (_label.valid()) {
_log_connection.construct(env, _label);
return *_log_connection;
} else {
_log_client.construct(
Genode::reinterpret_cap_cast<Genode::Log_session>
(env.parent().session_cap(Genode::Parent::Env::log())));
return *_log_client;
}
_log_client.construct(
env.parent().session_cap(Parent::Env::log())
.convert<Capability<Log_session>>(
[&] (Capability<Session> cap) {
return static_cap_cast<Log_session>(cap); },
[&] (Parent::Session_cap_error) {
return Capability<Log_session>(); }));
return *_log_client;
}
Genode::Log_session &_log;