diff --git a/base/include/base/rpc.h b/base/include/base/rpc.h index 18e1395cf..3b4c05868 100644 --- a/base/include/base/rpc.h +++ b/base/include/base/rpc.h @@ -80,7 +80,8 @@ #define GENODE_RPC_INTERFACE_INHERIT(base, ...) \ typedef ::Genode::Meta::Append::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::Value }; }; + + + /** + * Determine if a RPC interface is inherited + */ + template + struct Rpc_interface_is_inherited + { + typedef char yes[1]; + typedef char no[2]; + + template + static yes &test(typename IF::Rpc_inherited_interface *); + + template + static no &test(...); + + enum { VALUE = sizeof(test(0)) == sizeof(yes) }; + }; } #endif /* _INCLUDE__BASE__RPC_H_ */ diff --git a/base/include/parent/parent.h b/base/include/parent/parent.h index 30160df92..1ce6885da 100644 --- a/base/include/parent/parent.h +++ b/base/include/parent/parent.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 + void _announce_base(Capability const &, Meta::Bool_to_type *) { } - 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 + inline void _announce_base(Capability const &, Meta::Bool_to_type *); + + 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 - void announce(Capability 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 + void announce(Capability 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 - Capability session(Session_args const &args) - { - Session_capability cap = session(SESSION_TYPE::service_name(), args); - return reinterpret_cap_cast(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::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 + Capability session(Session_args const &args) + { + Session_capability cap = session(SESSION_TYPE::service_name(), args); + return reinterpret_cap_cast(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 +void +Genode::Parent::_announce_base(Genode::Capability const &service_root, + Genode::Meta::Bool_to_type *) +{ + /* 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 Root_inherited; + + /* convert root capability to match the inherited session type */ + Capability root = service_root; + Capability root_inherited = static_cap_cast(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::VALUE> *)0); +} + + #endif /* _INCLUDE__PARENT__PARENT_H_ */ diff --git a/base/include/util/meta.h b/base/include/util/meta.h index 14137f5ec..f407667ac 100644 --- a/base/include/util/meta.h +++ b/base/include/util/meta.h @@ -637,6 +637,11 @@ namespace Genode { Overload_selector() { } }; + /** + * Convert boolean value to type + */ + template struct Bool_to_type { enum { V = VALUE }; }; + } /* namespace Meta */ }