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