]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/receiver.cpp
8ce4c366d88e216ab07e488404423ee82d34a714
[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() = 0;
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 IMPLEMENT inline Receiver::~Receiver() {}
73 /** Constructor.
74     @param thread_lock the lock used for synchronizing access to this receiver
75     @param space_context the space context 
76  */
77 PROTECTED inline
78 Receiver::Receiver()
79 : Context(), _caller(0)
80 {}
81
82 PUBLIC inline
83 Receiver *
84 Receiver::caller() const
85 { return reinterpret_cast<Receiver*>(_caller & ~0x03UL); }
86
87 PUBLIC inline
88 unsigned char
89 Receiver::caller_rights() const
90 { return _caller & 0x3; }
91
92
93 PUBLIC inline
94 void
95 Receiver::set_caller(Receiver *caller, unsigned char rights)
96 {
97   register Mword nv = Mword(caller) | (rights & 0x3);
98   reinterpret_cast<Mword volatile &>(_caller) = nv;
99 }
100 /** IPC partner (sender).
101     @return sender of ongoing or previous IPC operation
102  */
103 PROTECTED inline
104 Sender*
105 Receiver::partner() const
106 {
107   return _partner;
108 }
109
110
111 // Interface for senders
112
113 /** Return a reference to receiver's IPC registers.
114     Senders call this function to poke values into the receiver's register set.
115     @pre state() & Thread_ipc_receiving_mask
116     @return pointer to receiver's IPC registers.
117  */
118 PUBLIC inline NEEDS[<cassert>]
119 Syscall_frame*
120 Receiver::rcv_regs() const
121 {
122   //assert (state () & Thread_ipc_receiving_mask);
123
124   return _rcv_regs;
125 }
126
127 /** Head of sender list.
128     @return a reference to the receiver's list of senders
129  */
130 PUBLIC inline
131 Iteratable_prio_list *
132 Receiver::sender_list()
133 {
134   return &_sender_list;
135 }
136
137 // MANIPULATORS
138
139 PROTECTED inline
140 void
141 Receiver::set_rcv_regs(Syscall_frame* regs)
142 {
143   _rcv_regs = regs;
144 }
145
146 PUBLIC inline
147 void
148 Receiver::set_timeout(Timeout *t)
149 {
150   _timeout = t;
151 }
152
153 PUBLIC inline
154 void
155 Receiver::dequeue_timeout()
156 {
157   if (_timeout)
158     _timeout->dequeue(_timeout->has_hit());
159 }
160
161 PUBLIC inline
162 void
163 Receiver::enqueue_timeout_again()
164 {
165   if (_timeout)
166     _timeout->set_again(cpu());
167 }
168
169 PUBLIC inline
170 void
171 Receiver::reset_timeout()
172 {
173   if (EXPECT_TRUE(!_timeout))
174     return;
175
176   _timeout->reset();
177   _timeout = 0;
178 }
179
180 PROTECTED inline
181 void Receiver::prepare_receive(Sender *partner, Syscall_frame *regs)
182 {
183   set_rcv_regs(regs);  // message should be poked in here
184   set_partner(partner);
185 }
186
187 PROTECTED inline
188 bool Receiver::prepared() const
189 { return _rcv_regs; }
190
191 /** Set the IPC partner (sender).
192     @param partner IPC partner
193  */
194 PUBLIC inline
195 void
196 Receiver::set_partner(Sender* partner)
197 {
198   _partner = partner;
199 }
200
201 PUBLIC inline
202 bool
203 Receiver::in_ipc(Sender *sender)
204 {
205   return (state() & Thread_receive_in_progress) && (partner() == sender);
206 }
207
208
209 /** Return whether the receiver is ready to accept a message from the
210     given sender.
211     @param sender thread that wants to send a message to this receiver
212     @return true if receiver is in correct state to accept a message 
213                  right now (open wait, or closed wait and waiting for sender).
214  */
215 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", "sender.h",
216                        Receiver::partner, Receiver::vcpu_async_ipc]
217 Receiver::Rcv_state
218 Receiver::sender_ok(const Sender *sender) const
219 {
220   unsigned ipc_state = state() & Thread_ipc_mask;
221
222   // If Thread_send_in_progress is still set, we're still in the send phase
223   if (EXPECT_FALSE(ipc_state != Thread_receive_wait))
224     return vcpu_async_ipc(sender);
225
226   // Check open wait; test if this sender is really the first in queue
227   if (EXPECT_TRUE(!partner()
228                   && (_sender_list.empty()
229                     || sender->is_head_of(&_sender_list))))
230     return Rs_ipc_receive;
231
232   // Check closed wait; test if this sender is really who we specified
233   if (EXPECT_TRUE(sender == partner()))
234     return Rs_ipc_receive;
235
236   return Rs_not_receiving;
237 }
238
239 //-----------------------------------------------------------------------------
240 // VCPU code:
241
242 PRIVATE inline
243 Receiver::Rcv_state
244 Receiver::vcpu_async_ipc(Sender const *sender) const
245 {
246   if (EXPECT_FALSE(state() & Thread_ipc_mask))
247     return Rs_not_receiving;
248
249   Vcpu_state *vcpu = vcpu_state().access();
250
251   if (EXPECT_FALSE(!vcpu_irqs_enabled(vcpu)))
252     return Rs_not_receiving;
253
254   Receiver *self = const_cast<Receiver*>(this);
255
256   if (this == current())
257     self->spill_user_state();
258
259   if (self->vcpu_enter_kernel_mode(vcpu))
260     vcpu = vcpu_state().access();
261
262   LOG_TRACE("VCPU events", "vcpu", this, 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()->empty())
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