5 #include "member_offs.h"
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.
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
22 class Receiver : public Context, public Ref_cnt_obj
29 Rs_not_receiving = false,
30 Rs_ipc_receive = true,
31 Rs_irq_receive = true + 1
34 Rcv_state sender_ok(const Sender* sender) const;
36 virtual ~Receiver() {}
40 Sender* _partner; // IPC partner I'm waiting for/involved with
41 Syscall_frame *_rcv_regs; // registers used for receive
43 Iteratable_prio_list _sender_list;
46 typedef Context_ptr_base<Receiver> Receiver_ptr;
55 #include "lock_guard.h"
58 #include "thread_lock.h"
59 #include "entry_frame.h"
60 #include "std_macros.h"
61 #include "thread_state.h"
63 // Interface for receivers
66 @param thread_lock the lock used for synchronizing access to this receiver
67 @param space_context the space context
70 Receiver::Receiver(Thread_lock *thread_lock)
71 : Context(thread_lock), _caller(0)
76 Receiver::caller() const
77 { return reinterpret_cast<Receiver*>(_caller & ~0x03UL); }
81 Receiver::caller_rights() const
82 { return _caller & 0x3; }
87 Receiver::set_caller(Receiver *caller, unsigned char rights)
89 register Mword nv = Mword(caller) | (rights & 0x3);
90 reinterpret_cast<Mword volatile &>(_caller) = nv;
92 /** IPC partner (sender).
93 @return sender of ongoing or previous IPC operation
97 Receiver::partner() const
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
107 PROTECTED inline NEEDS[Receiver::set_partner, Receiver::set_rcv_regs]
109 Receiver::restore_receiver_state(Sender* partner, Syscall_frame* regs)
111 set_partner(partner);
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
121 Receiver::save_receiver_state(Sender** out_partner, Syscall_frame** out_regs)
123 *out_partner = _partner;
124 *out_regs = _rcv_regs;
128 // Interface for senders
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.
135 PUBLIC inline NEEDS[<cassert>]
137 Receiver::rcv_regs() const
139 //assert (state () & Thread_ipc_receiving_mask);
144 /** Head of sender list.
145 @return a reference to the receiver's list of senders
148 Iteratable_prio_list *
149 Receiver::sender_list()
151 return &_sender_list;
158 Receiver::set_rcv_regs(Syscall_frame* regs)
165 Receiver::set_timeout(Timeout *t)
172 Receiver::dequeue_timeout()
175 _timeout->dequeue(_timeout->has_hit());
180 Receiver::enqueue_timeout_again()
183 _timeout->set_again(current_cpu());
188 Receiver::reset_timeout()
190 if (EXPECT_TRUE(!_timeout))
197 /** Initiates a receiving IPC and updates the ipc partner.
198 @param sender the sender that wants to establish an IPC handshake
200 PUBLIC inline NEEDS [Receiver::set_partner,
202 "entry_frame.h", "sender.h", "l4_types.h"]
204 Receiver::ipc_init(Sender* sender)
207 //rcv_regs()->from (sender->id());
208 state_add_dirty(Thread_transfer_in_progress);
212 void Receiver::prepare_receive_dirty_1(Sender *partner,
215 // cpu lock required, or weird things will happen
216 assert (cpu_lock.test());
218 set_rcv_regs(regs); // message should be poked in here
219 set_partner(partner);
223 bool Receiver::prepared() const
224 { return _rcv_regs; }
228 void Receiver::prepare_receive_dirty_2()
230 // cpu lock required, or weird things will happen
231 assert (cpu_lock.test());
234 state_change_dirty(~(Thread_ipc_sending_mask | Thread_transfer_in_progress),
235 Thread_receiving | Thread_ipc_in_progress);
240 Receiver::in_ipc(Sender *sender)
242 Mword ipc_state = (state() & (Thread_ipc_in_progress
244 | Thread_transfer_in_progress));
247 ((ipc_state == (Thread_transfer_in_progress | Thread_ipc_in_progress))
248 && _partner == sender))
255 /** Set the IPC partner (sender).
256 @param partner IPC partner
260 Receiver::set_partner(Sender* partner)
265 /** Unlock a receiver locked with ipc_try_lock(). */
266 PUBLIC inline NEEDS ["thread_lock.h", "globals.h"]
268 Receiver::ipc_unlock()
270 //assert (thread_lock()->lock_owner() == current());
272 thread_lock()->clear();
277 /** Return whether the receiver is ready to accept a message from the
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).
283 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", Receiver::partner,
284 Receiver::vcpu_async_ipc]
286 Receiver::sender_ok(const Sender *sender) const
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);
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;
301 // Check closed wait; test if this sender is really who we specified
302 if (EXPECT_TRUE(sender == partner()))
303 return Rs_ipc_receive;
305 return Rs_not_receiving;
308 //-----------------------------------------------------------------------------
313 Receiver::vcpu_async_ipc(Sender const *sender) const
315 Vcpu_state *vcpu = access_vcpu();
317 if (EXPECT_FALSE(!vcpu_irqs_enabled(vcpu)))
318 return Rs_not_receiving;
320 Receiver *self = const_cast<Receiver*>(this);
322 if (this == current())
323 self->spill_user_state();
325 self->vcpu_enter_kernel_mode(vcpu);
327 LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
328 Vcpu_log *l = tbe->payload<Vcpu_log>();
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;
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;
347 Receiver::vcpu_update_state()
349 if (EXPECT_TRUE(!(state() & Thread_vcpu_enabled)))
352 if (!sender_list()->head())
353 access_vcpu()->sticky_flags &= ~Vcpu_state::Sf_irq_pending;