L4Re - L4 Runtime Environment
ipc_array
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 #include "ipc_types"
23 
24 namespace L4 { namespace Ipc L4_EXPORT {
25 
26 /// Default type for passing length of an array.
27 typedef unsigned short Array_len_default;
28 
29 /**
30  * Array reference data type for arrays located in the message.
31  * \note Use Array for normal RPC interfaces, Array_ref is usually used
32  * as server-side argument, see Array.
33  * \tparam ELEM_TYPE The data type of an array element, should be 'const'
34  * when used as input.
35  * \tparam LEN_TYPE Data type used to store the number of elements in
36  * the array.
37  */
38 template< typename ELEM_TYPE, typename LEN_TYPE = Array_len_default >
39 struct Array_ref
40 {
41  typedef ELEM_TYPE *ptr_type;
42  typedef LEN_TYPE len_type;
43 
44  len_type length;
45  ptr_type data;
46  Array_ref() {}
47  Array_ref(len_type length, ptr_type data)
48  : length(length), data(data)
49  {}
50 
51  template<typename X> struct Non_const
52  { typedef Array_ref<X, LEN_TYPE> type; };
53 
54  template<typename X> struct Non_const<X const>
55  { typedef Array_ref<X, LEN_TYPE> type; };
56 
57  Array_ref(typename Non_const<ELEM_TYPE>::type const &other)
58  : length(other.length), data(other.data)
59  {}
60 };
61 
62 /**
63  * Array data type for dynamically sized arrays in RPCs.
64  * \tparam ELEM_TYPE The data type of an array element, should be 'const'
65  * when used as input.
66  * \tparam LEN_TYPE Data type used to store the number of elements in
67  * the array.
68  *
69  * An Array generally encapsulates a data pointer and a length (number of
70  * elements). Array does \em not provide any storage for the data itself.
71  * The storage is either provided by a client-side caller or in the case
72  * of Array_ref is the message itself.
73  *
74  * Arrays can be used as input or as output arguments, when used as input
75  * ELEM_TYPE should be qualified \a const, when used as output a reference
76  * to an array must be used and the ELEM_TYPE must \em not be qualified
77  * \a const. It is the caller's responsibility to provide an array buffer
78  * of sufficient length. If a message from the server is too large it will
79  * be silently truncated.
80  *
81  * If backward compatibility with Ipc::Stream is required, then LEN_TYPE must
82  * be `unsigned long`.
83  */
84 template<typename ELEM_TYPE, typename LEN_TYPE = Array_len_default>
85 struct Array : Array_ref<ELEM_TYPE , LEN_TYPE>
86 {
87  /// Make array
88  Array() {}
89  /// Make array from length and data pointer.
90  Array(LEN_TYPE length, ELEM_TYPE *data)
91  : Array_ref<ELEM_TYPE, LEN_TYPE>(length, data)
92  {}
93 
94  template<typename X> struct Non_const
95  { typedef Array<X, LEN_TYPE> type; };
96 
97  template<typename X> struct Non_const<X const>
98  { typedef Array<X, LEN_TYPE> type; };
99 
100  /// Make a const array from a non-const array
101  Array(typename Non_const<ELEM_TYPE>::type const &other)
102  : Array_ref<ELEM_TYPE, LEN_TYPE>(other.length, other.data)
103  {}
104 };
105 
106 /**
107  * Server-side copy in buffer for Array.
108  * \tparam ELEM_TYPE Data type of an array element.
109  * \tparam LEN_TYPE Data type for the number of elements in the array.
110  * \tparam MAX The maximum number of elements in the buffer.
111  * If the actual message is longer than the buffer, it
112  * will be silently truncated.
113  *
114  * This type is assignment compatible to Array_ref<ELEM_TYPE, LEN_TYPE> and
115  * provides a transparent server-side copy-in mechanism for array parameters.
116  * The Array_in_buf provides the storage for the array data and receives a
117  * copy of the data passed to the server-function.
118  */
119 template< typename ELEM_TYPE,
120  typename LEN_TYPE = Array_len_default,
121  LEN_TYPE MAX = (L4_UTCB_GENERIC_DATA_SIZE *
122  sizeof(l4_umword_t)) / sizeof(ELEM_TYPE) >
123 struct Array_in_buf
124 {
125  typedef Array_ref<ELEM_TYPE, LEN_TYPE> array;
126  typedef Array_ref<ELEM_TYPE const, LEN_TYPE> const_array;
127 
128  /// The data elements
129  ELEM_TYPE data[MAX];
130  /// The length of the array
131  LEN_TYPE length;
132 
133  /// copy in data from a source array
134  void copy_in(const_array a)
135  {
136  length = a.length;
137  if (length > MAX)
138  length = MAX;
139 
140  for (LEN_TYPE i = 0; i < length; ++i)
141  data[i] = a.data[i];
142  }
143 
144  /// Make Array_in_buf from a const array
145  Array_in_buf(const_array a) { copy_in(a); }
146  /// Make Array_in_buf from a non-const array
147  Array_in_buf(array a) { copy_in(a); }
148 };
149 
150 // implementation details for transmission
151 namespace Msg {
152 
153 /// Array as input arguments
154 template<typename A, typename LEN>
155 struct Elem< Array<A, LEN> >
156 {
157  /// Array<> as argument at the interface
158  typedef Array<A, LEN> arg_type;
159  /// Array_ref<> at the server side
160  typedef Array_ref<A, LEN> svr_type;
161  typedef svr_type svr_arg_type;
162  enum { Is_optional = false };
163 };
164 
165 /// Array as output argument
166 template<typename A, typename LEN>
167 struct Elem< Array<A, LEN> & >
168 {
169  /// Array<> & at the interface
170  typedef Array<A, LEN> &arg_type;
171  /// Array_ref<> as server storage type
172  typedef Array_ref<A, LEN> svr_type;
173  /// Array_ref<> & at the server side
174  typedef svr_type &svr_arg_type;
175  enum { Is_optional = false };
176 };
177 
178 /// Array_ref as output argument
179 template<typename A, typename LEN>
180 struct Elem< Array_ref<A, LEN> & >
181 {
182  /// Array_ref<> at the interface
183  typedef Array_ref<A, LEN> &arg_type;
184  /// Array_ref<> as server storage
185  typedef Array_ref<typename L4::Types::Remove_const<A>::type, LEN> svr_type;
186  /// Array_ref<> & as server argument
187  typedef svr_type &svr_arg_type;
188  enum { Is_optional = false };
189 };
190 
191 template<typename A> struct Class<Array<A> > : Class<A>::type {};
192 template<typename A> struct Class<Array_ref<A> > : Class<A>::type {};
193 
194 namespace Detail {
195 
196 template<typename A, typename LEN, typename ARRAY, bool REF>
197 struct Clnt_val_ops_d_in : Clnt_noops<ARRAY>
198 {
199  using Clnt_noops<ARRAY>::to_msg;
200  static int to_msg(char *msg, unsigned offset, unsigned limit,
201  ARRAY a, Dir_in, Cls_data)
202  {
203  offset = align_to<LEN>(offset);
204  if (L4_UNLIKELY(!check_size<LEN>(offset, limit)))
205  return -L4_EMSGTOOLONG;
206  *reinterpret_cast<LEN *>(msg + offset) = a.length;
207  offset = align_to<A>(offset + sizeof(LEN));
208  if (L4_UNLIKELY(!check_size<A>(offset, limit, a.length)))
209  return -L4_EMSGTOOLONG;
210  typedef typename L4::Types::Remove_const<A>::type elem_type;
211  elem_type *data = reinterpret_cast<elem_type*>(msg + offset);
212 
213  // we do not correctly handle overlaps
214  if (!REF || data != a.data)
215  for (LEN i = 0; i < a.length; ++i)
216  data[i] = a.data[i];
217 
218  return offset + a.length * sizeof(A);
219  }
220 };
221 } // namespace Detail
222 
223 template<typename A, typename LEN>
224 struct Clnt_val_ops<Array<A, LEN>, Dir_in, Cls_data> :
225  Detail::Clnt_val_ops_d_in<A, LEN, Array<A, LEN>, false> {};
226 
227 template<typename A, typename LEN>
228 struct Clnt_val_ops<Array_ref<A, LEN>, Dir_in, Cls_data> :
229  Detail::Clnt_val_ops_d_in<A, LEN, Array_ref<A, LEN>, true> {};
230 
231 template<typename A, typename LEN, typename CLASS>
232 struct Svr_val_ops< Array_ref<A, LEN>, Dir_in, CLASS >
233 : Svr_noops< Array_ref<A, LEN> >
234 {
235  typedef Array_ref<A, LEN> svr_type;
236 
237  using Svr_noops<svr_type>::to_svr;
238  static int to_svr(char *msg, unsigned offset, unsigned limit,
239  svr_type &a, Dir_in, Cls_data)
240  {
241  offset = align_to<LEN>(offset);
242  if (L4_UNLIKELY(!check_size<LEN>(offset, limit)))
243  return -L4_EMSGTOOSHORT;
244  a.length = *reinterpret_cast<LEN *>(msg + offset);
245  offset = align_to<A>(offset + sizeof(LEN));
246  if (L4_UNLIKELY(!check_size<A>(offset, limit, a.length)))
247  return -L4_EMSGTOOSHORT;
248  a.data = reinterpret_cast<A*>(msg + offset);
249  return offset + a.length * sizeof(A);
250  }
251 };
252 
253 template<typename A, typename LEN>
254 struct Svr_xmit< Array<A, LEN> > : Svr_xmit< Array_ref<A, LEN> > {};
255 
256 template<typename A, typename LEN>
257 struct Clnt_val_ops<Array<A, LEN>, Dir_out, Cls_data> : Clnt_noops<Array<A, LEN> >
258 {
259  typedef Array<A, LEN> type;
260 
261  using Clnt_noops<type>::from_msg;
262  static int from_msg(char *msg, unsigned offset, unsigned limit, long,
263  type &a, Dir_out, Cls_data)
264  {
265  offset = align_to<LEN>(offset);
266  if (L4_UNLIKELY(!check_size<LEN>(offset, limit)))
267  return -L4_EMSGTOOSHORT;
268 
269  LEN l = *reinterpret_cast<LEN *>(msg + offset);
270 
271  offset = align_to<A>(offset + sizeof(LEN));
272  if (L4_UNLIKELY(!check_size<A>(offset, limit, l)))
273  return -L4_EMSGTOOSHORT;
274 
275  A *data = reinterpret_cast<A*>(msg + offset);
276 
277  if (l > a.length)
278  l = a.length;
279  else
280  a.length = l;
281 
282  for (unsigned i = 0; i < l; ++i)
283  a.data[i] = data[i];
284 
285  return offset + l * sizeof(A);
286  };
287 };
288 
289 template<typename A, typename LEN>
290 struct Clnt_val_ops<Array_ref<A, LEN>, Dir_out, Cls_data> :
291  Clnt_noops<Array_ref<A, LEN> >
292 {
293  typedef Array_ref<A, LEN> type;
294 
295  using Clnt_noops<type>::from_msg;
296  static int from_msg(char *msg, unsigned offset, unsigned limit, long,
297  type &a, Dir_out, Cls_data)
298  {
299  offset = align_to<LEN>(offset);
300  if (L4_UNLIKELY(!check_size<LEN>(offset, limit)))
301  return -L4_EMSGTOOSHORT;
302 
303  LEN l = *reinterpret_cast<LEN *>(msg + offset);
304 
305  offset = align_to<A>(offset + sizeof(LEN));
306  if (L4_UNLIKELY(!check_size<A>(offset, limit, l)))
307  return -L4_EMSGTOOSHORT;
308 
309  a.data = reinterpret_cast<A*>(msg + offset);
310  a.length = l;
311  return offset + l * sizeof(A);
312  };
313 };
314 
315 template<typename A, typename LEN, typename CLASS>
316 struct Svr_val_ops<Array_ref<A, LEN>, Dir_out, CLASS> :
317  Svr_noops<Array_ref<typename L4::Types::Remove_const<A>::type, LEN> &>
318 {
319  typedef typename L4::Types::Remove_const<A>::type elem_type;
320  typedef Array_ref<elem_type, LEN> &svr_type;
321 
322  using Svr_noops<svr_type>::to_svr;
323  static int to_svr(char *msg, unsigned offset, unsigned limit,
324  svr_type a, Dir_out, Cls_data)
325  {
326  offset = align_to<LEN>(offset);
327  if (L4_UNLIKELY(!check_size<LEN>(offset, limit)))
328  return -L4_EMSGTOOLONG;
329 
330  offset = align_to<A>(offset + sizeof(LEN));
331  a.data = reinterpret_cast<elem_type *>(msg + offset);
332  a.length = (limit-offset) / sizeof(A);
333  return offset;
334  }
335 
336  using Svr_noops<svr_type>::from_svr;
337  static int from_svr(char *msg, unsigned offset, unsigned limit, long,
338  svr_type a, Dir_out, Cls_data)
339  {
340  offset = align_to<LEN>(offset);
341  if (L4_UNLIKELY(!check_size<LEN>(offset, limit)))
342  return -L4_EMSGTOOLONG;
343 
344  *reinterpret_cast<LEN *>(msg + offset) = a.length;
345 
346  offset = align_to<A>(offset + sizeof(LEN));
347  if (L4_UNLIKELY(!check_size<A>(offset, limit, a.length)))
348  return -L4_EMSGTOOLONG;
349 
350  return offset + a.length * sizeof(A);
351  }
352 };
353 
354 template<typename A, typename LEN>
355 struct Svr_xmit<Array<A, LEN> &> : Svr_xmit<Array_ref<A, LEN> &> {};
356 
357 // Pointer to array is not implemented.
358 template<typename A, typename LEN>
359 struct Is_valid_rpc_type< Array_ref<A, LEN> *> : L4::Types::False {};
360 
361 // Optional input arrays are not implemented.
362 template<typename A, typename LEN>
363 struct Is_valid_rpc_type< Opt<Array_ref<A, LEN> > > : L4::Types::False {};
364 
365 } // namespace Msg
366 
367 }}