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
71 : Context(), _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)
266 /** Return whether the receiver is ready to accept a message from the
268 @param sender thread that wants to send a message to this receiver
269 @return true if receiver is in correct state to accept a message
270 right now (open wait, or closed wait and waiting for sender).
272 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", Receiver::partner,
273 Receiver::vcpu_async_ipc]
275 Receiver::sender_ok(const Sender *sender) const
277 unsigned ipc_state = state() & (Thread_receiving |
278 // Thread_send_in_progress |
279 Thread_ipc_in_progress);
280 // If Thread_send_in_progress is still set, we're still in the send phase
281 if (EXPECT_FALSE(ipc_state != (Thread_receiving | Thread_ipc_in_progress)))
282 return vcpu_async_ipc(sender);
284 // Check open wait; test if this sender is really the first in queue
285 if (EXPECT_TRUE(!partner()
286 && (!_sender_list.head()
287 || sender->is_head_of(&_sender_list))))
288 return Rs_ipc_receive;
290 // Check closed wait; test if this sender is really who we specified
291 if (EXPECT_TRUE(sender == partner()))
292 return Rs_ipc_receive;
294 return Rs_not_receiving;
297 //-----------------------------------------------------------------------------
302 Receiver::vcpu_async_ipc(Sender const *sender) const
304 if (EXPECT_FALSE(state() & Thread_ipc_sending_mask))
305 return Rs_not_receiving;
307 Vcpu_state *vcpu = vcpu_state().access();
309 if (EXPECT_FALSE(!vcpu_irqs_enabled(vcpu)))
310 return Rs_not_receiving;
312 Receiver *self = const_cast<Receiver*>(this);
314 if (this == current())
315 self->spill_user_state();
317 self->vcpu_enter_kernel_mode(vcpu);
319 LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
320 Vcpu_log *l = tbe->payload<Vcpu_log>();
322 l->state = vcpu->_saved_state;
323 l->ip = Mword(sender);
324 l->sp = regs()->sp();
325 l->space = ~0; //vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
328 self->_rcv_regs = &vcpu->_ipc_regs;
329 vcpu->_ts.set_ipc_upcall();
330 self->set_partner(const_cast<Sender*>(sender));
331 self->state_add_dirty(Thread_receiving | Thread_ipc_in_progress);
332 self->vcpu_save_state_and_upcall();
333 return Rs_irq_receive;
339 Receiver::vcpu_update_state()
341 if (EXPECT_TRUE(!(state() & Thread_vcpu_enabled)))
344 if (!sender_list()->head())
345 vcpu_state().access()->sticky_flags &= ~Vcpu_state::Sf_irq_pending;
349 // --------------------------------------------------------------------------
351 struct Ipc_remote_dequeue_request
360 Receiver::handle_remote_abort_send(Drq *, Context *, void *_rq)
362 Ipc_remote_dequeue_request *rq = (Ipc_remote_dequeue_request*)_rq;
363 if (rq->sender->in_sender_list())
365 // really cancled IPC
366 rq->was_queued = true;
367 rq->sender->sender_dequeue(rq->partner->sender_list());
368 rq->partner->vcpu_update_state();
375 Receiver::abort_send(Sender *sender)
377 Ipc_remote_dequeue_request rq;
380 rq.was_queued = false;
381 current()->drq(handle_remote_abort_send, &rq);
382 return !rq.was_queued;