10 #include "member_offs.h"
12 #include "prio_list.h"
18 /** A receiver. This is a role class, and real receiver's must inherit from
19 it. The protected interface is intended for the receiver, and the public
20 interface is intended for the sender.
22 The only reason this class inherits from Context is to force a specific
23 layout for Thread. Otherwise, Receiver could just embed or reference
26 class Receiver : public Context, public Ref_cnt_obj
33 Rs_not_receiving = false,
34 Rs_ipc_receive = true,
35 Rs_irq_receive = true + 1
38 Rcv_state sender_ok(const Sender* sender) const;
40 virtual ~Receiver() {}
44 Sender* _partner; // IPC partner I'm waiting for/involved with
45 Syscall_frame *_rcv_regs; // registers used for receive
47 Iteratable_prio_list _sender_list;
50 typedef Context_ptr_base<Receiver> Receiver_ptr;
59 #include "lock_guard.h"
62 #include "thread_lock.h"
63 #include "entry_frame.h"
64 #include "std_macros.h"
65 #include "thread_state.h"
67 // Interface for receivers
70 @param thread_lock the lock used for synchronizing access to this receiver
71 @param space_context the space context
74 Receiver::Receiver(Thread_lock *thread_lock)
75 : Context(thread_lock), _caller(0)
80 Receiver::caller() const
81 { return reinterpret_cast<Receiver*>(_caller & ~0x03UL); }
85 Receiver::caller_rights() const
86 { return _caller & 0x3; }
91 Receiver::set_caller(Receiver *caller, unsigned char rights)
93 register Mword nv = Mword(caller) | (rights & 0x3);
94 reinterpret_cast<Mword volatile &>(_caller) = nv;
96 /** IPC partner (sender).
97 @return sender of ongoing or previous IPC operation
101 Receiver::partner() const
107 /** Restore a saved IPC state to restart a suspended IPC.
108 @param partner sender of suspended receive operation
109 @param regs registers of suspended receive operation
111 PROTECTED inline NEEDS[Receiver::set_partner, Receiver::set_rcv_regs]
113 Receiver::restore_receiver_state(Sender* partner, Syscall_frame* regs)
115 set_partner(partner);
119 /** Save IPC state to allow later restart a suspended IPC.
120 @param out_partner returns sender of suspended receive operation
121 @param out_regs returns pointer to IPC regs of suspended receive operation
125 Receiver::save_receiver_state(Sender** out_partner, Syscall_frame** out_regs)
127 *out_partner = _partner;
128 *out_regs = _rcv_regs;
132 // Interface for senders
134 /** Return a reference to receiver's IPC registers.
135 Senders call this function to poke values into the receiver's register set.
136 @pre state() & Thread_ipc_receiving_mask
137 @return pointer to receiver's IPC registers.
139 PUBLIC inline NEEDS[<cassert>]
141 Receiver::rcv_regs() const
143 //assert (state () & Thread_ipc_receiving_mask);
148 /** Head of sender list.
149 @return a reference to the receiver's list of senders
152 Iteratable_prio_list *
153 Receiver::sender_list()
155 return &_sender_list;
162 Receiver::set_rcv_regs(Syscall_frame* regs)
169 Receiver::set_timeout(Timeout *t)
176 Receiver::dequeue_timeout()
179 _timeout->dequeue(_timeout->has_hit());
184 Receiver::enqueue_timeout_again()
187 _timeout->set_again(current_cpu());
192 Receiver::reset_timeout()
194 if (EXPECT_TRUE(!_timeout))
201 /** Initiates a receiving IPC and updates the ipc partner.
202 @param sender the sender that wants to establish an IPC handshake
204 PUBLIC inline NEEDS [Receiver::set_partner,
206 "entry_frame.h", "sender.h", "l4_types.h"]
208 Receiver::ipc_init(Sender* sender)
211 //rcv_regs()->from (sender->id());
212 state_add_dirty(Thread_transfer_in_progress);
216 void Receiver::prepare_receive_dirty_1(Sender *partner,
219 // cpu lock required, or weird things will happen
220 assert (cpu_lock.test());
222 set_rcv_regs(regs); // message should be poked in here
223 set_partner(partner);
227 bool Receiver::prepared() const
228 { return _rcv_regs; }
232 void Receiver::prepare_receive_dirty_2()
234 // cpu lock required, or weird things will happen
235 assert (cpu_lock.test());
238 state_change_dirty(~(Thread_ipc_sending_mask | Thread_transfer_in_progress),
239 Thread_receiving | Thread_ipc_in_progress);
244 Receiver::in_ipc(Sender *sender)
246 Mword ipc_state = (state() & (Thread_ipc_in_progress
248 | Thread_transfer_in_progress));
251 ((ipc_state == (Thread_transfer_in_progress | Thread_ipc_in_progress))
252 && _partner == sender))
259 /** Set the IPC partner (sender).
260 @param partner IPC partner
264 Receiver::set_partner(Sender* partner)
269 /** Unlock a receiver locked with ipc_try_lock(). */
270 PUBLIC inline NEEDS ["thread_lock.h", "globals.h"]
272 Receiver::ipc_unlock()
274 //assert (thread_lock()->lock_owner() == current());
276 thread_lock()->clear();
281 /** Return whether the receiver is ready to accept a message from the
283 @param sender thread that wants to send a message to this receiver
284 @return true if receiver is in correct state to accept a message
285 right now (open wait, or closed wait and waiting for sender).
287 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", Receiver::partner,
288 Receiver::vcpu_async_ipc]
290 Receiver::sender_ok(const Sender *sender) const
292 unsigned ipc_state = state() & (Thread_receiving |
293 // Thread_send_in_progress |
294 Thread_ipc_in_progress);
295 // If Thread_send_in_progress is still set, we're still in the send phase
296 if (EXPECT_FALSE(ipc_state != (Thread_receiving | Thread_ipc_in_progress)))
297 return vcpu_async_ipc(sender);
299 // Check open wait; test if this sender is really the first in queue
300 if (EXPECT_TRUE(!partner()
301 && (!_sender_list.head()
302 || sender->is_head_of(&_sender_list))))
303 return Rs_ipc_receive;
305 // Check closed wait; test if this sender is really who we specified
306 if (EXPECT_TRUE(sender == partner()))
307 return Rs_ipc_receive;
309 return Rs_not_receiving;
312 /** Set up a receiving IPC.
313 @param sender 0 means any sender OK, otherwise only specified sender
315 @param regs register set that should be used as IPC registers
316 @return state bits that should be added to receiver's state word.
317 @post (sender == 0 || partner() == sender) && (receive_regs() == regs)
318 && (retval == Thread_receiving)
320 PROTECTED inline NEEDS["thread_state.h", Receiver::set_partner,
321 Receiver::set_rcv_regs]
323 Receiver::setup_receiver_state(Sender* sender, Syscall_frame* regs,
326 set_rcv_regs(regs); // message should be poked in here
328 return Thread_receiving;
331 //-----------------------------------------------------------------------------
336 Receiver::vcpu_async_ipc(Sender const *sender) const
338 if (EXPECT_FALSE(!vcpu_irqs_enabled()))
339 return Rs_not_receiving;
341 Receiver *self = const_cast<Receiver*>(this);
343 if (this == current())
344 self->spill_user_state();
346 self->vcpu_enter_kernel_mode();
348 LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
349 Vcpu_log *l = tbe->payload<Vcpu_log>();
351 l->state = vcpu_state()->_saved_state;
352 l->ip = Mword(sender);
353 l->sp = regs()->sp();
354 l->space = vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
357 self->_rcv_regs = &vcpu_state()->_ipc_regs;
358 self->vcpu_state()->_ts.set_ipc_upcall();
359 self->set_partner(const_cast<Sender*>(sender));
360 self->state_add_dirty(Thread_receiving | Thread_ipc_in_progress);
361 self->vcpu_save_state_and_upcall();
362 return Rs_irq_receive;
368 Receiver::vcpu_update_state()
370 if (EXPECT_TRUE(!(state() & Thread_vcpu_enabled)))
373 if (!sender_list()->head())
374 vcpu_state()->sticky_flags &= ~Vcpu_state::Sf_irq_pending;