mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
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:
parent
cb8910b40c
commit
0c76bc9cfd
@ -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_ */
|
||||
|
@ -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_ */
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user