]> 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   enum Abort_state
35   {
36     Abt_ipc_done,
37     Abt_ipc_cancel,
38     Abt_ipc_in_progress,
39   };
40
41   Rcv_state sender_ok(const Sender* sender) const;
42
43   virtual ~Receiver() {}
44
45 private:
46   // DATA
47   Sender*           _partner;   // IPC partner I'm waiting for/involved with
48   Syscall_frame    *_rcv_regs; // registers used for receive
49   Mword _caller;
50   Iteratable_prio_list         _sender_list;
51 };
52
53 typedef Context_ptr_base<Receiver> Receiver_ptr;
54
55 IMPLEMENTATION:
56
57 #include "l4_types.h"
58 #include <cassert>
59
60 #include "cpu_lock.h"
61 #include "globals.h"
62 #include "lock_guard.h"
63 #include "logdefs.h"
64 #include "sender.h"
65 #include "thread_lock.h"
66 #include "entry_frame.h"
67 #include "std_macros.h"
68 #include "thread_state.h"
69
70 // Interface for receivers
71
72 /** Constructor.
73     @param thread_lock the lock used for synchronizing access to this receiver
74     @param space_context the space context 
75  */
76 PROTECTED inline
77 Receiver::Receiver()
78 : Context(), _caller(0)
79 {}
80
81 PUBLIC inline
82 Receiver *
83 Receiver::caller() const
84 { return reinterpret_cast<Receiver*>(_caller & ~0x03UL); }
85
86 PUBLIC inline
87 unsigned char
88 Receiver::caller_rights() const
89 { return _caller & 0x3; }
90
91
92 PUBLIC inline
93 void
94 Receiver::set_caller(Receiver *caller, unsigned char rights)
95 {
96   register Mword nv = Mword(caller) | (rights & 0x3);
97   reinterpret_cast<Mword volatile &>(_caller) = nv;
98 }
99 /** IPC partner (sender).
100     @return sender of ongoing or previous IPC operation
101  */
102 PROTECTED inline
103 Sender*
104 Receiver::partner() const
105 {
106   return _partner;
107 }
108
109
110 // Interface for senders
111
112 /** Return a reference to receiver's IPC registers.
113     Senders call this function to poke values into the receiver's register set.
114     @pre state() & Thread_ipc_receiving_mask
115     @return pointer to receiver's IPC registers.
116  */
117 PUBLIC inline NEEDS[<cassert>]
118 Syscall_frame*
119 Receiver::rcv_regs() const
120 {
121   //assert (state () & Thread_ipc_receiving_mask);
122
123   return _rcv_regs;
124 }
125
126 /** Head of sender list.
127     @return a reference to the receiver's list of senders
128  */
129 PUBLIC inline
130 Iteratable_prio_list *
131 Receiver::sender_list()
132 {
133   return &_sender_list;
134 }
135
136 // MANIPULATORS
137
138 PROTECTED inline
139 void
140 Receiver::set_rcv_regs(Syscall_frame* regs)
141 {
142   _rcv_regs = regs;
143 }
144
145 PUBLIC inline
146 void
147 Receiver::set_timeout(Timeout *t)
148 {
149   _timeout = t;
150 }
151
152 PUBLIC inline
153 void
154 Receiver::dequeue_timeout()
155 {
156   if (_timeout)
157     _timeout->dequeue(_timeout->has_hit());
158 }
159
160 PUBLIC inline
161 void
162 Receiver::enqueue_timeout_again()
163 {
164   if (_timeout)
165     _timeout->set_again(current_cpu());
166 }
167
168 PUBLIC inline
169 void
170 Receiver::reset_timeout()
171 {
172   if (EXPECT_TRUE(!_timeout))
173     return;
174
175   _timeout->reset();
176   _timeout = 0;
177 }
178
179 PROTECTED inline
180 void Receiver::prepare_receive(Sender *partner, Syscall_frame *regs)
181 {
182   set_rcv_regs(regs);  // message should be poked in here
183   set_partner(partner);
184 }
185
186 PROTECTED inline
187 bool Receiver::prepared() const
188 { return _rcv_regs; }
189
190 /** Set the IPC partner (sender).
191     @param partner IPC partner
192  */
193 PUBLIC inline
194 void
195 Receiver::set_partner(Sender* partner)
196 {
197   _partner = partner;
198 }
199
200 PUBLIC inline
201 bool
202 Receiver::in_ipc(Sender *sender)
203 {
204   return (state() & Thread_receive_in_progress) && (partner() == sender);
205 }
206
207
208 /** Return whether the receiver is ready to accept a message from the
209     given sender.
210     @param sender thread that wants to send a message to this receiver
211     @return true if receiver is in correct state to accept a message 
212                  right now (open wait, or closed wait and waiting for sender).
213  */
214 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", "sender.h",
215                        Receiver::partner, Receiver::vcpu_async_ipc]
216 Receiver::Rcv_state
217 Receiver::sender_ok(const Sender *sender) const
218 {
219   unsigned ipc_state = state() & Thread_ipc_mask;
220
221   // If Thread_send_in_progress is still set, we're still in the send phase
222   if (EXPECT_FALSE(ipc_state != Thread_receive_wait))
223     return vcpu_async_ipc(sender);
224
225   // Check open wait; test if this sender is really the first in queue
226   if (EXPECT_TRUE(!partner()
227                   && (!_sender_list.head()
228                     || sender->is_head_of(&_sender_list))))
229     return Rs_ipc_receive;
230
231   // Check closed wait; test if this sender is really who we specified
232   if (EXPECT_TRUE(sender == partner()))
233     return Rs_ipc_receive;
234
235   return Rs_not_receiving;
236 }
237
238 //-----------------------------------------------------------------------------
239 // VCPU code:
240
241 PRIVATE inline
242 Receiver::Rcv_state
243 Receiver::vcpu_async_ipc(Sender const *sender) const
244 {
245   if (EXPECT_FALSE(state() & Thread_ipc_mask))
246     return Rs_not_receiving;
247
248   Vcpu_state *vcpu = vcpu_state().access();
249
250   if (EXPECT_FALSE(!vcpu_irqs_enabled(vcpu)))
251     return Rs_not_receiving;
252
253   Receiver *self = const_cast<Receiver*>(this);
254
255   if (this == current())
256     self->spill_user_state();
257
258   if (self->vcpu_enter_kernel_mode(vcpu))
259     vcpu = vcpu_state().access();
260
261   LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
262       Vcpu_log *l = tbe->payload<Vcpu_log>();
263       l->type = 1;
264       l->state = vcpu->_saved_state;
265       l->ip = Mword(sender);
266       l->sp = regs()->sp();
267       l->space = ~0; //vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
268       );
269
270   self->_rcv_regs = &vcpu->_ipc_regs;
271   vcpu->_ts.set_ipc_upcall();
272   self->set_partner(const_cast<Sender*>(sender));
273   self->state_add_dirty(Thread_receive_wait);
274   self->vcpu_save_state_and_upcall();
275   return Rs_irq_receive;
276 }
277
278
279 PUBLIC inline
280 void
281 Receiver::vcpu_update_state()
282 {
283   if (EXPECT_TRUE(!(state() & Thread_vcpu_enabled)))
284     return;
285
286   if (!sender_list()->head())
287     vcpu_state().access()->sticky_flags &= ~Vcpu_state::Sf_irq_pending;
288 }
289
290
291 // --------------------------------------------------------------------------
292
293 struct Ipc_remote_dequeue_request
294 {
295   Receiver *partner;
296   Sender *sender;
297   Receiver::Abort_state state;
298 };
299
300 PRIVATE static
301 unsigned
302 Receiver::handle_remote_abort_send(Drq *, Context *, void *_rq)
303 {
304   Ipc_remote_dequeue_request *rq = (Ipc_remote_dequeue_request*)_rq;
305   if (rq->sender->in_sender_list())
306     {
307       // really cancled IPC
308       rq->state = Abt_ipc_cancel;
309       rq->sender->sender_dequeue(rq->partner->sender_list());
310       rq->partner->vcpu_update_state();
311     }
312   else if (rq->partner->in_ipc(rq->sender))
313     rq->state = Abt_ipc_in_progress;
314   return 0;
315 }
316
317 PUBLIC
318 Receiver::Abort_state
319 Receiver::abort_send(Sender *sender)
320 {
321   Ipc_remote_dequeue_request rq;
322   rq.partner = this;
323   rq.sender = sender;
324   rq.state = Abt_ipc_done;
325   if (current_cpu() != cpu())
326     drq(handle_remote_abort_send, &rq);
327   else
328     handle_remote_abort_send(0, 0, &rq);
329   return rq.state;
330 }
331