/* * \brief Capability * \author Norman Feske * \date 2011-05-22 * * A typed capability is a capability tied to one specifiec RPC interface */ /* * Copyright (C) 2011-2013 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #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_client; /** * 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(Ipc_client &ipc_client, ATL &args) const; void _marshal_args(Ipc_client &, Meta::Empty &) const { } /** * Unmarshal single RPC argument from the message buffer */ template void _unmarshal_result(Ipc_client &ipc_client, T &arg, Meta::Overload_selector) const; template void _unmarshal_result(Ipc_client &ipc_client, T &arg, Meta::Overload_selector) const; template void _unmarshal_result(Ipc_client &, T &, Meta::Overload_selector) const { } /** * Read RPC results from the message buffer */ template void _unmarshal_results(Ipc_client &ipc_client, ATL &args) const; void _unmarshal_results(Ipc_client &, 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_BASE - Meta::Length::Value }; if (exc_code == 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 void _call(typename IF::Client_args &args, typename IF::Ret_type &ret) 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; } /** * Wrapper for the return type instantiated by 'call' overloads * * Each 'call' overload creates an instance of the return value * type as local variable. A reference to this variable is passed * to the '_call' method, which will assign its value. Even * though the variable does not need to be initialized prior the * call of '_call', the GCC will still complain "warning: ‘ret’ may * be used uninitialized in this function". Wrapping the return * value in a struct silences the compiler. */ template struct Return { typedef typename Trait::Call_return::Type Return_type; volatile Return_type _value; Return_type &value() { return *(Return_type *)(&_value); } }; 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 Trait::Call_return::Type call() const { Meta::Empty e; Return ret; _call(e, ret.value()); return ret.value(); } template typename Trait::Call_return::Type call(typename Arg::Type v1) const { Meta::Empty e; typename IF::Client_args args(v1, e); Return ret; _call(args, ret.value()); return ret.value(); } template typename Trait::Call_return::Type call(typename Arg::Type v1, typename Arg::Type v2) const { Meta::Empty e; typename IF::Client_args args(v1, v2, e); Return ret; _call(args, ret.value()); return ret.value(); } template typename Trait::Call_return::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 ret; _call(args, ret.value()); return ret.value(); } template typename Trait::Call_return::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 ret; _call(args, ret.value()); return ret.value(); } template typename Trait::Call_return::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 ret; _call(args, ret.value()); return ret.value(); } template typename Trait::Call_return::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 ret; _call(args, ret.value()); return ret.value(); } template typename Trait::Call_return::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 ret; _call(args, ret.value()); return ret.value(); } }; /** * 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_ */