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
41 Rcv_state sender_ok(const Sender* sender) const;
43 virtual ~Receiver() = 0;
47 Sender *_partner; // IPC partner I'm waiting for/involved with
48 Syscall_frame *_rcv_regs; // registers used for receive
50 Iteratable_prio_list _sender_list;
53 typedef Context_ptr_base<Receiver> Receiver_ptr;
62 #include "lock_guard.h"
65 #include "thread_lock.h"
66 #include "entry_frame.h"
67 #include "std_macros.h"
68 #include "thread_state.h"
70 // Interface for receivers
72 IMPLEMENT inline Receiver::~Receiver() {}
74 @param thread_lock the lock used for synchronizing access to this receiver
75 @param space_context the space context
79 : Context(), _caller(0)
84 Receiver::caller() const
85 { return reinterpret_cast<Receiver*>(_caller & ~0x03UL); }
89 Receiver::caller_rights() const
90 { return _caller & 0x3; }
95 Receiver::set_caller(Receiver *caller, unsigned char rights)
97 register Mword nv = Mword(caller) | (rights & 0x3);
98 reinterpret_cast<Mword volatile &>(_caller) = nv;
100 /** IPC partner (sender).
101 @return sender of ongoing or previous IPC operation
105 Receiver::partner() const
111 // Interface for senders
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.
118 PUBLIC inline NEEDS[<cassert>]
120 Receiver::rcv_regs() const
122 //assert (state () & Thread_ipc_receiving_mask);
127 /** Head of sender list.
128 @return a reference to the receiver's list of senders
131 Iteratable_prio_list *
132 Receiver::sender_list()
134 return &_sender_list;
141 Receiver::set_rcv_regs(Syscall_frame* regs)
148 Receiver::set_timeout(Timeout *t)
155 Receiver::dequeue_timeout()
158 _timeout->dequeue(_timeout->has_hit());
163 Receiver::enqueue_timeout_again()
166 _timeout->set_again(cpu());
171 Receiver::reset_timeout()
173 if (EXPECT_TRUE(!_timeout))
181 void Receiver::prepare_receive(Sender *partner, Syscall_frame *regs)
183 set_rcv_regs(regs); // message should be poked in here
184 set_partner(partner);
188 bool Receiver::prepared() const
189 { return _rcv_regs; }
191 /** Set the IPC partner (sender).
192 @param partner IPC partner
196 Receiver::set_partner(Sender* partner)
203 Receiver::in_ipc(Sender *sender)
205 return (state() & Thread_receive_in_progress) && (partner() == sender);
209 /** Return whether the receiver is ready to accept a message from the
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).
215 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", "sender.h",
216 Receiver::partner, Receiver::vcpu_async_ipc]
218 Receiver::sender_ok(const Sender *sender) const
220 unsigned ipc_state = state() & Thread_ipc_mask;
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);
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;
232 // Check closed wait; test if this sender is really who we specified
233 if (EXPECT_TRUE(sender == partner()))
234 return Rs_ipc_receive;
236 return Rs_not_receiving;
239 //-----------------------------------------------------------------------------
244 Receiver::vcpu_async_ipc(Sender const *sender) const
246 if (EXPECT_FALSE(state() & Thread_ipc_mask))
247 return Rs_not_receiving;
249 Vcpu_state *vcpu = vcpu_state().access();
251 if (EXPECT_FALSE(!vcpu_irqs_enabled(vcpu)))
252 return Rs_not_receiving;
254 Receiver *self = const_cast<Receiver*>(this);
256 if (this == current())
257 self->spill_user_state();
259 if (self->vcpu_enter_kernel_mode(vcpu))
260 vcpu = vcpu_state().access();
262 LOG_TRACE("VCPU events", "vcpu", this, Vcpu_log,
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;
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;
281 Receiver::vcpu_update_state()
283 if (EXPECT_TRUE(!(state() & Thread_vcpu_enabled)))
286 if (sender_list()->empty())
287 vcpu_state().access()->sticky_flags &= ~Vcpu_state::Sf_irq_pending;
291 // --------------------------------------------------------------------------
293 struct Ipc_remote_dequeue_request
297 Receiver::Abort_state state;
302 Receiver::handle_remote_abort_send(Drq *, Context *, void *_rq)
304 Ipc_remote_dequeue_request *rq = (Ipc_remote_dequeue_request*)_rq;
305 if (rq->sender->in_sender_list())
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();
312 else if (rq->partner->in_ipc(rq->sender))
313 rq->state = Abt_ipc_in_progress;
318 Receiver::Abort_state
319 Receiver::abort_send(Sender *sender)
321 Ipc_remote_dequeue_request rq;
324 rq.state = Abt_ipc_done;
325 if (current_cpu() != cpu())
326 drq(handle_remote_abort_send, &rq);
328 handle_remote_abort_send(0, 0, &rq);