genode/repos/base/include/base/local_connection.h
Norman Feske a0fb944721 Propagate session diag flag to core
This commit restores the diag feature for selecting diagnostic output of
services provided by core. This feature became unavailable with commit
"base: remove dependency from deprecated APIs", which hard-wired the
diag flag for core services to false.

To control this feature, three possible policies can be expressed in a
routing target of init's configuration:

* Forcing silence by specifying 'diag="no"'
* Enabling diagnostics by specifying 'diag="yes"'
* Forwarding the preference of the client by omitting the 'diag'
  attribute

Fixes #3962
2020-12-09 14:02:11 +01:00

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, diag,
_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_ */