/* * \brief Capability * \author Norman Feske * \date 2011-05-22 * * A typed capability is a capability tied to one specifiec RPC interface */ /* * Copyright (C) 2011-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__CAPABILITY_H_ #define _INCLUDE__BASE__CAPABILITY_H_ #include #include #include namespace Genode { /** * Forward declaration needed for internal interfaces of 'Capability' */ class Ipc_unmarshaller; class Msgbuf_base; /** * Capability that is not associated with a specific RPC interface */ typedef Native_capability Untyped_capability; template class Capability; template Capability reinterpret_cap_cast(Untyped_capability const &); template Capability static_cap_cast(Capability); } /** * Capability referring to a specific RPC interface * * \param RPC_INTERFACE class containing the RPC interface declaration */ template class Genode::Capability : public Untyped_capability { private: /** * Insert RPC arguments into the message buffer */ template void _marshal_args(Msgbuf_base &, ATL &args) const; void _marshal_args(Msgbuf_base &, Meta::Empty &) const { } /** * Unmarshal single RPC argument from the message buffer */ template void _unmarshal_result(Ipc_unmarshaller &, T &arg, Meta::Overload_selector) const; template void _unmarshal_result(Ipc_unmarshaller &, T &arg, Meta::Overload_selector) const; template void _unmarshal_result(Ipc_unmarshaller &, T &, Meta::Overload_selector) const { } /** * Read RPC results from the message buffer */ template void _unmarshal_results(Ipc_unmarshaller &, ATL &args) const; void _unmarshal_results(Ipc_unmarshaller &, Meta::Empty &) const { } /** * Check RPC return code for the occurrence of exceptions * * A server-side exception is indicated by a non-zero exception * code. Each exception code corresponds to an entry in the * exception type list specified in the RPC function declaration. * The '_check_for_exception' method template throws the * exception type belonging to the received exception code. */ template void _check_for_exceptions(Rpc_exception_code const exc_code, Meta::Overload_selector) const { enum { EXCEPTION_CODE = Rpc_exception_code::EXCEPTION_BASE - Meta::Length::Value }; if (exc_code.value == EXCEPTION_CODE) throw typename EXC_TL::Head(); _check_for_exceptions(exc_code, Meta::Overload_selector()); } void _check_for_exceptions(Rpc_exception_code const, Meta::Overload_selector) const { } /** * Perform RPC call, arguments passed a as nested 'Ref_tuple' object */ template typename IF::Ret_type _call(typename IF::Client_args &args) const; /** * Shortcut for querying argument types used in 'call' methods */ template struct Arg { typedef typename Meta::Type_at::Type Type; }; template Untyped_capability _check_compatibility(Capability const &cap) const { FROM_RPC_INTERFACE *from = 0; RPC_INTERFACE *to = from; (void)to; return cap; } public: typedef RPC_INTERFACE Rpc_interface; /** * Constructor * * This implicit constructor checks at compile time for the * compatibility of the source and target capability types. The * construction is performed only if the target capability type is * identical to or a base type of the source capability type. */ template Capability(Capability const &cap) : Untyped_capability(_check_compatibility(cap)) { } /** * Default constructor creates invalid capability */ Capability() { } template typename IF::Ret_type call() const { Meta::Empty e; return _call(e); } template typename IF::Ret_type call(typename Arg::Type v1) const { Meta::Empty e; typename IF::Client_args args(v1, e); return _call(args); } template typename IF::Ret_type call(typename Arg::Type v1, typename Arg::Type v2) const { Meta::Empty e; typename IF::Client_args args(v1, v2, e); return _call(args); } template typename IF::Ret_type call(typename Arg::Type v1, typename Arg::Type v2, typename Arg::Type v3) const { Meta::Empty e; typename IF::Client_args args(v1, v2, v3, e); return _call(args); } template typename IF::Ret_type call(typename Arg::Type v1, typename Arg::Type v2, typename Arg::Type v3, typename Arg::Type v4) const { Meta::Empty e; typename IF::Client_args args(v1, v2, v3, v4, e); return _call(args); } template typename IF::Ret_type call(typename Arg::Type v1, typename Arg::Type v2, typename Arg::Type v3, typename Arg::Type v4, typename Arg::Type v5) const { Meta::Empty e; typename IF::Client_args args(v1, v2, v3, v4, v5, e); return _call(args); } template typename IF::Ret_type call(typename Arg::Type v1, typename Arg::Type v2, typename Arg::Type v3, typename Arg::Type v4, typename Arg::Type v5, typename Arg::Type v6) const { Meta::Empty e; typename IF::Client_args args(v1, v2, v3, v4, v5, v6, e); return _call(args); } template typename IF::Ret_type call(typename Arg::Type v1, typename Arg::Type v2, typename Arg::Type v3, typename Arg::Type v4, typename Arg::Type v5, typename Arg::Type v6, typename Arg::Type v7) const { Meta::Empty e; typename IF::Client_args args(v1, v2, v3, v4, v5, v6, v7, e); return _call(args); } }; /** * Convert an untyped capability to a typed capability */ template Genode::Capability Genode::reinterpret_cap_cast(Untyped_capability const &untyped_cap) { /* * The object layout of untyped and typed capabilities is identical. * Hence we can just use it's copy-constructors. */ Untyped_capability *ptr = const_cast(&untyped_cap); return *static_cast*>(ptr); } /** * Convert capability type from an interface base type to an inherited * interface type */ template Genode::Capability Genode::static_cap_cast(Capability cap) { /* check interface compatibility */ (void)static_cast((FROM_RPC_INTERFACE *)0); return reinterpret_cap_cast(cap); } #endif /* _INCLUDE__BASE__CAPABILITY_H_ */