L4Re - L4 Runtime Environment
ipc_stream
Go to the documentation of this file.
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /**
3  * \file
4  * IPC stream
5  */
6 /*
7  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8  * Alexander Warg <warg@os.inf.tu-dresden.de>,
9  * Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
10  * economic rights: Technische Universit├Ąt Dresden (Germany)
11  *
12  * This file is part of TUD:OS and distributed under the terms of the
13  * GNU General Public License 2.
14  * Please see the COPYING-GPL-2 file for details.
15  *
16  * As a special exception, you may use this file as part of a free software
17  * library without restriction. Specifically, if other files instantiate
18  * templates or use macros or inline functions from this file, or you compile
19  * this file and link it with other files to produce an executable, this
20  * file does not by itself cause the resulting executable to be covered by
21  * the GNU General Public License. This exception does not however
22  * invalidate any other reasons why the executable file might be covered by
23  * the GNU General Public License.
24  */
25 #pragma once
26 
27 #include <l4/sys/ipc.h>
28 #include <l4/sys/capability>
29 #include <l4/sys/cxx/ipc_types>
30 #include <l4/sys/cxx/ipc_varg>
31 #include <l4/cxx/type_traits>
32 #include <l4/cxx/minmax>
33 
34 #define L4_CXX_IPC_BACKWARD_COMPAT
35 
36 namespace L4 {
37 namespace Ipc {
38 
39 class Ostream;
40 class Istream;
41 
42 namespace Internal {
43 /**
44  * Abstraction for inserting an array into an Ipc::Ostream.
45  * \internal
46  *
47  * An object of Buf_cp_out can be used to insert an array of arbitrary values,
48  * that can be inserted into an Ipc::Ostream individually.
49  * The array is therefore copied to the message buffer, in contrast to
50  * data handled with Msg_out_buffer or Msg_io_buffer.
51  *
52  * On insertion into the Ipc::Ostream exactly the given number of elements
53  * of type T are copied to the message buffer, this means the source buffer
54  * is no longer referenced after insertion into the stream.
55  *
56  * You should use buf_cp_out() to create instances of Buf_cp_out.
57  *
58  * The counterpart is either Buf_cp_in (buf_cp_in()) or Buf_in (buf_in()).
59  */
60 template< typename T >
61 class Buf_cp_out
62 {
63 public:
64  /**
65  * Create a buffer object for the given array.
66  *
67  * \param v The pointer to the array with size elements of type T.
68  * \param size The number of elements in the array.
69  */
70  Buf_cp_out(T const *v, unsigned long size) : _v(v), _s(size) {}
71 
72  /**
73  * Get the number of elements in the array.
74  *
75  * \returns The number of elements in the array.
76  *
77  * \note This function is usually used by the Ipc::Ostream itself.
78  */
79  unsigned long size() const { return _s; }
80 
81  /**
82  * Get the pointer to the array.
83  *
84  * \returns Pointer to the array.
85  *
86  * \note This function is usually used by the Ipc::Ostream itself.
87  */
88  T const *buf() const { return _v; }
89 
90 private:
91  friend class Ostream;
92  T const *_v;
93  unsigned long _s;
94 };
95 }
96 
97 /**
98  * Insert an array into an Ipc::Ostream.
99  *
100  * \param v Pointer to the array that shall be inserted into an
101  * Ipc::Ostream.
102  * \param size Number of elements in the array.
103  *
104  * This function inserts an array (e.g. a string) into an Ipc::Ostream.
105  * The data is copied to the stream. On insertion into the Ipc::Ostream
106  * exactly the given number of elements of type T are copied to the message
107  * buffer, this means the source buffer is no longer referenced after
108  * insertion into the stream.
109  *
110  * \see The counterpart is either buf_cp_in() or buf_in().
111  */
112 template< typename T >
113 Internal::Buf_cp_out<T> buf_cp_out(T const *v, unsigned long size)
114 { return Internal::Buf_cp_out<T>(v, size); }
115 
116 
117 namespace Internal {
118 /**
119  * Abstraction for extracting array from an Ipc::Istream.
120  * \internal
121  *
122  * An instance of Buf_cp_in can be used to extract an array from
123  * an Ipc::Istream. This is the counterpart to the Buf_cp_out abstraction.
124  * The data from the received message is thereby copied to the given buffer
125  * and size is set to the number of elements found in the stream.
126  * To avoid the copy operation Buf_in may be used instead.
127  *
128  * \see buf_cp_in(), Buf_in, buf_in(), Buf_cp_out, and buf_cp_out().
129  */
130 template< typename T >
131 class Buf_cp_in
132 {
133 public:
134  /**
135  * Create a buffer for extracting an array from an Ipc::Istream.
136  *
137  * \param v The buffer for array (copy in).
138  * \param[in,out] size Input: the number of elements the array can take at
139  * most <br>
140  * Output: the number of elements found in the stream.
141  */
142  Buf_cp_in(T *v, unsigned long &size) : _v(v), _s(&size) {}
143 
144  unsigned long &size() const { return *_s; }
145  T *buf() const { return _v; }
146 
147 private:
148  friend class Istream;
149  T *_v;
150  unsigned long *_s;
151 };
152 }
153 
154 /**
155  * Extract an array from an Ipc::Istream.
156  *
157  * \param v Pointer to the array that shall receive the values from
158  * the Ipc::Istream.
159  * \param[in,out] size Input: the number of elements the array can take at
160  * most <br>
161  * Output: the number of elements found in the stream.
162  *
163  * buf_cp_in() can be used to extract an array from an Ipc::Istream. This is
164  * the counterpart buf_cp_out(). The data from the received message is
165  * thereby copied to the given buffer and size is set to the number of
166  * elements found in the stream. To avoid the copy operation buf_in() may be
167  * used instead.
168  *
169  * \see buf_in() and buf_cp_out().
170  */
171 template< typename T >
172 Internal::Buf_cp_in<T> buf_cp_in(T *v, unsigned long &size)
173 { return Internal::Buf_cp_in<T>(v, size); }
174 
175 /**
176  * Abstraction for extracting a zero-terminated string from an Ipc::Istream.
177  *
178  * An instance of Str_cp_in can be used to extract a zero-terminated string
179  * an Ipc::Istream. The data from the received message is thereby copied to the
180  * given buffer and size is set to the number of characters found in the
181  * stream. The string is zero terminated in any circumstances. When the given
182  * buffer is smaller than the received string the last byte in the buffer will
183  * be the zero terminator. In the case the received string is shorter than the
184  * given buffer the zero termination will be placed behind the received data.
185  * This provides a zero-terminated result even in cases where the sender did
186  * not provide proper termination or in cases of too small receiver buffers.
187  *
188  * \see str_cp_in().
189  */
190 template< typename T >
191 class Str_cp_in
192 {
193 public:
194  /**
195  * Create a buffer for extracting an array from an Ipc::Istream.
196  *
197  * \param v The buffer for string.
198  * \param[in,out] size Input: The number of bytes available in `v` <br>
199  * Output: The number of bytes received (including the
200  * terminator).
201  */
202  Str_cp_in(T *v, unsigned long &size) : _v(v), _s(&size) {}
203 
204  unsigned long &size() const { return *_s; }
205  T *buf() const { return _v; }
206 
207 private:
208  friend class Istream;
209  T *_v;
210  unsigned long *_s;
211 };
212 
213 /**
214  * Create a Str_cp_in for the given values.
215  *
216  * \param v Pointer to the array that shall receive the values from
217  * the Ipc::Istream.
218  * \param[in,out] size Input: the number of elements the array can take at
219  * most <br>
220  * Output: the number of elements found in the stream.
221  *
222  * This function makes it more convenient to extract arrays from an
223  * Ipc::Istream (\see Str_cp_in.)
224  */
225 template< typename T >
226 Str_cp_in<T> str_cp_in(T *v, unsigned long &size)
227 { return Str_cp_in<T>(v, size); }
228 
229 /**
230  * Pointer to an element of type T in an Ipc::Istream.
231  *
232  * This wrapper can be used to extract an element of type T from an
233  * Ipc::Istream, whereas the data is not copied out, but a pointer into
234  * the message buffer itself is returned. With is mechanism it is possible
235  * to avoid an extra copy of large data structures from a received IPC
236  * message, instead the returned pointer gives direct access to the data
237  * in the message.
238  *
239  * See msg_ptr().
240  */
241 template< typename T >
242 class Msg_ptr
243 {
244 private:
245  T **_p;
246 public:
247  /**
248  * Create a Msg_ptr object that set pointer p to point into the message
249  * buffer.
250  *
251  * \param p The pointer that is adjusted to point into the message buffer.
252  */
253  explicit Msg_ptr(T *&p) : _p(&p) {}
254  void set(T *p) const { *_p = p; }
255 };
256 
257 /**
258  * Create an Msg_ptr to adjust the given pointer.
259  *
260  * This function makes it more convenient to extract pointers to data in the
261  * message buffer itself from an Ipc::Istream. This may be used to avoid copy
262  * out of large data structures. (See Msg_ptr.)
263  */
264 template< typename T >
265 Msg_ptr<T> msg_ptr(T *&p)
266 { return Msg_ptr<T>(p); }
267 
268 
269 namespace Internal {
270 /**
271  * Abstraction to extract an array from an Ipc::Istream.
272  * \internal
273  *
274  * This wrapper provides a possibility to extract an array from an
275  * Ipc::Istream, without extra copy overhead. In contrast to Buf_cp_in
276  * the data is not copied to a buffer, but a pointer to the array is returned.
277  *
278  * The mechanism is comparable to that of Msg_ptr, however it handles arrays
279  * inserted with Buf_cp_out.
280  *
281  * See buf_in(), Buf_cp_out, buf_cp_out(), Buf_cp_in, and buf_cp_in().
282  */
283 template< typename T >
284 class Buf_in
285 {
286 public:
287  /**
288  * Create a Buf_in to adjust a pointer to the array and the size of the array.
289  *
290  * \param v The pointer to adjust to the first element of the array.
291  * \param[out] size The number of elements found in the stream.
292  */
293  Buf_in(T *&v, unsigned long &size) : _v(&v), _s(&size) {}
294 
295  void set_size(unsigned long s) const { *_s = s; }
296  T *&buf() const { return *_v; }
297 
298 private:
299  friend class Istream;
300  T **_v;
301  unsigned long *_s;
302 };
303 }
304 
305 /**
306  * Return a pointer to stream array data.
307  *
308  * \param[out] v Pointer to the array within the Ipc::Istream.
309  * \param[out] size The number of elements found in the stream.
310  *
311  * This routine provdes a possibility to extract an array from an
312  * Ipc::Istream, without extra copy overhead. In contrast to buf_cp_in()
313  * the data is not copied to a buffer, but a pointer to the array is returned.
314  * The user must make sure the UTCB is not used for other purposes while the
315  * returned pointer is still in use.
316  *
317  * The mechanism is comparable to that of Msg_ptr, however it handles arrays
318  * inserted with buf_cp_out().
319  *
320  * \see buf_cp_in() and buf_cp_out().
321  */
322 template< typename T >
323 Internal::Buf_in<T> buf_in(T *&v, unsigned long &size)
324 { return Internal::Buf_in<T>(v, size); }
325 
326 namespace Utcb_stream_check
327 {
328  static bool check_utcb_data_offset(unsigned sz)
329  { return sz > sizeof(l4_umword_t) * L4_UTCB_GENERIC_DATA_SIZE; }
330 }
331 
332 
333 /**
334  * Input stream for IPC unmarshalling.
335  *
336  * Ipc::Istream is part of the dynamic IPC marshalling infrastructure, as well
337  * as Ipc::Ostream and Ipc::Iostream.
338  *
339  * Ipc::Istream is an input stream supporting extraction of values from an
340  * IPC message buffer. A received IPC message can be unmarshalled using the
341  * usual extraction operator (>>).
342  *
343  * There exist some special wrapper classes to extract arrays (see
344  * Ipc_buf_cp_in and Ipc_buf_in) and indirect strings (see Msg_in_buffer and
345  * Msg_io_buffer).
346  */
347 class Istream
348 {
349 public:
350  /**
351  * Create an input stream for the given message buffer.
352  *
353  * The given message buffer is used for IPC operations wait()/receive()
354  * and received data can be extracted using the >> operator afterwards.
355  * In the case of indirect message parts a buffer of type Msg_in_buffer
356  * must be inserted into the stream before the IPC operation and contains
357  * received data afterwards.
358  *
359  * \param utcb The message buffer to receive IPC messages.
360  */
361  Istream(l4_utcb_t *utcb)
362  : _tag(), _utcb(utcb),
363  _current_msg(reinterpret_cast<char*>(l4_utcb_mr_u(utcb)->mr)),
364  _pos(0), _current_buf(0)
365  {}
366 
367  /**
368  * Reset the stream to empty, and ready for receive()/wait().
369  * The stream is reset to the same state as on its creation.
370  */
371  void reset()
372  {
373  _pos = 0;
374  _current_buf = 0;
375  _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
376  }
377 
378  /**
379  * Check whether a value of type T can be obtained from the stream.
380  */
381  template< typename T >
382  bool has_more(unsigned long count = 1)
383  {
384  auto const max_bytes = L4_UTCB_GENERIC_DATA_SIZE * sizeof(l4_umword_t);
385  unsigned apos = cxx::Type_traits<T>::align(_pos);
386  return (count <= max_bytes / sizeof(T))
387  && (apos + (sizeof(T) * count)
388  <= _tag.words() * sizeof(l4_umword_t));
389  }
390 
391  /**
392  * \name Get/Put Functions.
393  */
394  //@{
395 
396  /**
397  * Copy out an array of type `T` with `size` elements.
398  *
399  * \param buf Pointer to a buffer for size elements of type T.
400  * \param elems Number of elements of type T to copy out.
401  *
402  * See \ref Istream::operator>>()
403  */
404  template< typename T >
405  unsigned long get(T *buf, unsigned long elems)
406  {
407  if (L4_UNLIKELY(!has_more<T>(elems)))
408  return 0;
409 
410  unsigned long size = elems * sizeof(T);
411  _pos = cxx::Type_traits<T>::align(_pos);
412 
413  __builtin_memcpy(buf, _current_msg + _pos, size);
414  _pos += size;
415  return elems;
416  }
417 
418 
419  /**
420  * Skip size elements of type T in the stream.
421  * \param elems Number of elements to skip.
422  */
423  template< typename T >
424  void skip(unsigned long elems)
425  {
426  if (L4_UNLIKELY(!has_more<T>(elems)))
427  return;
428 
429  unsigned long size = elems * sizeof(T);
430  _pos = cxx::Type_traits<T>::align(_pos);
431  _pos += size;
432  }
433 
434  /**
435  * Read one size elements of type T from the stream and return a pointer.
436  *
437  * \param buf A Msg_ptr that is actually set to point to the element in the
438  * stream.
439  * \param elems Number of elements to extract (default is 1).
440  *
441  * In contrast to a normal get, this version does actually not copy the data
442  * but returns a pointer to the data.
443  *
444  * See \ref Istream::operator>>()
445  */
446  template< typename T >
447  unsigned long get(Msg_ptr<T> const &buf, unsigned long elems = 1)
448  {
449  if (L4_UNLIKELY(!has_more<T>(elems)))
450  return 0;
451 
452  unsigned long size = elems * sizeof(T);
453  _pos = cxx::Type_traits<T>::align(_pos);
454 
455  buf.set(reinterpret_cast<T*>(_current_msg + _pos));
456  _pos += size;
457  return elems;
458  }
459 
460 
461  /**
462  * Extract a single element of type T from the stream.
463  *
464  * \param[out] v The element.
465  *
466  * See \ref Istream::operator>>()
467  */
468  template< typename T >
469  bool get(T &v)
470  {
471  if (L4_UNLIKELY(!has_more<T>()))
472  {
473  v = T();
474  return false;
475  }
476 
477  _pos = cxx::Type_traits<T>::align(_pos);
478  v = *(reinterpret_cast<T*>(_current_msg + _pos));
479  _pos += sizeof(T);
480  return true;
481  }
482 
483 
484  bool get(Ipc::Varg *va)
485  {
486  Ipc::Varg::Tag t;
487  if (!has_more<Ipc::Varg::Tag>())
488  {
489  va->tag(0);
490  return 0;
491  }
492  get(t);
493  va->tag(t);
494  char const *d;
495  get(msg_ptr(d), va->length());
496  va->data(d);
497 
498  return 1;
499  }
500 
501  /**
502  * Get the message tag of a received IPC.
503  *
504  * \return The L4 message tag for the received IPC.
505  *
506  * This is in particular useful for handling page faults or exceptions.
507  *
508  * See \ref Istream::operator>>()
509  */
510  l4_msgtag_t tag() const { return _tag; }
511 
512 
513  /**
514  * Get the message tag of a received IPC.
515  *
516  * \return A reference to the L4 message tag for the received IPC.
517  *
518  * This is in particular useful for handling page faults or exceptions.
519  *
520  * See \ref Istream::operator>>()
521  */
522  l4_msgtag_t &tag() { return _tag; }
523 
524  //@}
525 
526  /**
527  * \internal
528  * Put a receive item into the stream's buffer registers.
529  */
530  inline bool put(Buf_item const &);
531 
532  /**
533  * \internal
534  * Put a small receive item into the stream's buffer registers.
535  */
536  inline bool put(Small_buf const &);
537 
538 
539  /**
540  * \name IPC operations.
541  */
542  //@{
543 
544  /**
545  * Wait for an incoming message from any sender.
546  *
547  * \param[out] src Contains the sender after a successful IPC operation.
548  *
549  * \return Syscall return tag.
550  *
551  * This wait is actually known as 'open wait'.
552  */
553  inline l4_msgtag_t wait(l4_umword_t *src)
554  { return wait(src, L4_IPC_NEVER); }
555 
556  /**
557  * Wait for an incoming message from any sender.
558  *
559  * \param[out] src Contains the sender after a successful IPC operation.
560  * \param timeout Timeout used for IPC.
561  *
562  * \return The IPC result dope (l4_msgtag_t).
563  *
564  * This wait is actually known as 'open wait'.
565  */
566  inline l4_msgtag_t wait(l4_umword_t *src, l4_timeout_t timeout);
567 
568  /**
569  * Wait for a message from the specified sender.
570  *
571  * \param src The sender id to receive from.
572  *
573  * \return The IPC result dope (l4_msgtag_t).
574  *
575  * This is commonly known as 'closed wait'.
576  */
577  inline l4_msgtag_t receive(l4_cap_idx_t src)
578  { return receive(src, L4_IPC_NEVER); }
579  inline l4_msgtag_t receive(l4_cap_idx_t src, l4_timeout_t timeout);
580 
581  //@}
582 
583  /**
584  * Return utcb pointer.
585  */
586  inline l4_utcb_t *utcb() const { return _utcb; }
587 
588 protected:
589  l4_msgtag_t _tag;
590  l4_utcb_t *_utcb;
591  char *_current_msg;
592  unsigned _pos;
593  unsigned char _current_buf;
594 };
595 
596 class Istream_copy : public Istream
597 {
598 private:
599  l4_msg_regs_t _mrs;
600 
601 public:
602  Istream_copy(Istream const &o) : Istream(o), _mrs(*l4_utcb_mr_u(o.utcb()))
603  {
604  // do some reverse mr to utcb trickery
605  _utcb = (l4_utcb_t *)((l4_addr_t)&_mrs - (l4_addr_t)l4_utcb_mr_u((l4_utcb_t *)0));
606  _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
607  }
608 
609 };
610 
611 /**
612  * Output stream for IPC marshalling.
613  *
614  * Ipc::Ostream is part of the dynamic IPC marshalling infrastructure, as well
615  * as Ipc::Istream and Ipc::Iostream.
616  *
617  * Ipc::Ostream is an output stream supporting insertion of values into an
618  * IPC message buffer. A IPC message can be marshalled using the
619  * usual insertion operator <<, see \link ipc_stream IPC stream operators
620  * \endlink.
621  *
622  * There exist some special wrapper classes to insert arrays (see
623  * Ipc::Buf_cp_out) and indirect strings (see Msg_out_buffer and
624  * Msg_io_buffer). */
625 class Ostream
626 {
627 public:
628  /**
629  * Create an IPC output stream using the given message buffer `utcb`.
630  */
631  Ostream(l4_utcb_t *utcb)
632  : _tag(), _utcb(utcb),
633  _current_msg(reinterpret_cast<char *>(l4_utcb_mr_u(_utcb)->mr)),
634  _pos(0), _current_item(0)
635  {}
636 
637  /**
638  * Reset the stream to empty, same state as a newly created stream.
639  */
640  void reset()
641  {
642  _pos = 0;
643  _current_item = 0;
644  _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
645  }
646 
647  /**
648  * \name Get/Put functions.
649  *
650  * These functions are basically used to implement the insertion operators
651  * (<<) and should not be called directly.
652  */
653  //@{
654 
655  /**
656  * Put an array with `size` elements of type `T` into the stream.
657  *
658  * \param buf A pointer to the array to insert into the buffer.
659  * \param size The number of elements in the array.
660  */
661  template< typename T >
662  bool put(T *buf, unsigned long size)
663  {
664  size *= sizeof(T);
665  _pos = cxx::Type_traits<T>::align(_pos);
666  if (Utcb_stream_check::check_utcb_data_offset(_pos + size))
667  return false;
668 
669  __builtin_memcpy(_current_msg + _pos, buf, size);
670  _pos += size;
671  return true;
672  }
673 
674  /**
675  * Insert an element of type `T` into the stream.
676  *
677  * \param v The element to insert.
678  */
679  template< typename T >
680  bool put(T const &v)
681  {
682  _pos = cxx::Type_traits<T>::align(_pos);
683  if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T)))
684  return false;
685 
686  *(reinterpret_cast<T*>(_current_msg + _pos)) = v;
687  _pos += sizeof(T);
688  return true;
689  }
690 
691  int put(Varg const &va)
692  {
693  put(va.tag());
694  put(va.data(), va.length());
695 
696  return 0;
697  }
698 
699  template< typename T >
700  int put(Varg_t<T> const &va)
701  { return put(static_cast<Varg const &>(va)); }
702 
703  /**
704  * Extract the L4 message tag from the stream.
705  *
706  * \return the extracted L4 message tag.
707  */
708  l4_msgtag_t tag() const { return _tag; }
709 
710  /**
711  * Extract a reference to the L4 message tag from the stream.
712  *
713  * \return A reference to the L4 message tag.
714  */
715  l4_msgtag_t &tag() { return _tag; }
716 
717  //@}
718 
719  /**
720  * \internal
721  * Put a send item into the stream's message buffer.
722  */
723  inline bool put_snd_item(Snd_item const &);
724 
725 
726  /**
727  * \name IPC operations.
728  */
729  //@{
730 
731  /**
732  * Send the message via IPC to the given receiver.
733  *
734  * \param dst The destination for the message.
735  * \param proto Protocol to use.
736  * \param flags Flags to use.
737  *
738  * \return Syscall return tag.
739  */
740  inline l4_msgtag_t send(l4_cap_idx_t dst, long proto = 0, unsigned flags = 0);
741 
742  //@}
743 
744  /**
745  * Return utcb pointer.
746  */
747  inline l4_utcb_t *utcb() const { return _utcb; }
748 #if 0
749  /**
750  * Get the currently used bytes in the stream.
751  */
752  unsigned long tell() const
753  {
754  unsigned w = (_pos + sizeof(l4_umword_t)-1) / sizeof(l4_umword_t);
755  w -= _current_item * 2;
756  _tag = l4_msgtag(0, w, _current_item, 0);
757  }
758 #endif
759 public:
760  l4_msgtag_t prepare_ipc(long proto = 0, unsigned flags = 0)
761  {
762  unsigned w = (_pos + sizeof(l4_umword_t) - 1) / sizeof(l4_umword_t);
763  w -= _current_item * 2;
764  return l4_msgtag(proto, w, _current_item, flags);
765  }
766 
767  // XXX: this is a hack for <l4/sys/cxx/ipc_server> adaption
768  void set_ipc_params(l4_msgtag_t tag)
769  {
770  _pos = (tag.words() + tag.items() * 2) * sizeof(l4_umword_t);
771  _current_item = tag.items();
772  }
773 protected:
774  l4_msgtag_t _tag;
775  l4_utcb_t *_utcb;
776  char *_current_msg;
777  unsigned _pos;
778  unsigned char _current_item;
779 };
780 
781 
782 /**
783  * Input/Output stream for IPC [un]marshalling.
784  *
785  * The Ipc::Iostream is part of the AW Env IPC framework as well as
786  * Ipc::Istream and Ipc::Ostream.
787  * In particular an Ipc::Iostream is a combination of an Ipc::Istream and an
788  * Ipc::Ostream. It can use either a single message buffer for receiving and
789  * sending messages or a pair of a receive and a send buffer. The stream also
790  * supports combined IPC operations such as call() and reply_and_wait(), which
791  * can be used to implement RPC functionality.
792  */
793 class Iostream : public Istream, public Ostream
794 {
795 public:
796 
797  /**
798  * Create an IPC IO stream with a single message buffer.
799  *
800  * \param utcb The message buffer used as backing store.
801  *
802  * The created IO stream uses the same message buffer for sending and
803  * receiving IPC messages.
804  */
805  explicit Iostream(l4_utcb_t *utcb)
806  : Istream(utcb), Ostream(utcb)
807  {}
808 
809  // disambiguate those functions
810  l4_msgtag_t tag() const { return Istream::tag(); }
811  l4_msgtag_t &tag() { return Istream::tag(); }
812  l4_utcb_t *utcb() const { return Istream::utcb(); }
813 
814  /**
815  * Reset the stream to its initial state.
816  *
817  * Input as well as the output stream are reset.
818  */
819  void reset()
820  {
821  Istream::reset();
822  Ostream::reset();
823  }
824 
825 
826  /**
827  * \name Get/Put functions.
828  *
829  * These functions are basically used to implement the insertion operators
830  * (<<) and should not be called directly.
831  */
832  //@{
833 
834  using Istream::get;
835  using Istream::put;
836  using Ostream::put;
837 
838  //@}
839 
840  /**
841  * \name IPC operations.
842  */
843  //@{
844 
845  /**
846  * Do an IPC call using the message in the output stream and receiving to
847  * the input stream.
848  *
849  * \param dst The destination L4 UID (thread) to call.
850  * \param timeout The IPC timeout for the call.
851  * \param proto The protocol value to use in the message tag.
852  *
853  * \return The result dope of the IPC operation.
854  *
855  * This is a combined IPC operation consisting of a send and a receive
856  * to/from the given destination `dst`.
857  *
858  * A call is usually used by clients for RPCs to a server.
859  */
860  inline l4_msgtag_t call(l4_cap_idx_t dst, l4_timeout_t timeout, long proto = 0);
861  inline l4_msgtag_t call(l4_cap_idx_t dst, long proto = 0);
862 
863  /**
864  * Do an IPC reply and wait.
865  *
866  * \param[in,out] src_dst Input: the destination for the send operation. <br>
867  * Output: the source of the received message.
868  * \param proto Protocol to use.
869  *
870  * \return the result dope of the IPC operation.
871  *
872  * This is a combined IPC operation consisting of a send operation and
873  * an open wait for any message.
874  *
875  * A reply and wait is usually used by servers that reply to a client
876  * and wait for the next request by any other client.
877  */
878  inline l4_msgtag_t reply_and_wait(l4_umword_t *src_dst, long proto = 0)
879  { return reply_and_wait(src_dst, L4_IPC_SEND_TIMEOUT_0, proto); }
880 
881  inline l4_msgtag_t send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
882  long proto = 0)
883  { return send_and_wait(dest, src, L4_IPC_SEND_TIMEOUT_0, proto); }
884 
885  /**
886  * Do an IPC reply and wait.
887  *
888  * \param[in,out] src_dst Input: the destination for the send operation. <br>
889  * Output: the source of the received message.
890  * \param timeout Timeout used for IPC.
891  * \param proto Protocol to use.
892  *
893  * \return the result dope of the IPC operation.
894  *
895  * This is a combined IPC operation consisting of a send operation and
896  * an open wait for any message.
897  *
898  * A reply and wait is usually used by servers that reply to a client
899  * and wait for the next request by any other client.
900  */
901  inline l4_msgtag_t reply_and_wait(l4_umword_t *src_dst,
902  l4_timeout_t timeout, long proto = 0);
903  inline l4_msgtag_t send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
904  l4_timeout_t timeout, long proto = 0);
905  inline l4_msgtag_t reply(l4_timeout_t timeout, long proto = 0);
906  inline l4_msgtag_t reply(long proto = 0)
907  { return reply(L4_IPC_SEND_TIMEOUT_0, proto); }
908 
909  //@}
910 };
911 
912 
913 inline bool
914 Ostream::put_snd_item(Snd_item const &v)
915 {
916  typedef Snd_item T;
917  _pos = cxx::Type_traits<Snd_item>::align(_pos);
918  if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T)))
919  return false;
920 
921  *(reinterpret_cast<T*>(_current_msg + _pos)) = v;
922  _pos += sizeof(T);
923  ++_current_item;
924  return true;
925 }
926 
927 
928 inline bool
929 Istream::put(Buf_item const &item)
930 {
931  if (_current_buf >= L4_UTCB_GENERIC_BUFFERS_SIZE - 3)
932  return false;
933 
934  l4_utcb_br_u(_utcb)->bdr &= ~L4_BDR_OFFSET_MASK;
935 
936  reinterpret_cast<Buf_item&>(l4_utcb_br_u(_utcb)->br[_current_buf]) = item;
937  _current_buf += 2;
938  return true;
939 }
940 
941 
942 inline bool
943 Istream::put(Small_buf const &item)
944 {
945  if (_current_buf >= L4_UTCB_GENERIC_BUFFERS_SIZE - 2)
946  return false;
947 
948  l4_utcb_br_u(_utcb)->bdr &= ~L4_BDR_OFFSET_MASK;
949 
950  reinterpret_cast<Small_buf&>(l4_utcb_br_u(_utcb)->br[_current_buf]) = item;
951  _current_buf += 1;
952  return true;
953 }
954 
955 
956 inline l4_msgtag_t
957 Ostream::send(l4_cap_idx_t dst, long proto, unsigned flags)
958 {
959  l4_msgtag_t tag = prepare_ipc(proto, L4_MSGTAG_FLAGS & flags);
960  return l4_ipc_send(dst, _utcb, tag, L4_IPC_NEVER);
961 }
962 
963 inline l4_msgtag_t
964 Iostream::call(l4_cap_idx_t dst, l4_timeout_t timeout, long label)
965 {
966  l4_msgtag_t tag = prepare_ipc(label);
967  tag = l4_ipc_call(dst, Ostream::_utcb, tag, timeout);
968  Istream::tag() = tag;
969  Istream::_pos = 0;
970  return tag;
971 }
972 
973 inline l4_msgtag_t
974 Iostream::call(l4_cap_idx_t dst, long label)
975 { return call(dst, L4_IPC_NEVER, label); }
976 
977 
978 inline l4_msgtag_t
979 Iostream::reply_and_wait(l4_umword_t *src_dst, l4_timeout_t timeout, long proto)
980 {
981  l4_msgtag_t tag = prepare_ipc(proto);
982  tag = l4_ipc_reply_and_wait(Ostream::_utcb, tag, src_dst, timeout);
983  Istream::tag() = tag;
984  Istream::_pos = 0;
985  return tag;
986 }
987 
988 
989 inline l4_msgtag_t
990 Iostream::send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
991  l4_timeout_t timeout, long proto)
992 {
993  l4_msgtag_t tag = prepare_ipc(proto);
994  tag = l4_ipc_send_and_wait(dest, Ostream::_utcb, tag, src, timeout);
995  Istream::tag() = tag;
996  Istream::_pos = 0;
997  return tag;
998 }
999 
1000 inline l4_msgtag_t
1001 Iostream::reply(l4_timeout_t timeout, long proto)
1002 {
1003  l4_msgtag_t tag = prepare_ipc(proto);
1004  tag = l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, Ostream::_utcb, tag, timeout);
1005  Istream::tag() = tag;
1006  Istream::_pos = 0;
1007  return tag;
1008 }
1009 
1010 inline l4_msgtag_t
1011 Istream::wait(l4_umword_t *src, l4_timeout_t timeout)
1012 {
1013  l4_msgtag_t res;
1014  res = l4_ipc_wait(_utcb, src, timeout);
1015  tag() = res;
1016  _pos = 0;
1017  return res;
1018 }
1019 
1020 
1021 inline l4_msgtag_t
1022 Istream::receive(l4_cap_idx_t src, l4_timeout_t timeout)
1023 {
1024  l4_msgtag_t res;
1025  res = l4_ipc_receive(src, _utcb, timeout);
1026  tag() = res;
1027  _pos = 0;
1028  return res;
1029 }
1030 
1031 } // namespace Ipc
1032 } // namespace L4
1033 
1034 /**
1035  * Extract one element of type `T` from the stream `s`.
1036  *
1037  * \param s The stream to extract from.
1038  * \param[out] v Extracted value.
1039  *
1040  * \return The stream `s`.
1041  */
1042 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, bool &v) { s.get(v); return s; }
1043 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, int &v) { s.get(v); return s; }
1044 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, long int &v) { s.get(v); return s; }
1045 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, long long int &v) { s.get(v); return s; }
1046 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned int &v) { s.get(v); return s; }
1047 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned long int &v) { s.get(v); return s; }
1048 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned long long int &v) { s.get(v); return s; }
1049 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, short int &v) { s.get(v); return s; }
1050 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned short int &v) { s.get(v); return s; }
1051 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, char &v) { s.get(v); return s; }
1052 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned char &v) { s.get(v); return s; }
1053 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, signed char &v) { s.get(v); return s; }
1054 inline L4::Ipc::Istream &operator << (L4::Ipc::Istream &s, L4::Ipc::Buf_item const &v) { s.put(v); return s; }
1055 inline L4::Ipc::Istream &operator << (L4::Ipc::Istream &s, L4::Ipc::Small_buf const &v) { s.put(v); return s; }
1056 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Snd_item &v)
1057 {
1058  l4_umword_t b, d;
1059  s >> b >> d;
1060  v = L4::Ipc::Snd_item(b, d);
1061  return s;
1062 }
1063 inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Varg &v)
1064 { s.get(&v); return s; }
1065 
1066 
1067 /**
1068  * Extract the L4 message tag from the stream `s`.
1069  *
1070  * \param s The stream to extract from.
1071  * \param[out] v The extracted tag.
1072  *
1073  * \return The stream `s`.
1074  */
1075 inline
1076 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, l4_msgtag_t &v)
1077 {
1078  v = s.tag();
1079  return s;
1080 }
1081 
1082 /**
1083  * Extract an array of `T` elements from the stream `s`.
1084  *
1085  * \param s The stream to extract from.
1086  * \param[out] v Pointer to the extracted array (ipc_buf_in()).
1087  *
1088  * \return The stream `s`.
1089  *
1090  * This operator actually does not copy out the data in the array, but
1091  * returns a pointer into the message buffer itself. This means that the
1092  * data is only valid as long as there is no new data inserted into the stream.
1093  *
1094  * \note If array does not fit into transmitted words size will be set to zero.
1095  * Client has to implement check against zero.
1096  *
1097  * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out.
1098  */
1099 template< typename T >
1100 inline
1101 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1102  L4::Ipc::Internal::Buf_in<T> const &v)
1103 {
1104  unsigned long si;
1105  if (s.get(si) && s.has_more<T>(si))
1106  v.set_size(s.get(L4::Ipc::Msg_ptr<T>(v.buf()), si));
1107  else
1108  v.set_size(0);
1109  return s;
1110 }
1111 
1112 /**
1113  * Extract an element of type `T` from the stream `s`.
1114  *
1115  * \param s The stream to extract from.
1116  * \param[out] v Pointer to the extracted element.
1117  *
1118  * \return the stream `s`.
1119  *
1120  * This operator actually does not copy out the data, but
1121  * returns a pointer into the message buffer itself. This means that the
1122  * data is only valid as long as there is no new data inserted into the stream.
1123  *
1124  * See Msg_ptr.
1125  */
1126 template< typename T >
1127 inline
1128 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1129  L4::Ipc::Msg_ptr<T> const &v)
1130 {
1131  s.get(v);
1132  return s;
1133 }
1134 
1135 /**
1136  * Extract an array of `T` elements from the stream `s`.
1137  *
1138  * \param s The stream to extract from.
1139  * \param[out] v Buffer description to copy the array to (Ipc::Buf_cp_out()).
1140  *
1141  * \return The stream `s`.
1142  *
1143  * This operator does a copy out of the data into the given buffer.
1144  *
1145  * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out.
1146  */
1147 template< typename T >
1148 inline
1149 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1150  L4::Ipc::Internal::Buf_cp_in<T> const &v)
1151 {
1152  unsigned long sz;
1153  s.get(sz);
1154  v.size() = s.get(v.buf(), cxx::min(v.size(), sz));
1155  return s;
1156 }
1157 
1158 /**
1159  * Extract a zero-terminated string from the stream.
1160  *
1161  * \param s The stream to extract from.
1162  * \param[out] v Buffer description to copy the array to (Ipc::Str_cp_out()).
1163  *
1164  * \return the stream `s`.
1165  *
1166  * This operator does a copy out of the data into the given buffer.
1167  */
1168 template< typename T >
1169 inline
1170 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1171  L4::Ipc::Str_cp_in<T> const &v)
1172 {
1173  unsigned long sz;
1174  s.get(sz);
1175  unsigned long rsz = s.get(v.buf(), cxx::min(v.size(), sz));
1176  if (rsz < v.size() && v.buf()[rsz - 1])
1177  ++rsz; // add the zero termination behind the received data
1178 
1179  if (rsz != 0)
1180  v.buf()[rsz - 1] = 0;
1181 
1182  v.size() = rsz;
1183  return s;
1184 }
1185 
1186 
1187 /**
1188  * Insert an element to type `T` into the stream `s`.
1189  *
1190  * \param s The stream to insert the element `v`.
1191  * \param v The element to insert.
1192  *
1193  * \return The stream `s`.
1194  */
1195 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, bool v) { s.put(v); return s; }
1196 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, int v) { s.put(v); return s; }
1197 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, long int v) { s.put(v); return s; }
1198 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, long long int v) { s.put(v); return s; }
1199 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned int v) { s.put(v); return s; }
1200 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned long int v) { s.put(v); return s; }
1201 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned long long int v) { s.put(v); return s; }
1202 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, short int v) { s.put(v); return s; }
1203 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned short int v) { s.put(v); return s; }
1204 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char v) { s.put(v); return s; }
1205 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned char v) { s.put(v); return s; }
1206 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, signed char v) { s.put(v); return s; }
1207 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Snd_item const &v) { s.put_snd_item(v); return s; }
1208 template< typename T >
1209 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Cap<T> const &v)
1210 { s << L4::Ipc::Snd_fpage(v.fpage()); return s; }
1211 
1212 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Varg const &v)
1213 { s.put(v); return s; }
1214 template< typename T >
1215 inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Varg_t<T> const &v)
1216 { s.put(v); return s; }
1217 
1218 /**
1219  * Insert the L4 message tag into the stream `s`.
1220  *
1221  * \param s The stream to insert the tag `v`.
1222  * \param v The L4 message tag to insert.
1223  *
1224  * \return The stream `s`.
1225  *
1226  * \note Only one message tag can be inserted into a stream. Multiple
1227  * insertions simply overwrite previous insertions.
1228  */
1229 inline
1230 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, l4_msgtag_t const &v)
1231 {
1232  s.tag() = v;
1233  return s;
1234 }
1235 
1236 /**
1237  * Insert an array with elements of type `T` into the stream `s`.
1238  *
1239  * \param s The stream to insert the array `v`.
1240  * \param v The array to insert (see Ipc::Buf_cp_out()).
1241  *
1242  * \return the stream `s`.
1243  */
1244 template< typename T >
1245 inline
1246 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s,
1247  L4::Ipc::Internal::Buf_cp_out<T> const &v)
1248 {
1249  s.put(v.size());
1250  s.put(v.buf(), v.size());
1251  return s;
1252 }
1253 
1254 /**
1255  * Insert a zero terminated character string into the stream `s`.
1256  *
1257  * \param s The stream to insert the string `v`.
1258  * \param v The string to insert.
1259  *
1260  * \return The stream `s`.
1261  *
1262  * This operator produces basically the same content as the array insertion,
1263  * however the length of the array is calculated using `strlen(v) + 1`
1264  * The string is copied into the message including the trailing zero.
1265  */
1266 inline
1267 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char const *v)
1268 {
1269  unsigned long l = __builtin_strlen(v) + 1;
1270  s.put(l);
1271  s.put(v, l);
1272  return s;
1273 }
1274 
1275 
1276 #ifdef L4_CXX_IPC_BACKWARD_COMPAT
1277 namespace L4 {
1278 
1279 #if 0
1280 template< typename T > class Ipc_buf_cp_out : public Ipc::Buf_cp_out<T> {};
1281 template< typename T > class Ipc_buf_cp_in : public Ipc::Buf_cp_in<T> {};
1282 template< typename T > class Ipc_buf_in : public Ipc::Buf_in<T> {};
1283 template< typename T > class Msg_ptr : public Ipc::Msg_ptr<T> {};
1284 #endif
1285 
1286 template< typename T >
1287 Ipc::Internal::Buf_cp_out<T> ipc_buf_cp_out(T *v, unsigned long size)
1288  L4_DEPRECATED("Use L4::Ipc::buf_cp_out() now");
1289 
1290 template< typename T >
1291 Ipc::Internal::Buf_cp_out<T> ipc_buf_cp_out(T *v, unsigned long size)
1292 { return Ipc::Internal::Buf_cp_out<T>(v, size); }
1293 
1294 
1295 template< typename T >
1296 Ipc::Internal::Buf_cp_in<T> ipc_buf_cp_in(T *v, unsigned long &size)
1297  L4_DEPRECATED("Use L4::Ipc::buf_cp_in() now");
1298 
1299 template< typename T >
1300 Ipc::Internal::Buf_cp_in<T> ipc_buf_cp_in(T *v, unsigned long &size)
1301 { return Ipc::Internal::Buf_cp_in<T>(v, size); }
1302 
1303 
1304 template< typename T >
1305 Ipc::Internal::Buf_in<T> ipc_buf_in(T *&v, unsigned long &size)
1306  L4_DEPRECATED("Use L4::Ipc::buf_in() now");
1307 
1308 template< typename T >
1309 Ipc::Internal::Buf_in<T> ipc_buf_in(T *&v, unsigned long &size)
1310 { return Ipc::Internal::Buf_in<T>(v, size); }
1311 
1312 
1313 template< typename T >
1314 Ipc::Msg_ptr<T> msg_ptr(T *&p)
1315  L4_DEPRECATED("Use L4::Ipc::msg_ptr() now");
1316 
1317 template< typename T >
1318 Ipc::Msg_ptr<T> msg_ptr(T *&p)
1319 { return Ipc::Msg_ptr<T>(p); }
1320 
1321 typedef Ipc::Istream Ipc_istream L4_DEPRECATED("Use L4::Ipc::Istream now");
1322 typedef Ipc::Ostream Ipc_ostream L4_DEPRECATED("Use L4::Ipc::Ostream now");;
1323 typedef Ipc::Iostream Ipc_iostream L4_DEPRECATED("Use L4::Ipc::Iostream now");;
1324 typedef Ipc::Snd_fpage Snd_fpage L4_DEPRECATED("Use L4::Ipc::Snd_fpage now");;
1325 typedef Ipc::Rcv_fpage Rcv_fpage L4_DEPRECATED("Use L4::Ipc::Rcv_fpage now");;
1326 typedef Ipc::Small_buf Small_buf L4_DEPRECATED("Use L4::Ipc::Small_buf now");;
1327 
1328 
1329 namespace Ipc {
1330 template< typename T > class Buf_cp_in : public Internal::Buf_cp_in<T>
1331 {
1332 public:
1333  Buf_cp_in(T *v, unsigned long &size) : Internal::Buf_cp_in<T>(v, size) {}
1334 };
1335 
1336 template< typename T >
1337 class Buf_cp_out : public Internal::Buf_cp_out<T>
1338 {
1339 public:
1340  Buf_cp_out(T const *v, unsigned long size) : Internal::Buf_cp_out<T>(v, size) {}
1341 };
1342 
1343 template< typename T >
1344 class Buf_in : public Internal::Buf_in<T>
1345 {
1346 public:
1347  Buf_in(T *&v, unsigned long &size) : Internal::Buf_in<T>(v, size) {}
1348 };
1349 } // namespace Ipc
1350 } // namespace L4
1351 
1352 template< typename T >
1353 inline
1354 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Buf_cp_in<T> const &v)
1355  L4_DEPRECATED("Use L4::Ipc::buf_cp_in() now");
1356 
1357 template< typename T >
1358 inline
1359 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Buf_cp_in<T> const &v)
1360 { return operator>>(s, static_cast<L4::Ipc::Internal::Buf_cp_in<T> >(v)); }
1361 
1362 template< typename T >
1363 inline
1364 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Buf_in<T> const &v)
1365  L4_DEPRECATED("Use L4::Ipc::buf_in() now");
1366 
1367 template< typename T >
1368 inline
1369 L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Buf_in<T> const &v)
1370 { return operator>>(s, static_cast<L4::Ipc::Internal::Buf_in<T> >(v)); }
1371 
1372 template< typename T >
1373 inline
1374 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Buf_cp_out<T> const &v)
1375  L4_DEPRECATED("Use L4::Ipc::buf_cp_out() now");
1376 
1377 template< typename T >
1378 inline
1379 L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Buf_cp_out<T> const &v)
1380 { return operator<<(s, static_cast<L4::Ipc::Internal::Buf_cp_out<T> >(v)); }
1381 #endif
1382 
1383 namespace L4 { namespace Ipc {
1384 /**
1385  * Read a value out of a stream.
1386  *
1387  * \param s An Istream.
1388  * \return The value of type `T`.
1389  *
1390  * The stream position is progressed accordingly.
1391  */
1392 template< typename T >
1393 inline
1394 T read(Istream &s) { T t; s >> t; return t; }
1395 
1396 } // namespace Ipc
1397 } // namespace L4