]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/receiver.cpp
031b4791b2225c7ef1fc5e68ff455cf4c5f89689
[l4.git] / kernel / fiasco / src / kern / receiver.cpp
1 INTERFACE:
2
3 #include "context.h"
4 #include "l4_error.h"
5 #include "member_offs.h"
6 #include "timeout.h"
7 #include "prio_list.h"
8 #include "ref_obj.h"
9
10 class Syscall_frame;
11 class Sender;
12
13
14 /** A receiver.  This is a role class, and real receiver's must inherit from 
15     it.  The protected interface is intended for the receiver, and the public
16     interface is intended for the sender.
17
18     The only reason this class inherits from Context is to force a specific 
19     layout for Thread.  Otherwise, Receiver could just embed or reference
20     a Context.
21  */
22 class Receiver : public Context,  public Ref_cnt_obj
23 {
24   MEMBER_OFFSET();
25
26 public:
27   enum Rcv_state
28   {
29     Rs_not_receiving = false,
30     Rs_ipc_receive   = true,
31     Rs_irq_receive   = true + 1
32   };
33
34   Rcv_state sender_ok(const Sender* sender) const;
35
36   virtual ~Receiver() {}
37
38 private:
39   // DATA
40   Sender*           _partner;   // IPC partner I'm waiting for/involved with
41   Syscall_frame    *_rcv_regs; // registers used for receive
42   Mword _caller;
43   Iteratable_prio_list         _sender_list;
44 };
45
46 typedef Context_ptr_base<Receiver> Receiver_ptr;
47
48 IMPLEMENTATION:
49
50 #include "l4_types.h"
51 #include <cassert>
52
53 #include "cpu_lock.h"
54 #include "globals.h"
55 #include "lock_guard.h"
56 #include "logdefs.h"
57 #include "sender.h"
58 #include "thread_lock.h"
59 #include "entry_frame.h"
60 #include "std_macros.h"
61 #include "thread_state.h"
62
63 // Interface for receivers
64
65 /** Constructor.
66     @param thread_lock the lock used for synchronizing access to this receiver
67     @param space_context the space context 
68  */
69 PROTECTED inline
70 Receiver::Receiver()
71 : Context(), _caller(0)
72 {}
73
74 PUBLIC inline
75 Receiver *
76 Receiver::caller() const
77 { return reinterpret_cast<Receiver*>(_caller & ~0x03UL); }
78
79 PUBLIC inline
80 unsigned char
81 Receiver::caller_rights() const
82 { return _caller & 0x3; }
83
84
85 PUBLIC inline
86 void
87 Receiver::set_caller(Receiver *caller, unsigned char rights)
88 {
89   register Mword nv = Mword(caller) | (rights & 0x3);
90   reinterpret_cast<Mword volatile &>(_caller) = nv;
91 }
92 /** IPC partner (sender).
93     @return sender of ongoing or previous IPC operation
94  */
95 PROTECTED inline
96 Sender*
97 Receiver::partner() const
98 {
99   return _partner;
100 }
101
102
103 /** Restore a saved IPC state to restart a suspended IPC.
104     @param partner sender of suspended receive operation
105     @param regs registers of suspended receive operation
106  */
107 PROTECTED inline NEEDS[Receiver::set_partner, Receiver::set_rcv_regs]
108 void
109 Receiver::restore_receiver_state(Sender* partner, Syscall_frame* regs)
110 {
111   set_partner(partner);
112   set_rcv_regs(regs);
113 }
114
115 /** Save IPC state to allow later restart a suspended IPC.
116     @param out_partner returns sender of suspended receive operation
117     @param out_regs returns pointer to IPC regs of suspended receive operation
118  */
119 PROTECTED inline
120 void
121 Receiver::save_receiver_state(Sender** out_partner, Syscall_frame** out_regs)
122 {
123   *out_partner = _partner;
124   *out_regs = _rcv_regs;
125 }
126
127
128 // Interface for senders
129
130 /** Return a reference to receiver's IPC registers.
131     Senders call this function to poke values into the receiver's register set.
132     @pre state() & Thread_ipc_receiving_mask
133     @return pointer to receiver's IPC registers.
134  */
135 PUBLIC inline NEEDS[<cassert>]
136 Syscall_frame*
137 Receiver::rcv_regs() const
138 {
139   //assert (state () & Thread_ipc_receiving_mask);
140
141   return _rcv_regs;
142 }
143
144 /** Head of sender list.
145     @return a reference to the receiver's list of senders
146  */
147 PUBLIC inline
148 Iteratable_prio_list *
149 Receiver::sender_list()
150 {
151   return &_sender_list;
152 }
153
154 // MANIPULATORS
155
156 PROTECTED inline 
157 void
158 Receiver::set_rcv_regs(Syscall_frame* regs)
159 {
160   _rcv_regs = regs;
161 }
162
163 PUBLIC inline
164 void
165 Receiver::set_timeout(Timeout *t)
166 {
167   _timeout = t;
168 }
169
170 PUBLIC inline
171 void
172 Receiver::dequeue_timeout()
173 {
174   if (_timeout)
175     _timeout->dequeue(_timeout->has_hit());
176 }
177
178 PUBLIC inline
179 void
180 Receiver::enqueue_timeout_again()
181 {
182   if (_timeout)
183     _timeout->set_again(current_cpu());
184 }
185
186 PUBLIC inline
187 void
188 Receiver::reset_timeout()
189 {
190   if (EXPECT_TRUE(!_timeout))
191     return;
192
193   _timeout->reset();
194   _timeout = 0;
195 }
196
197 /** Initiates a receiving IPC and updates the ipc partner.
198     @param sender the sender that wants to establish an IPC handshake
199  */
200 PUBLIC inline NEEDS [Receiver::set_partner,
201                      Receiver::rcv_regs,
202                      "entry_frame.h", "sender.h", "l4_types.h"]
203 void
204 Receiver::ipc_init(Sender* sender)
205 {
206   set_partner(sender);
207   //rcv_regs()->from (sender->id());
208   state_add_dirty(Thread_transfer_in_progress);
209 }
210
211 PROTECTED inline
212 void Receiver::prepare_receive_dirty_1(Sender *partner,
213                                        Syscall_frame *regs)
214 {
215   // cpu lock required, or weird things will happen
216   assert (cpu_lock.test());
217
218   set_rcv_regs(regs);  // message should be poked in here
219   set_partner(partner);
220 }
221
222 PROTECTED inline
223 bool Receiver::prepared() const
224 { return _rcv_regs; }
225
226
227 PROTECTED inline
228 void Receiver::prepare_receive_dirty_2()
229 {
230   // cpu lock required, or weird things will happen
231   assert (cpu_lock.test());
232   assert (_rcv_regs);
233
234   state_change_dirty(~(Thread_ipc_sending_mask | Thread_transfer_in_progress),
235                      Thread_receiving | Thread_ipc_in_progress);
236 }
237
238 PUBLIC inline
239 bool
240 Receiver::in_ipc(Sender *sender)
241 {
242   Mword ipc_state = (state() & (Thread_ipc_in_progress
243                                | Thread_cancel
244                                | Thread_transfer_in_progress));
245
246   if (EXPECT_TRUE
247       ((ipc_state == (Thread_transfer_in_progress | Thread_ipc_in_progress))
248        &&  _partner == sender))
249     return true;
250
251   return false;
252
253 }
254
255 /** Set the IPC partner (sender).
256     @param partner IPC partner
257  */
258 PROTECTED inline 
259 void
260 Receiver::set_partner(Sender* partner)
261 {
262   _partner = partner;
263 }
264
265
266 /** Return whether the receiver is ready to accept a message from the
267     given sender.
268     @param sender thread that wants to send a message to this receiver
269     @return true if receiver is in correct state to accept a message 
270                  right now (open wait, or closed wait and waiting for sender).
271  */
272 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", Receiver::partner,
273                        Receiver::vcpu_async_ipc]
274 Receiver::Rcv_state
275 Receiver::sender_ok(const Sender *sender) const
276 {
277   unsigned ipc_state = state() & (Thread_receiving |
278                                   //                 Thread_send_in_progress |
279                                   Thread_ipc_in_progress);
280   // If Thread_send_in_progress is still set, we're still in the send phase
281   if (EXPECT_FALSE(ipc_state != (Thread_receiving | Thread_ipc_in_progress)))
282     return vcpu_async_ipc(sender);
283
284   // Check open wait; test if this sender is really the first in queue
285   if (EXPECT_TRUE(!partner()
286                   && (!_sender_list.head()
287                     || sender->is_head_of(&_sender_list))))
288     return Rs_ipc_receive;
289
290   // Check closed wait; test if this sender is really who we specified
291   if (EXPECT_TRUE(sender == partner()))
292     return Rs_ipc_receive;
293
294   return Rs_not_receiving;
295 }
296
297 //-----------------------------------------------------------------------------
298 // VCPU code:
299
300 PRIVATE inline
301 Receiver::Rcv_state
302 Receiver::vcpu_async_ipc(Sender const *sender) const
303 {
304   if (EXPECT_FALSE(state() & Thread_ipc_sending_mask))
305     return Rs_not_receiving;
306
307   Vcpu_state *vcpu = vcpu_state().access();
308
309   if (EXPECT_FALSE(!vcpu_irqs_enabled(vcpu)))
310     return Rs_not_receiving;
311
312   Receiver *self = const_cast<Receiver*>(this);
313
314   if (this == current())
315     self->spill_user_state();
316
317   self->vcpu_enter_kernel_mode(vcpu);
318
319   LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
320       Vcpu_log *l = tbe->payload<Vcpu_log>();
321       l->type = 1;
322       l->state = vcpu->_saved_state;
323       l->ip = Mword(sender);
324       l->sp = regs()->sp();
325       l->space = ~0; //vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
326       );
327
328   self->_rcv_regs = &vcpu->_ipc_regs;
329   vcpu->_ts.set_ipc_upcall();
330   self->set_partner(const_cast<Sender*>(sender));
331   self->state_add_dirty(Thread_receiving | Thread_ipc_in_progress);
332   self->vcpu_save_state_and_upcall();
333   return Rs_irq_receive;
334 }
335
336
337 PUBLIC inline
338 void
339 Receiver::vcpu_update_state()
340 {
341   if (EXPECT_TRUE(!(state() & Thread_vcpu_enabled)))
342     return;
343
344   if (!sender_list()->head())
345     vcpu_state().access()->sticky_flags &= ~Vcpu_state::Sf_irq_pending;
346 }
347
348
349 // --------------------------------------------------------------------------
350
351 struct Ipc_remote_dequeue_request
352 {
353   Receiver *partner;
354   Sender *sender;
355   bool was_queued;
356 };
357
358 PRIVATE static
359 unsigned
360 Receiver::handle_remote_abort_send(Drq *, Context *, void *_rq)
361 {
362   Ipc_remote_dequeue_request *rq = (Ipc_remote_dequeue_request*)_rq;
363   if (rq->sender->in_sender_list())
364     {
365       // really cancled IPC
366       rq->was_queued = true;
367       rq->sender->sender_dequeue(rq->partner->sender_list());
368       rq->partner->vcpu_update_state();
369     }
370   return 0;
371 }
372
373 PUBLIC
374 bool
375 Receiver::abort_send(Sender *sender)
376 {
377   Ipc_remote_dequeue_request rq;
378   rq.partner = this;
379   rq.sender = sender;
380   rq.was_queued = false;
381   current()->drq(handle_remote_abort_send, &rq);
382   return !rq.was_queued;
383 }
384