4 * \brief IPC server loop
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)
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.
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.
28 #include <l4/sys/capability>
29 #include <l4/sys/err.h>
30 #include <l4/cxx/ipc_stream>
31 #include <l4/cxx/type_traits>
32 #include <l4/cxx/exceptions>
37 * \brief Helper classes for L4::Server instantiation.
42 * \brief Reply mode for server loop.
44 * The reply mode specifies if the server loop shall do a compound reply
45 * and wait operation (#Reply_compund), which is the most performant
46 * method. Note, setup_wait() is called before the reply. The other
47 * way is to call reply and wait separately and call setup_wait in between.
49 * The actual mode is determined by the return value of the before_reply()
50 * hook in the LOOP_HOOKS of L4::Server.
54 Reply_compound, ///< Server shall use a compound reply and wait (fast).
55 Reply_separate ///< Server shall call reply and wait separately.
59 * \brief Mix in for LOOP_HOOKS to ignore IPC errors.
62 { static void error(l4_msgtag_t, L4::Ipc::Iostream const &) {} };
65 * \brief Mix in for LOOP_HOOKS to use a 0 send and a infinite receive timeout.
67 struct Default_timeout
68 { static l4_timeout_t timeout() { return L4_IPC_SEND_TIMEOUT_0; } };
71 * \brief Mix in for LOOP_HOOKS to always use compound reply and wait.
75 static Reply_mode before_reply(long, L4::Ipc::Ostream const &)
76 { return Reply_compound; }
80 * \brief Mix in for LOOP_HOOKS for setup_wait no op.
82 struct Default_setup_wait
83 { static void setup_wait(L4::Ipc::Istream &, Reply_mode) {} };
86 * \brief Default LOOP_HOOKS.
88 * Combination of Ignore_errors, Default_timeout, Compound_reply,
89 * and Default_setup_wait.
91 struct Default_loop_hooks :
92 public Ignore_errors, public Default_timeout, public Compound_reply,
93 public Default_setup_wait
97 template< typename HOOKS >
98 class Timed_work : public HOOKS
101 l4_cpu_time_t _timeout;
105 : _timeout(HOOKS::next_timeout(HOOKS::current_time())) {}
107 l4_timeout_t timeout()
109 return l4_timeout(L4_IPC_TIMEOUT_0,
110 l4_timeout_abs(_timeout, this->timeout_br()));
113 void setup_wait(L4::Ipc::Istream &s, Reply_mode mode)
115 if (_timeout <= this->current_time()
116 && mode == Reply_separate)
119 _timeout = this->next_timeout(_timeout);
121 HOOKS::setup_wait(s, mode);
124 Reply_mode before_reply(long, L4::Ipc::Ostream const &)
126 if (_timeout <= this->current_time())
127 return Reply_separate;
128 return Reply_compound;
132 template< typename R >
133 struct Direct_dispatch
136 Direct_dispatch(R &r) : r(r) {}
137 long operator () (l4_umword_t obj, L4::Ipc::Iostream &ios)
138 { return r.dispatch(obj, ios); }
141 template< typename R >
142 struct Direct_dispatch<R*>
145 Direct_dispatch(R *r) : r(r) {}
146 long operator () (l4_umword_t obj, L4::Ipc::Iostream &ios)
147 { return r->dispatch(obj, ios); }
150 template< typename R, typename Exc = L4::Runtime_error>
151 struct Exc_dispatch : private Direct_dispatch<R>
153 Exc_dispatch(R r) : Direct_dispatch<R>(r) {}
154 long operator () (l4_umword_t obj, L4::Ipc::Iostream &ios)
158 return Direct_dispatch<R>::operator () (obj, ios);
170 * \brief Basic server loop for handling client requests.
171 * \ingroup client_server_ipc
172 * \param LOOP_HOOKS the server inherits from LOOP_HOOKS and calls the
173 * hooks defined in LOOP_HOOKS in the server loop.
174 * See Ipc_svr::Default_loop_hooks, Ipc_svr::Ignore_errors,
175 * Ipc_svr::Default_timeout, Ipc_svr::Compound_reply, and
176 * Ipc_svr::Default_setup_wait.
178 * This is basically a simple server loop that uses a single message buffer
179 * for receiving requests and sending replies. The dispatcher determines
180 * how incoming messages are handled.
182 template< typename LOOP_HOOKS = Ipc_svr::Default_loop_hooks >
188 * \brief Initializes the server loop and its underlying Ipc::Iostream.
189 * \param utcb The UTCB of the thread running the server loop.
191 explicit Server(l4_utcb_t *utcb) : _iostream(utcb) {}
194 * \brief The server loop.
196 * This function usually never returns, it waits for
197 * incoming messages calls the dispatcher, sends a reply and waits again.
199 template< typename DISPATCH >
200 inline L4_NORETURN void internal_loop(DISPATCH dispatch);
202 template< typename R >
203 inline L4_NORETURN void loop_noexc(R r)
204 { internal_loop(Ipc_svr::Direct_dispatch<R>(r)); }
206 template< typename R >
207 inline L4_NORETURN void loop(R r)
208 { internal_loop(Ipc_svr::Exc_dispatch<R>(r)); }
211 inline l4_msgtag_t reply_n_wait(long reply, l4_umword_t *p);
214 Ipc::Iostream _iostream;
217 template< typename L >
219 Server<L>::reply_n_wait(long reply, l4_umword_t *p)
221 if (reply != -L4_ENOREPLY)
223 Ipc_svr::Reply_mode m = this->before_reply(reply, _iostream);
224 if (m == Ipc_svr::Reply_compound)
226 this->setup_wait(_iostream, m);
227 return _iostream.reply_and_wait(p, this->timeout(), reply);
231 l4_msgtag_t res = _iostream.reply(this->timeout(), reply);
236 this->setup_wait(_iostream, Ipc_svr::Reply_separate);
237 return _iostream.wait(p, this->timeout());
240 template< typename L >
241 template< typename DISPATCH >
242 inline L4_NORETURN void
243 Server<L>::internal_loop(DISPATCH dispatch)
247 long r = -L4_ENOREPLY;
251 res = reply_n_wait(r, &p);
254 this->error(res, _iostream);
259 _iostream.Ipc::Ostream::reset();
260 r = dispatch(p, _iostream);
268 * \brief Abstract server object to be used with L4::Server and L4::Basic_registry.
269 * \ingroup client_server_ipc
271 * This server object provides an abstract interface that is used by the
272 * L4::Registry_dispatcher model. You can derive subclasses from this
273 * interface and implement application specific server objects.
279 * \brief The abstract handler for client requests to the object.
280 * \param obj The object ID used for looking up the object.
281 * \param ios The Ipc::Iostream for reading the request and writing the reply.
282 * \return #Reply, #No_reply, or #Invalid_opcode.
284 * This function must be implemented by application specific server
285 * objects. The implementation must unmarshall data from the stream (\a ios)
286 * and create a reply by marshalling to the stream (\a ios). For details
287 * about the IPC stream see \link ipc_stream IPC stream operators \endlink.
289 * \note You need to extract the complete message from the \a ios stream before
290 * inserting any reply data or before doing any function call that may use
291 * the UTCB. Otherwise, the incoming message may get lost.
293 virtual int dispatch(unsigned long obj, Ipc::Iostream &ios) = 0;
294 virtual ~Server_object() = 0;
297 Cap<Kobject> obj_cap() const { return _cap; }
298 template< typename T>
299 void obj_cap(Cap<T> const &cap) { _cap = cap; }
300 void obj_cap(Cap<Kobject> const &cap) { _cap = cap; }
306 inline Server_object::~Server_object() {}
309 * \brief This registry returns the corresponding server object
310 * based on the label of an Ipc_gate.
311 * \ingroup client_server_ipc
317 * \brief Get the server object for a Ipc_gate label.
318 * \param label The label usually stored in an Ipc_gate.
319 * \return A pointer to the Server_object identified the given label.
321 typedef Server_object Value;
322 static Value *find(l4_umword_t label)
323 { return reinterpret_cast<Value*>(label & ~3UL); }
326 * \brief The dispatch function called by the server loop.
328 * This function forwards the message to the server object identified by the
331 * \param label The label used to find the object including the rights bits
332 * of the invoked capability.
333 * \param ios The Ipc::Iostream for the request and the reply.
334 * \return The return code from the object's dispatch function or -L4_ENOENT
335 * if the object does not exist.
337 static int dispatch(l4_umword_t label, L4::Ipc::Iostream &ios)
339 Value *o = find(label);
344 return o->dispatch(label, ios);