10 #include "member_offs.h"
12 #include "prio_list.h"
19 /** A receiver. This is a role class, and real receiver's must inherit from
20 it. The protected interface is intended for the receiver, and the public
21 interface is intended for the sender.
23 The only reason this class inherits from Context is to force a specific
24 layout for Thread. Otherwise, Receiver could just embed or reference
27 class Receiver : public Context, public Ref_cnt_obj
34 Rs_not_receiving = false,
35 Rs_ipc_receive = true,
36 Rs_irq_receive = true + 1
39 Rcv_state sender_ok(const Sender* sender) const;
41 virtual ~Receiver() {}
45 Sender* _partner; // IPC partner I'm waiting for/involved with
46 Syscall_frame *_rcv_regs; // registers used for receive
48 Iteratable_prio_list _sender_list;
51 typedef Context_ptr_base<Receiver> Receiver_ptr;
60 #include "lock_guard.h"
63 #include "thread_lock.h"
64 #include "entry_frame.h"
65 #include "std_macros.h"
66 #include "thread_state.h"
68 // Interface for receivers
71 @param thread_lock the lock used for synchronizing access to this receiver
72 @param space_context the space context
75 Receiver::Receiver(Thread_lock *thread_lock)
76 : Context(thread_lock), _caller(0)
81 Receiver::caller() const
82 { return reinterpret_cast<Receiver*>(_caller & ~0x03UL); }
86 Receiver::caller_rights() const
87 { return _caller & 0x3; }
92 Receiver::set_caller(Receiver *caller, unsigned char rights)
94 register Mword nv = Mword(caller) | (rights & 0x3);
95 reinterpret_cast<Mword volatile &>(_caller) = nv;
97 /** IPC partner (sender).
98 @return sender of ongoing or previous IPC operation
102 Receiver::partner() const
108 /** Restore a saved IPC state to restart a suspended IPC.
109 @param partner sender of suspended receive operation
110 @param regs registers of suspended receive operation
112 PROTECTED inline NEEDS[Receiver::set_partner, Receiver::set_rcv_regs]
114 Receiver::restore_receiver_state(Sender* partner, Syscall_frame* regs)
116 set_partner(partner);
120 /** Save IPC state to allow later restart a suspended IPC.
121 @param out_partner returns sender of suspended receive operation
122 @param out_regs returns pointer to IPC regs of suspended receive operation
126 Receiver::save_receiver_state(Sender** out_partner, Syscall_frame** out_regs)
128 *out_partner = _partner;
129 *out_regs = _rcv_regs;
133 // Interface for senders
135 /** Return a reference to receiver's IPC registers.
136 Senders call this function to poke values into the receiver's register set.
137 @pre state() & Thread_ipc_receiving_mask
138 @return pointer to receiver's IPC registers.
140 PUBLIC inline NEEDS[<cassert>]
142 Receiver::rcv_regs() const
144 //assert (state () & Thread_ipc_receiving_mask);
149 /** Head of sender list.
150 @return a reference to the receiver's list of senders
153 Iteratable_prio_list *
154 Receiver::sender_list()
156 return &_sender_list;
163 Receiver::set_rcv_regs(Syscall_frame* regs)
170 Receiver::set_timeout(Timeout *t)
177 Receiver::dequeue_timeout()
180 _timeout->dequeue(_timeout->has_hit());
185 Receiver::enqueue_timeout_again()
188 _timeout->set_again(current_cpu());
193 Receiver::reset_timeout()
195 if (EXPECT_TRUE(!_timeout))
202 /** Initiates a receiving IPC and updates the ipc partner.
203 @param sender the sender that wants to establish an IPC handshake
205 PUBLIC inline NEEDS [Receiver::set_partner,
207 "entry_frame.h", "sender.h", "l4_types.h"]
209 Receiver::ipc_init(Sender* sender)
212 //rcv_regs()->from (sender->id());
213 state_add_dirty(Thread_transfer_in_progress);
217 void Receiver::prepare_receive_dirty_1(Sender *partner,
220 // cpu lock required, or weird things will happen
221 assert (cpu_lock.test());
223 set_rcv_regs(regs); // message should be poked in here
224 set_partner(partner);
228 bool Receiver::prepared() const
229 { return _rcv_regs; }
233 void Receiver::prepare_receive_dirty_2()
235 // cpu lock required, or weird things will happen
236 assert (cpu_lock.test());
239 state_change_dirty(~(Thread_ipc_sending_mask | Thread_transfer_in_progress),
240 Thread_receiving | Thread_ipc_in_progress);
245 Receiver::in_ipc(Sender *sender)
247 Mword ipc_state = (state() & (Thread_ipc_in_progress
249 | Thread_transfer_in_progress));
252 ((ipc_state == (Thread_transfer_in_progress | Thread_ipc_in_progress))
253 && _partner == sender))
260 /** Set the IPC partner (sender).
261 @param partner IPC partner
265 Receiver::set_partner(Sender* partner)
270 /** Unlock a receiver locked with ipc_try_lock(). */
271 PUBLIC inline NEEDS ["thread_lock.h", "globals.h"]
273 Receiver::ipc_unlock()
275 //assert (thread_lock()->lock_owner() == current());
277 thread_lock()->clear();
282 /** Return whether the receiver is ready to accept a message from the
284 @param sender thread that wants to send a message to this receiver
285 @return true if receiver is in correct state to accept a message
286 right now (open wait, or closed wait and waiting for sender).
288 IMPLEMENT inline NEEDS["std_macros.h", "thread_state.h", Receiver::partner,
289 Receiver::vcpu_async_ipc]
291 Receiver::sender_ok(const Sender *sender) const
293 unsigned ipc_state = state() & (Thread_receiving |
294 // Thread_send_in_progress |
295 Thread_ipc_in_progress);
296 // If Thread_send_in_progress is still set, we're still in the send phase
297 if (EXPECT_FALSE(ipc_state != (Thread_receiving | Thread_ipc_in_progress)))
298 return vcpu_async_ipc(sender);
300 // Check open wait; test if this sender is really the first in queue
301 if (EXPECT_TRUE(!partner()
302 && (!_sender_list.head()
303 || sender->is_head_of(&_sender_list))))
304 return Rs_ipc_receive;
306 // Check closed wait; test if this sender is really who we specified
307 if (EXPECT_TRUE(sender == partner()))
308 return Rs_ipc_receive;
310 return Rs_not_receiving;
313 /** Set up a receiving IPC.
314 @param sender 0 means any sender OK, otherwise only specified sender
316 @param regs register set that should be used as IPC registers
317 @return state bits that should be added to receiver's state word.
318 @post (sender == 0 || partner() == sender) && (receive_regs() == regs)
319 && (retval == Thread_receiving)
321 PROTECTED inline NEEDS["thread_state.h", Receiver::set_partner,
322 Receiver::set_rcv_regs]
324 Receiver::setup_receiver_state(Sender* sender, Syscall_frame* regs,
327 set_rcv_regs(regs); // message should be poked in here
329 return Thread_receiving;
332 //-----------------------------------------------------------------------------
337 Receiver::vcpu_async_ipc(Sender const *sender) const
339 if (EXPECT_FALSE(!vcpu_irqs_enabled()))
340 return Rs_not_receiving;
342 Receiver *self = const_cast<Receiver*>(this);
344 if (this == current())
345 self->spill_user_state();
347 self->vcpu_enter_kernel_mode();
349 LOG_TRACE("VCPU events", "vcpu", this, __context_vcpu_log_fmt,
350 Vcpu_log *l = tbe->payload<Vcpu_log>();
352 l->state = vcpu_state()->_saved_state;
353 l->ip = Mword(sender);
354 l->sp = regs()->sp();
355 l->space = vcpu_user_space() ? static_cast<Task*>(vcpu_user_space())->dbg_id() : ~0;
358 self->_rcv_regs = &vcpu_state()->_ipc_regs;
359 self->vcpu_state()->_ts.set_ipc_upcall();
360 self->set_partner(const_cast<Sender*>(sender));
361 self->state_add_dirty(Thread_receiving | Thread_ipc_in_progress);
362 self->vcpu_save_state_and_upcall();
363 return Rs_irq_receive;
369 Receiver::vcpu_update_state()
371 if (EXPECT_TRUE(!(state() & Thread_vcpu_enabled)))
374 if (!sender_list()->head())
375 vcpu_state()->sticky_flags &= ~Vcpu_state::Sf_irq_pending;