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