mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-30 08:03:59 +00:00
81613afa03
Whenever an environment session was provided by an asynchronous service, e.g., the depot_rom of the sculpt scenario, the session quota was not transferred to the server at session-creation time. This resulted in a slow depletion of the server's quota over time. This patch ensures that the delivery of session quota is consistent with the information reported to the server as session argument.
185 lines
5.2 KiB
C++
185 lines
5.2 KiB
C++
/*
|
|
* \brief Connection to a local child
|
|
* \author Norman Feske
|
|
* \date 2016-11-10
|
|
*
|
|
* The 'Local_connection' can be used to locally establish a connection
|
|
* to a 'Local_service' or a 'Parent_service'.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2016-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#ifndef _INCLUDE__BASE__LOCAL_CONNECTION_H_
|
|
#define _INCLUDE__BASE__LOCAL_CONNECTION_H_
|
|
|
|
#include <util/arg_string.h>
|
|
#include <base/service.h>
|
|
|
|
namespace Genode {
|
|
|
|
class Local_connection_base;
|
|
template <typename> class Local_connection;
|
|
}
|
|
|
|
|
|
struct Genode::Local_connection_base : Noncopyable
|
|
{
|
|
public:
|
|
|
|
typedef Session_state::Args Args;
|
|
|
|
protected:
|
|
|
|
Constructible<Session_state> _session_state { };
|
|
|
|
private:
|
|
|
|
static Args _init_args(Args const &args, Session::Resources resources,
|
|
Session::Diag diag)
|
|
{
|
|
/* copy original arguments into modifiable buffer */
|
|
char buf[Args::capacity()];
|
|
strncpy(buf, args.string(), sizeof(buf));
|
|
|
|
Arg_string::set_arg(buf, sizeof(buf), "ram_quota",
|
|
String<64>(resources.ram_quota.value).string());
|
|
Arg_string::set_arg(buf, sizeof(buf), "cap_quota",
|
|
String<64>(resources.cap_quota.value).string());
|
|
Arg_string::set_arg(buf, sizeof(buf), "diag", diag.enabled);
|
|
|
|
/* return result as a copy */
|
|
return Args(Cstring(buf));
|
|
}
|
|
|
|
protected:
|
|
|
|
Local_connection_base(Service &service,
|
|
Id_space<Parent::Client> &id_space,
|
|
Parent::Client::Id id,
|
|
Args const &args, Affinity const &affinity,
|
|
Session::Label const &label,
|
|
Session::Diag diag,
|
|
Session::Resources resources)
|
|
{
|
|
enum { NUM_ATTEMPTS = 10 };
|
|
for (unsigned i = 0; i < NUM_ATTEMPTS; i++) {
|
|
_session_state.construct(service, id_space, id, label,
|
|
_init_args(args, resources, diag),
|
|
affinity);
|
|
|
|
_session_state->service().initiate_request(*_session_state);
|
|
|
|
if (_session_state->alive())
|
|
break;
|
|
|
|
switch (_session_state->phase) {
|
|
|
|
case Session_state::INSUFFICIENT_RAM_QUOTA:
|
|
resources.ram_quota.value += 4096;
|
|
break;
|
|
|
|
case Session_state::INSUFFICIENT_CAP_QUOTA:
|
|
resources.cap_quota.value += 1;
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
if (_session_state->phase == Session_state::INSUFFICIENT_RAM_QUOTA
|
|
|| _session_state->phase == Session_state::INSUFFICIENT_CAP_QUOTA)
|
|
warning("giving up to increase session quota for ", service.name(), " session "
|
|
"after ", (int)NUM_ATTEMPTS, " attempts");
|
|
}
|
|
|
|
void close()
|
|
{
|
|
if (_session_state->alive()) {
|
|
_session_state->phase = Session_state::CLOSE_REQUESTED;
|
|
_session_state->service().initiate_request(*_session_state);
|
|
}
|
|
}
|
|
|
|
~Local_connection_base() { close(); }
|
|
};
|
|
|
|
|
|
template <typename CONNECTION>
|
|
class Genode::Local_connection : Local_connection_base
|
|
{
|
|
private:
|
|
|
|
typedef typename CONNECTION::Session_type SESSION;
|
|
|
|
Constructible <typename SESSION::Client> _client { };
|
|
|
|
public:
|
|
|
|
Capability<SESSION> cap() const
|
|
{
|
|
return reinterpret_cap_cast<SESSION>(_session_state->cap);
|
|
}
|
|
|
|
SESSION &session()
|
|
{
|
|
/*
|
|
* If session comes from a local service (e.g,. a virtualized
|
|
* RAM session, we return the reference to the corresponding
|
|
* component object, which can be called directly.
|
|
*/
|
|
if (_session_state->local_ptr)
|
|
return *static_cast<SESSION *>(_session_state->local_ptr);
|
|
|
|
/*
|
|
* The session is provided remotely. So return a client stub for
|
|
* interacting with the session. We construct the client object if
|
|
* we have a valid session capability.
|
|
*/
|
|
if (!_client.constructed() && _session_state->cap.valid())
|
|
_client.construct(cap());
|
|
|
|
if (_client.constructed())
|
|
return *_client;
|
|
|
|
/*
|
|
* This error is printed if the session could not be
|
|
* established or the session is provided by a child service.
|
|
*/
|
|
error(SESSION::service_name(), " session (", _session_state->args(), ") "
|
|
"unavailable");
|
|
throw Service_denied();
|
|
}
|
|
|
|
SESSION const &session() const
|
|
{
|
|
return const_cast<Local_connection *>(this)->session();
|
|
}
|
|
|
|
Local_connection(Service &service, Id_space<Parent::Client> &id_space,
|
|
Parent::Client::Id id, Args const &args,
|
|
Affinity const &affinity,
|
|
Session::Label const &label = Session_label(),
|
|
Session::Diag diag = { false })
|
|
:
|
|
Local_connection_base(service, id_space, id, args, affinity,
|
|
label.valid() ? label : label_from_args(args.string()),
|
|
diag,
|
|
Session::Resources { Ram_quota { CONNECTION::RAM_QUOTA },
|
|
Cap_quota { CONNECTION::CAP_QUOTA } })
|
|
{
|
|
service.wakeup();
|
|
}
|
|
|
|
bool alive() const { return _session_state->alive(); }
|
|
bool closed() const { return _session_state->closed(); }
|
|
|
|
using Local_connection_base::close;
|
|
};
|
|
|
|
#endif /* _INCLUDE__BASE__LOCAL_CONNECTION_H_ */
|