Add support for specialized session interfaces

This patch introduces principal support for extending session interfaces
with specialized functionality in a clean way. For example, an 'Uart'
interface may implement the 'Terminal' interface but also offers
additional functions for setting the baud rate. A service that
implements the 'Uart' service will then automatically announce both the
'Uart' and 'Terminal' services.
This commit is contained in:
Norman Feske 2012-10-29 12:18:24 +01:00
parent cb8910b40c
commit 0c76bc9cfd
3 changed files with 198 additions and 114 deletions

View File

@ -80,7 +80,8 @@
#define GENODE_RPC_INTERFACE_INHERIT(base, ...) \
typedef ::Genode::Meta::Append<base::Rpc_functions, \
GENODE_TYPE_LIST(__VA_ARGS__) >::Type \
Rpc_functions;
Rpc_functions; \
typedef base Rpc_inherited_interface;
namespace Genode {
@ -282,6 +283,25 @@ namespace Genode {
struct Rpc_interface_msg_size {
typedef typename RPC_IF::Rpc_functions Rpc_functions;
enum { Value = Rpc_function_list_msg_size<Rpc_functions, MSG_TYPE>::Value }; };
/**
* Determine if a RPC interface is inherited
*/
template <typename INTERFACE>
struct Rpc_interface_is_inherited
{
typedef char yes[1];
typedef char no[2];
template <typename IF>
static yes &test(typename IF::Rpc_inherited_interface *);
template <typename>
static no &test(...);
enum { VALUE = sizeof(test<INTERFACE>(0)) == sizeof(yes) };
};
}
#endif /* _INCLUDE__BASE__RPC_H_ */

View File

@ -23,136 +23,195 @@
namespace Genode {
struct Parent
class Parent
{
/*********************
** Exception types **
*********************/
private:
class Exception : public ::Genode::Exception { };
class Service_denied : public Exception { };
class Quota_exceeded : public Exception { };
class Unavailable : public Exception { };
/**
* Recursively announce inherited service interfaces
*
* At compile time, the 'ROOT' type is inspected for the presence
* of the 'Rpc_inherited_interface' type in the corresponding
* session interface. If present, the session type gets announced.
* This works recursively.
*/
template <typename ROOT>
void _announce_base(Capability<ROOT> const &, Meta::Bool_to_type<false> *) { }
typedef Rpc_in_buffer<64> Service_name;
typedef Rpc_in_buffer<160> Session_args;
typedef Rpc_in_buffer<160> Upgrade_args;
/*
* This overload gets selected if the ROOT interface corresponds to
* an inherited session type.
*/
template <typename ROOT>
inline void _announce_base(Capability<ROOT> const &, Meta::Bool_to_type<true> *);
public:
/*********************
** Exception types **
*********************/
class Exception : public ::Genode::Exception { };
class Service_denied : public Exception { };
class Quota_exceeded : public Exception { };
class Unavailable : public Exception { };
typedef Rpc_in_buffer<64> Service_name;
typedef Rpc_in_buffer<160> Session_args;
typedef Rpc_in_buffer<160> Upgrade_args;
virtual ~Parent() { }
virtual ~Parent() { }
/**
* Tell parent to exit the program
*/
virtual void exit(int exit_value) = 0;
/**
* Tell parent to exit the program
*/
virtual void exit(int exit_value) = 0;
/**
* Announce service to the parent
*/
virtual void announce(Service_name const &service_name,
Root_capability service_root) = 0;
/**
* Announce service to the parent
*/
virtual void announce(Service_name const &service_name,
Root_capability service_root) = 0;
/**
* Announce service to the parent
*
* \param service_root root capability
*
* The type of the specified 'service_root' capability match with
* an interface that provides a 'Session_type' type (i.e., a
* 'Typed_root' interface). This 'Session_type' is expected to
* host a static function called 'service_name' returning the
* name of the provided interface as null-terminated string.
*/
template <typename ROOT_INTERFACE>
void announce(Capability<ROOT_INTERFACE> const &service_root)
{
announce(ROOT_INTERFACE::Session_type::service_name(), service_root);
}
/**
* Create session to a service
*
* \param service_name name of the requested interface
* \param args session constructor arguments
*
* \throw Service_denied parent denies session request
* \throw Quota_exceeded our own quota does not suffice for
* the creation of the new session
* \throw Unavailable
*
* \return untyped capability to new session
*
* The use of this function is discouraged. Please use the type safe
* 'session()' template instead.
*/
virtual Session_capability session(Service_name const &service_name,
Session_args const &args) = 0;
/**
* Announce service to the parent
*
* \param service_root root capability
*
* The type of the specified 'service_root' capability match with
* an interface that provides a 'Session_type' type (i.e., a
* 'Typed_root' interface). This 'Session_type' is expected to
* host a static function called 'service_name' returning the
* name of the provided interface as null-terminated string.
*/
template <typename ROOT_INTERFACE>
void announce(Capability<ROOT_INTERFACE> const &service_root)
{
typedef typename ROOT_INTERFACE::Session_type Session;
announce(Session::service_name(), service_root);
/**
* Create session to a service
*
* \param SESSION_TYPE session interface type
* \param args session constructor arguments
*
* \throw Service_denied parent denies session request
* \throw Quota_exceeded our own quota does not suffice for
* the creation of the new session
* \throw Unavailable
*
* \return capability to new session
*/
template <typename SESSION_TYPE>
Capability<SESSION_TYPE> session(Session_args const &args)
{
Session_capability cap = session(SESSION_TYPE::service_name(), args);
return reinterpret_cap_cast<SESSION_TYPE>(cap);
}
/*
* Announce inherited session types
*
* Select the overload based on the presence of the type
* 'Rpc_inherited_interface' within the session type.
*/
_announce_base(service_root,
(Meta::Bool_to_type<Rpc_interface_is_inherited<Session>::VALUE> *)0);
}
/**
* Transfer our quota to the server that provides the specified session
*
* \param to_session recipient session
* \param args description of the amount of quota to transfer
*
* \throw Quota_exceeded quota could not be transferred
*
* The 'args' argument has the same principle format as the 'args'
* argument of the 'session' function.
* The error case indicates that there is not enough unused quota on
* the source side.
*/
virtual void upgrade(Session_capability to_session,
Upgrade_args const &args) = 0;
/**
* Create session to a service
*
* \param service_name name of the requested interface
* \param args session constructor arguments
*
* \throw Service_denied parent denies session request
* \throw Quota_exceeded our own quota does not suffice for
* the creation of the new session
* \throw Unavailable
*
* \return untyped capability to new session
*
* The use of this function is discouraged. Please use the type safe
* 'session()' template instead.
*/
virtual Session_capability session(Service_name const &service_name,
Session_args const &args) = 0;
/**
* Close session
*/
virtual void close(Session_capability session) = 0;
/**
* Create session to a service
*
* \param SESSION_TYPE session interface type
* \param args session constructor arguments
*
* \throw Service_denied parent denies session request
* \throw Quota_exceeded our own quota does not suffice for
* the creation of the new session
* \throw Unavailable
*
* \return capability to new session
*/
template <typename SESSION_TYPE>
Capability<SESSION_TYPE> session(Session_args const &args)
{
Session_capability cap = session(SESSION_TYPE::service_name(), args);
return reinterpret_cap_cast<SESSION_TYPE>(cap);
}
/**
* Provide thread_cap of main thread
*/
virtual Thread_capability main_thread_cap() const = 0;
/**
* Transfer our quota to the server that provides the specified session
*
* \param to_session recipient session
* \param args description of the amount of quota to transfer
*
* \throw Quota_exceeded quota could not be transferred
*
* The 'args' argument has the same principle format as the 'args'
* argument of the 'session' function.
* The error case indicates that there is not enough unused quota on
* the source side.
*/
virtual void upgrade(Session_capability to_session,
Upgrade_args const &args) = 0;
/*********************
** RPC declaration **
*********************/
/**
* Close session
*/
virtual void close(Session_capability session) = 0;
GENODE_RPC(Rpc_exit, void, exit, int);
GENODE_RPC(Rpc_announce, void, announce,
Service_name const &, Root_capability);
GENODE_RPC_THROW(Rpc_session, Session_capability, session,
GENODE_TYPE_LIST(Service_denied, Quota_exceeded, Unavailable),
Service_name const &, Session_args const &);
GENODE_RPC_THROW(Rpc_upgrade, void, upgrade,
GENODE_TYPE_LIST(Quota_exceeded),
Session_capability, Upgrade_args const &);
GENODE_RPC(Rpc_close, void, close, Session_capability);
GENODE_RPC(Rpc_main_thread, Thread_capability, main_thread_cap);
/**
* Provide thread_cap of main thread
*/
virtual Thread_capability main_thread_cap() const = 0;
GENODE_RPC_INTERFACE(Rpc_exit, Rpc_announce, Rpc_session, Rpc_upgrade,
Rpc_close, Rpc_main_thread);
/*********************
** RPC declaration **
*********************/
GENODE_RPC(Rpc_exit, void, exit, int);
GENODE_RPC(Rpc_announce, void, announce,
Service_name const &, Root_capability);
GENODE_RPC_THROW(Rpc_session, Session_capability, session,
GENODE_TYPE_LIST(Service_denied, Quota_exceeded, Unavailable),
Service_name const &, Session_args const &);
GENODE_RPC_THROW(Rpc_upgrade, void, upgrade,
GENODE_TYPE_LIST(Quota_exceeded),
Session_capability, Upgrade_args const &);
GENODE_RPC(Rpc_close, void, close, Session_capability);
GENODE_RPC(Rpc_main_thread, Thread_capability, main_thread_cap);
GENODE_RPC_INTERFACE(Rpc_exit, Rpc_announce, Rpc_session, Rpc_upgrade,
Rpc_close, Rpc_main_thread);
};
}
template <typename ROOT_INTERFACE>
void
Genode::Parent::_announce_base(Genode::Capability<ROOT_INTERFACE> const &service_root,
Genode::Meta::Bool_to_type<true> *)
{
/* shortcut for inherited session type */
typedef typename ROOT_INTERFACE::Session_type::Rpc_inherited_interface
Session_type_inherited;
/* shortcut for root interface type matching the inherited session type */
typedef Typed_root<Session_type_inherited> Root_inherited;
/* convert root capability to match the inherited session type */
Capability<Root> root = service_root;
Capability<Root_inherited> root_inherited = static_cap_cast<Root_inherited>(root);
/* announce inherited service type */
announce(Session_type_inherited::service_name(), root_inherited);
/* recursively announce further inherited session types */
_announce_base(root_inherited,
(Meta::Bool_to_type<Rpc_interface_is_inherited<Session_type_inherited>::VALUE> *)0);
}
#endif /* _INCLUDE__PARENT__PARENT_H_ */

View File

@ -637,6 +637,11 @@ namespace Genode {
Overload_selector() { }
};
/**
* Convert boolean value to type
*/
template <bool VALUE> struct Bool_to_type { enum { V = VALUE }; };
} /* namespace Meta */
}