mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 11:27:29 +00:00
parent
19c13877ca
commit
0288cffaee
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -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 };
|
||||
|
||||
|
@ -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); });
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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))) { }
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user