]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/cxx/lib/ipc/include/ipc_server
df81421cdb59d086fbea9c44bdde4e93106a3c96
[l4.git] / l4 / pkg / cxx / lib / ipc / include / ipc_server
1 // vi:ft=cpp
2 /**
3  * \file
4  * \brief IPC server loop
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
26 #pragma once
27
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>
33
34 namespace L4 {
35
36 /**
37  * \brief Helper classes for L4::Server instantiation.
38  */
39 namespace Ipc_svr {
40
41 /**
42  * \brief Reply mode for server loop.
43  *
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.
48  *
49  * The actual mode is determined by the return value of the before_reply()
50  * hook in the LOOP_HOOKS of L4::Server.
51  */
52 enum Reply_mode
53 {
54   Reply_compound, ///< Server shall use a compound reply and wait (fast).
55   Reply_separate  ///< Server shall call reply and wait separately.
56 };
57
58 /**
59  * \brief Mix in for LOOP_HOOKS to ignore IPC errors.
60  */
61 struct Ignore_errors
62 { static void error(l4_msgtag_t, L4::Ipc::Iostream const &) {} };
63
64 /**
65  * \brief Mix in for LOOP_HOOKS to use a 0 send and a infinite receive timeout.
66  */
67 struct Default_timeout
68 { static l4_timeout_t timeout() { return L4_IPC_SEND_TIMEOUT_0; } };
69
70 /**
71  * \brief Mix in for LOOP_HOOKS to always use compound reply and wait.
72  */
73 struct Compound_reply
74 {
75   static Reply_mode before_reply(long, L4::Ipc::Ostream const &)
76   { return Reply_compound; }
77 };
78
79 /**
80  * \brief Mix in for LOOP_HOOKS for setup_wait no op.
81  */
82 struct Default_setup_wait
83 { static void setup_wait(L4::Ipc::Istream &, Reply_mode) {} };
84
85 /**
86  * \brief Default LOOP_HOOKS.
87  *
88  * Combination of Ignore_errors, Default_timeout, Compound_reply,
89  * and Default_setup_wait.
90  */
91 struct Default_loop_hooks :
92   public Ignore_errors, public Default_timeout, public Compound_reply,
93   public Default_setup_wait
94 {};
95
96
97 template< typename HOOKS >
98 class Timed_work : public HOOKS
99 {
100 protected:
101   l4_cpu_time_t _timeout;
102
103 public:
104   Timed_work()
105   : _timeout(HOOKS::next_timeout(HOOKS::current_time())) {}
106
107   l4_timeout_t timeout()
108   {
109     return l4_timeout(L4_IPC_TIMEOUT_0,
110                       l4_timeout_abs(_timeout, this->timeout_br()));
111   }
112
113   void setup_wait(L4::Ipc::Istream &s, Reply_mode mode)
114   {
115     if (_timeout <= this->current_time()
116         && mode == Reply_separate)
117       {
118         this->work();
119         _timeout = this->next_timeout(_timeout);
120       }
121     HOOKS::setup_wait(s, mode);
122   }
123
124   Reply_mode before_reply(long, L4::Ipc::Ostream const &)
125   {
126     if (_timeout <= this->current_time())
127       return Reply_separate;
128     return Reply_compound;
129   }
130 };
131
132 template< typename R >
133 struct Direct_dispatch
134 {
135   R &r;
136   Direct_dispatch(R &r) : r(r) {}
137   long operator () (l4_umword_t obj, L4::Ipc::Iostream &ios)
138   { return r.dispatch(obj, ios); }
139 };
140
141 template< typename R >
142 struct Direct_dispatch<R*>
143 {
144   R *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); }
148 };
149
150 template< typename R, typename Exc = L4::Runtime_error>
151 struct Exc_dispatch : private Direct_dispatch<R>
152 {
153   Exc_dispatch(R r) : Direct_dispatch<R>(r) {}
154   long operator () (l4_umword_t obj, L4::Ipc::Iostream &ios)
155   {
156     try
157       {
158         return Direct_dispatch<R>::operator () (obj, ios);
159       }
160     catch (Exc &e)
161       {
162         return e.err_no();
163       }
164   }
165 };
166
167 }
168
169 /**
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.
177  *
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.
181  */
182 template< typename LOOP_HOOKS = Ipc_svr::Default_loop_hooks >
183 class Server :
184   public LOOP_HOOKS
185 {
186 public:
187   /**
188    * \brief Initializes the server loop and its underlying Ipc::Iostream.
189    * \param utcb The UTCB of the thread running the server loop.
190    */
191   explicit Server(l4_utcb_t *utcb) : _iostream(utcb) {}
192
193   /**
194    * \brief The server loop.
195    *
196    * This function usually never returns, it waits for
197    * incoming messages calls the dispatcher, sends a reply and waits again.
198    */
199   template< typename DISPATCH >
200   inline L4_NORETURN void internal_loop(DISPATCH dispatch);
201
202   template< typename R >
203   inline L4_NORETURN void loop_noexc(R r)
204   { internal_loop(Ipc_svr::Direct_dispatch<R>(r)); }
205
206   template< typename R >
207   inline L4_NORETURN void loop(R r)
208   { internal_loop(Ipc_svr::Exc_dispatch<R>(r)); }
209
210 protected:
211   inline l4_msgtag_t reply_n_wait(long reply, l4_umword_t *p);
212
213 public:
214   Ipc::Iostream _iostream;
215 };
216
217 template< typename L >
218 inline l4_msgtag_t
219 Server<L>::reply_n_wait(long reply, l4_umword_t *p)
220 {
221   if (reply != -L4_ENOREPLY)
222     {
223       Ipc_svr::Reply_mode m = this->before_reply(reply, _iostream);
224       if (m == Ipc_svr::Reply_compound)
225         {
226           this->setup_wait(_iostream, m);
227           return _iostream.reply_and_wait(p, this->timeout(), reply);
228         }
229       else
230         {
231           l4_msgtag_t res = _iostream.reply(this->timeout(), reply);
232           if (res.has_error())
233             return res;
234         }
235     }
236   this->setup_wait(_iostream, Ipc_svr::Reply_separate);
237   return _iostream.wait(p, this->timeout());
238 }
239
240 template< typename L >
241 template< typename DISPATCH >
242 inline L4_NORETURN void
243 Server<L>::internal_loop(DISPATCH dispatch)
244 {
245   l4_msgtag_t res;
246   l4_umword_t p;
247   long r = -L4_ENOREPLY;
248
249   while (true)
250     {
251       res = reply_n_wait(r, &p);
252       if (res.has_error())
253         {
254           this->error(res, _iostream);
255           r = -L4_ENOREPLY;
256           continue;
257         }
258
259       _iostream.Ipc::Ostream::reset();
260       r = dispatch(p, _iostream);
261     }
262 }
263
264
265
266
267 /**
268  * \brief Abstract server object to be used with L4::Server and L4::Basic_registry.
269  * \ingroup client_server_ipc
270  *
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.
274  */
275 class Server_object
276 {
277 public:
278   /**
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.
283    *
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.
288    *
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.
292    */
293   virtual int dispatch(unsigned long obj, Ipc::Iostream &ios) = 0;
294   virtual ~Server_object() = 0;
295
296
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; }
301
302 private:
303   Cap<Kobject> _cap;
304 };
305
306 inline Server_object::~Server_object() {}
307
308 /**
309  * \brief This registry returns the corresponding server object
310  *        based on the label of an Ipc_gate.
311  * \ingroup client_server_ipc
312  */
313 class Basic_registry
314 {
315 public:
316   /**
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.
320    */
321   typedef Server_object Value;
322   static Value *find(l4_umword_t label)
323   { return reinterpret_cast<Value*>(label & ~3UL); }
324
325   /**
326    * \brief The dispatch function called by the server loop.
327    *
328    * This function forwards the message to the server object identified by the
329    * given \a label.
330    *
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.
336    */
337   static int dispatch(l4_umword_t label, L4::Ipc::Iostream &ios)
338   {
339     Value *o = find(label);
340
341     if (!o)
342       return -L4_ENOENT;
343
344     return o->dispatch(label, ios);
345   }
346 };
347
348 }