1// vi:set ft=cpp: -*- Mode: C++ -*-
2/*
3 * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
4 *
5 * This file is part of TUD:OS and distributed under the terms of the
6 * GNU General Public License 2.
7 * Please see the COPYING-GPL-2 file for details.
8 *
9 * As a special exception, you may use this file as part of a free software
10 * library without restriction.  Specifically, if other files instantiate
11 * templates or use macros or inline functions from this file, or you compile
12 * this file and link it with other files to produce an executable, this
13 * file does not by itself cause the resulting executable to be covered by
14 * the GNU General Public License.  This exception does not however
15 * invalidate any other reasons why the executable file might be covered by
16 * the GNU General Public License.
17 */
18#pragma once
19
20#include "types"
21#include "ipc_basics"
22
23namespace L4 { namespace Ipc L4_EXPORT {
24
25// ---------------------------------------------------------------
26/**
27 * Dynamically sized output array of type T.
28 * \tparam T  The data-type of each array element.
29 *
30 * Ret_array<> is a special dynamically sized output array
31 * where the number of transmitted elements is passed in
32 * the return value of the call (if positive)
33 */
34template<typename T> struct L4_EXPORT Ret_array
35{
36  typedef T const **ptr_type;
37
38  T *value;
39  unsigned max;
40  Ret_array() {}
41  Ret_array(T *v, unsigned max) : value(v), max(max) {}
42};
43
44namespace Msg {
45
46template<typename A> struct Elem< Ret_array<A> >
47{
48  enum { Is_optional = false };
49  typedef Ret_array<A> type;
50  typedef typename type::ptr_type arg_type;
51  typedef type svr_type;
52  typedef type svr_arg_type;
53};
54
55template<typename A>
56struct Is_valid_rpc_type<Ret_array<A> *> : L4::Types::False {};
57template<typename A>
58struct Is_valid_rpc_type<Ret_array<A> &> : L4::Types::False {};
59template<typename A>
60struct Is_valid_rpc_type<Ret_array<A> const &> : L4::Types::False {};
61template<typename A>
62struct Is_valid_rpc_type<Ret_array<A> const *> : L4::Types::False {};
63
64template<typename A> struct Class< Ret_array<A> > : Class<A>::type {};
65template<typename A> struct Direction< Ret_array<A> > : Dir_out {};
66
67template<typename A, typename CLASS>
68struct Clnt_val_ops<A const *, Dir_out, CLASS> : Clnt_noops<A const *>
69{
70  using Clnt_noops<A const *>::from_msg;
71  static int from_msg(char *msg, unsigned offset, unsigned limit, long ret,
72                      A const *&arg, Dir_out, Cls_data)
73  {
74    offset = align_to<A>(offset);
75    arg = reinterpret_cast<A const *>(msg + offset);
76    if (L4_UNLIKELY(!check_size<A>(offset, limit, ret)))
77      return -1;
78
79    return offset + ret * sizeof(A);
80  }
81};
82
83template<typename A, typename CLASS>
84struct Svr_val_ops<Ret_array<A>, Dir_out, CLASS> :
85  Svr_noops<Ret_array<A> >
86{
87  typedef Ret_array<A> ret_array;
88  using Svr_noops<ret_array>::from_svr;
89  static int from_svr(char *, unsigned offset, unsigned limit, long ret,
90                      ret_array const &, Dir_out, CLASS)
91  {
92    offset = align_to<A>(offset);
93    if (L4_UNLIKELY(!check_size<A>(offset, limit, ret)))
94      return -1;
95    offset += sizeof(A) * ret;
96    return offset;
97  }
98
99  using Svr_noops<ret_array>::to_svr;
100  static int to_svr(char *msg, unsigned offset, unsigned limit,
101                    ret_array &arg, Dir_out, CLASS)
102  {
103    // there can be actually no limit check here, as this
104    // is variably sized output array
105    // FIXME: we could somehow makesure that this is the last
106    //        output value...
107    offset = align_to<A>(offset);
108    arg = ret_array(reinterpret_cast<A*>(msg + offset),
109                    (limit - offset) / sizeof(A));
110    // FIXME: we dont know the length of the array here so, cheat
111    return offset;
112  }
113};
114} // namespace Msg
115
116}}
117