]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/receiver.cpp
update
[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(Thread_lock *thread_lock)
71 : Context(thread_lock), _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 /** Unlock a receiver locked with ipc_try_lock(). */
266 PUBLIC inline NEEDS ["thread_lock.h", "globals.h"]
267 void
268 Receiver::ipc_unlock()
269 {
270   //assert (thread_lock()->lock_owner() == current());
271
272   thread_lock()->clear();
273 }
274
275
276
277 /** Return whether the receiver is ready to accept a message from the
278     given sender.
279     @param sender thread that wants to send a message to this receiver
280     @return true if receiver is in correct state to accept a message 
281                  right now (open wait, or closed wait and waiting for sender).
282  */
283 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", Receiver::partner,
284                        Receiver::vcpu_async_ipc]
285 Receiver::Rcv_state
286 Receiver::sender_ok(const Sender *sender) const
287 {
288   unsigned ipc_state = state() & (Thread_receiving |
289                                   //                 Thread_send_in_progress |
290                                   Thread_ipc_in_progress);
291   // If Thread_send_in_progress is still set, we're still in the send phase
292   if (EXPECT_FALSE(ipc_state != (Thread_receiving | Thread_ipc_in_progress)))
293     return vcpu_async_ipc(sender);
294
295   // Check open wait; test if this sender is really the first in queue
296   if (EXPECT_TRUE(!partner()
297                   && (!_sender_list.head() 
298                     || sender->is_head_of(&_sender_list))))
299     return Rs_ipc_receive;
300
301   // Check closed wait; test if this sender is really who we specified
302   if (EXPECT_TRUE(sender == partner()))
303     return Rs_ipc_receive;
304
305   return Rs_not_receiving;
306 }
307
308 //-----------------------------------------------------------------------------
309 // VCPU code:
310
311 PRIVATE inline
312 Receiver::Rcv_state
313 Receiver::vcpu_async_ipc(Sender const *sender) const
314 {
315   Vcpu_state *vcpu = access_vcpu();
316
317   if (EXPECT_FALSE(!vcpu_irqs_enabled(vcpu)))
318     return Rs_not_receiving;
319
320   Receiver *self = const_cast<Receiver*>(this);
321
322   if (this == current())
323     self->spill_user_state();
324
325   self->vcpu_enter_kernel_mode(vcpu);
326
327   LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
328       Vcpu_log *l = tbe->payload<Vcpu_log>();
329       l->type = 1;
330       l->state = vcpu->_saved_state;
331       l->ip = Mword(sender);
332       l->sp = regs()->sp();
333       l->space = ~0; //vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
334       );
335
336   self->_rcv_regs = &vcpu->_ipc_regs;
337   vcpu->_ts.set_ipc_upcall();
338   self->set_partner(const_cast<Sender*>(sender));
339   self->state_add_dirty(Thread_receiving | Thread_ipc_in_progress);
340   self->vcpu_save_state_and_upcall();
341   return Rs_irq_receive;
342 }
343
344
345 PUBLIC inline
346 void
347 Receiver::vcpu_update_state()
348 {
349   if (EXPECT_TRUE(!(state() & Thread_vcpu_enabled)))
350     return;
351
352   if (!sender_list()->head())
353     access_vcpu()->sticky_flags &= ~Vcpu_state::Sf_irq_pending;
354 }