genode/repos/base/include/base/local_connection.h

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()];
copy_cstring(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_ */