L4Re – L4 Runtime Environment
ipc_server_loop
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /*
3  * Copyright (C) 2015 Kernkonzept GmbH.
4  * Author(s): Alexander Warg <alexander.warg@kernkonzept.com>
5  *
6  * This file is distributed under the terms of the GNU General Public
7  * License, version 2. 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 "ipc_epiface"
21 
22 namespace L4 {
23 
35 namespace Ipc_svr {
36 
51 {
54 };
55 
62 { static void error(l4_msgtag_t, l4_utcb_t *) {} };
63 
70 { static l4_timeout_t timeout() { return L4_IPC_SEND_TIMEOUT_0; } };
71 
78 {
79  static Reply_mode before_reply(l4_msgtag_t, l4_utcb_t *)
80  { return Reply_compound; }
81 };
82 
89 { static void setup_wait(l4_utcb_t *, Reply_mode) {} };
90 
96 template< typename HOOKS >
97 class Timed_work : public HOOKS
98 {
99 protected:
100  l4_cpu_time_t _timeout;
101 
102 public:
103  Timed_work()
104  : _timeout(HOOKS::next_timeout(HOOKS::current_time())) {}
105 
106  l4_timeout_t timeout()
107  {
109  l4_timeout_abs(_timeout, this->timeout_br()));
110  }
111 
112  void setup_wait(l4_utcb_t *utcb, Reply_mode mode)
113  {
114  if (_timeout <= this->current_time()
115  && mode == Reply_separate)
116  {
117  this->work();
118  _timeout = this->next_timeout(_timeout);
119  }
120  HOOKS::setup_wait(utcb, mode);
121  }
122 
123  Reply_mode before_reply(l4_msgtag_t, l4_utcb_t *)
124  {
125  if (_timeout <= this->current_time())
126  return Reply_separate;
127  return Reply_compound;
128  }
129 };
130 
138 template< typename R >
140 {
142  R &r;
143 
145  Direct_dispatch(R &r) : r(r) {}
146 
149  { return r.dispatch(tag, obj, utcb); }
150 };
151 
159 template< typename R >
160 struct Direct_dispatch<R*>
161 {
163  R *r;
164 
166  Direct_dispatch(R *r) : r(r) {}
167 
169  l4_msgtag_t operator () (l4_msgtag_t tag, l4_umword_t obj, l4_utcb_t *utcb)
170  { return r->dispatch(tag, obj, utcb); }
171 };
172 
173 #ifdef __EXCEPTIONS
183 template< typename R, typename Exc> // = L4::Runtime_error>
184 struct Exc_dispatch : private Direct_dispatch<R>
185 {
188 
193  {
194  try
195  {
196  return Direct_dispatch<R>::operator () (tag, obj, utcb);
197  }
198  catch (Exc &e)
199  {
200  return l4_msgtag(e.err_no(), 0, 0, 0);
201  }
202  catch (int err)
203  {
204  return l4_msgtag(err, 0, 0, 0);
205  }
206  catch (long err)
207  {
208  return l4_msgtag(err, 0, 0, 0);
209  }
210  }
211 };
212 #endif
213 
225 {
226 public:
231  int alloc_buffer_demand(Demand const &demand)
232  {
233  if (!demand.no_demand())
234  return -L4_ENOMEM;
235  return L4_EOK;
236  }
237 
240  { return L4::Cap<void>::Invalid; }
241 
244  { return -L4_ENOMEM; }
245 
248  { return -L4_ENOSYS; }
249 
252  { return -L4_ENOSYS; }
253 
254 protected:
256  unsigned first_free_br() const
257  { return 1; }
258 
261  {
262  l4_buf_regs_t *br = l4_utcb_br_u(utcb);
263  br->bdr = 0;
264  br->br[0] = 0;
265  }
266 };
267 
277  public Ignore_errors, public Default_timeout, public Compound_reply,
279 {};
280 
281 }
282 
297 template< typename LOOP_HOOKS = Ipc_svr::Default_loop_hooks >
298 class Server :
299  public LOOP_HOOKS
300 {
301 public:
306  explicit Server(l4_utcb_t *utcb) : _utcb(utcb) {}
307 
314  template< typename DISPATCH >
315  inline L4_NORETURN void internal_loop(DISPATCH dispatch);
316 
320  template< typename R >
321  inline L4_NORETURN void loop_noexc(R r)
323 #ifdef __EXCEPTIONS
330  template< typename EXC, typename R >
331  inline L4_NORETURN void loop(R r)
332  { internal_loop(Ipc_svr::Exc_dispatch<R, EXC>(r)); while(1) ; }
333 #endif
334 protected:
337 
338 public:
339  l4_utcb_t *_utcb;
340 };
341 
342 template< typename L >
343 inline l4_msgtag_t
345 {
346  if (reply.label() != -L4_ENOREPLY)
347  {
348  Ipc_svr::Reply_mode m = this->before_reply(reply, _utcb);
349  if (m == Ipc_svr::Reply_compound)
350  {
351  this->setup_wait(_utcb, m);
352  return l4_ipc_reply_and_wait(_utcb, reply, p, this->timeout());
353  }
354  else
355  {
356  l4_msgtag_t res = l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, _utcb, reply, this->timeout());
357  if (res.has_error())
358  return res;
359  }
360  }
361  this->setup_wait(_utcb, Ipc_svr::Reply_separate);
362  return l4_ipc_wait(_utcb, p, this->timeout());
363 }
364 
365 template< typename L >
366 template< typename DISPATCH >
367 inline L4_NORETURN void
368 Server<L>::internal_loop(DISPATCH dispatch)
369 {
370  l4_msgtag_t res;
371  l4_umword_t p;
372  l4_msgtag_t r = l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
373 
374  while (true)
375  {
376  res = reply_n_wait(r, &p);
377  if (res.has_error())
378  {
379  this->error(res, _utcb);
380  r = l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
381  continue;
382  }
383 
384  r = dispatch(res, p, _utcb);
385  }
386 }
387 
388 } // namespace L4
C++ interface for capabilities.
Definition: capability.h:219
Empty implementation of Server_iface.
int alloc_buffer_demand(Demand const &demand)
Tells the server to allocate buffers for the given demand.
int realloc_rcv_cap(int)
Returns -L4_ENOMEM, we have no buffer management.
L4::Cap< void > get_rcv_cap(int) const
Returns L4::Cap<void>::Invalid, we have no buffer management.
int remove_timeout(Timeout *)
Returns -L4_ENOSYS, we have no timeout queue.
unsigned first_free_br() const
Returns 1 as first free buffer.
int add_timeout(Timeout *, l4_kernel_clock_t)
Returns -L4_ENOSYS, we have no timeout queue.
void setup_wait(l4_utcb_t *utcb, L4::Ipc_svr::Reply_mode)
Setup wait function for the server loop (Server<>).
Interface for server-loop related functions.
Definition: ipc_epiface:48
Callback interface for Timeout_queue.
Basic server loop for handling client requests.
Server(l4_utcb_t *utcb)
Initializes the server loop.
l4_msgtag_t reply_n_wait(l4_msgtag_t reply, l4_umword_t *p)
Internal implementation for reply and wait.
L4_NORETURN void loop(R r)
Server loop with internal exception handling.
L4_NORETURN void internal_loop(DISPATCH dispatch)
The server loop.
L4_NORETURN void loop_noexc(R r)
Server loop without exception handling.
Data type for expressing the needed receive buffers at the server-side of an interface.
Definition: __typeinfo.h:517
bool no_demand() const noexcept
Definition: __typeinfo.h:542
#define L4_NORETURN
Noreturn function attribute.
Definition: compiler.h:206
Reply_mode
Reply mode for server loop.
Definition: ipc_server_loop:51
@ Reply_separate
Server shall call reply and wait separately.
Definition: ipc_server_loop:53
@ Reply_compound
Server shall use a compound reply and wait (fast).
Definition: ipc_server_loop:52
unsigned long l4_umword_t
Unsigned machine word.
Definition: l4int.h:51
l4_uint64_t l4_cpu_time_t
CPU clock type.
Definition: l4int.h:58
l4_uint64_t l4_kernel_clock_t
Kernel clock type.
Definition: l4int.h:64
@ L4_INVALID_CAP
Invalid capability selector.
Definition: consts.h:141
@ L4_ENOSYS
No sys.
Definition: err.h:60
@ L4_ENOREPLY
No reply.
Definition: err.h:65
@ L4_EOK
Ok.
Definition: err.h:43
@ L4_ENOMEM
No memory.
Definition: err.h:50
l4_msgtag_t l4_ipc_reply_and_wait(l4_utcb_t *utcb, l4_msgtag_t tag, l4_umword_t *label, l4_timeout_t timeout) L4_NOTHROW
Reply and wait operation (uses the reply capability).
Definition: ipc.h:471
l4_msgtag_t l4_ipc_send(l4_cap_idx_t dest, l4_utcb_t *utcb, l4_msgtag_t tag, l4_timeout_t timeout) L4_NOTHROW
Send a message to an object (do not wait for a reply).
Definition: ipc.h:488
l4_msgtag_t l4_ipc_wait(l4_utcb_t *utcb, l4_umword_t *label, l4_timeout_t timeout) L4_NOTHROW
Wait for an incoming message from any possible sender.
Definition: ipc.h:496
@ L4_SYSF_REPLY
Reply flag.
Definition: consts.h:89
l4_msgtag_t l4_msgtag(long label, unsigned words, unsigned items, unsigned flags) L4_NOTHROW
Create a message tag from the specified values.
Definition: types.h:408
#define L4_IPC_TIMEOUT_0
Timeout constants.
Definition: __timeout.h:79
l4_timeout_t l4_timeout(l4_timeout_s snd, l4_timeout_s rcv) L4_NOTHROW
Combine send and receive timeout in a timeout.
Definition: __timeout.h:198
l4_timeout_s l4_timeout_abs(l4_kernel_clock_t pint, int br) L4_NOTHROW
Set an absolute timeout.
Definition: utcb.h:383
struct l4_utcb_t l4_utcb_t
Opaque type for the UTCB.
Definition: utcb.h:67
L4 low-level kernel interface.
Mix in for LOOP_HOOKS to always use compound reply and wait.
Definition: ipc_server_loop:78
Mix in for LOOP_HOOKS for setup_wait no op.
Definition: ipc_server_loop:89
Mix in for LOOP_HOOKS to use a 0 send and a infinite receive timeout.
Definition: ipc_server_loop:70
R * r
stores a pointer to the registry object
Direct_dispatch(R *r)
Make a direct dispatcher.
Direct dispatch helper, for forwarding dispatch calls to a registry R.
R & r
stores a reference to the registry object
l4_msgtag_t operator()(l4_msgtag_t tag, l4_umword_t obj, l4_utcb_t *utcb)
call operator forwarding to r.dispatch()
Direct_dispatch(R &r)
Make a direct dispatcher.
Dispatch helper wrapping try {} catch {} around the dispatch call.
Exc_dispatch(R r)
Make an exception handling dispatcher.
l4_msgtag_t operator()(l4_msgtag_t tag, l4_umword_t obj, l4_utcb_t *utcb)
Dispatch the call via Direct_dispatch<R>() and handle exceptions.
Mix in for LOOP_HOOKS to ignore IPC errors.
Definition: ipc_server_loop:62
Encapsulation of the buffer-registers block in the UTCB.
Definition: utcb.h:94
l4_umword_t br[L4_UTCB_GENERIC_BUFFERS_SIZE]
Buffer registers.
Definition: utcb.h:99
l4_umword_t bdr
Buffer descriptor.
Definition: utcb.h:96
Message tag data structure.
Definition: types.h:160
long label() const L4_NOTHROW
Get the protocol value.
Definition: types.h:164
unsigned has_error() const L4_NOTHROW
Test if flags indicate an error.
Definition: types.h:191
Timeout pair.
Definition: __timeout.h:59