6 class Ipc_sender_base : public Sender
10 template< typename Derived >
11 class Ipc_sender : public Ipc_sender_base
14 Derived *derived() { return static_cast<Derived*>(this); }
15 static bool dequeue_sender() { return true; }
16 static bool requeue_sender() { return false; }
19 extern "C" void fast_ret_from_irq(void);
24 #include "entry_frame.h"
27 #include "thread_state.h"
32 Ipc_sender_base::ipc_receiver_aborted()
36 sender_dequeue(receiver()->sender_list());
37 receiver()->vcpu_update_state();
41 /** Sender-activation function called when receiver gets ready.
42 Irq::hit() actually ensures that this method is always called
43 when an interrupt occurs, even when the receiver was already
46 PUBLIC template< typename Derived >
48 Ipc_sender<Derived>::ipc_receiver_ready(Receiver *recv)
50 // we are running with ints off
51 assert_kdb(current()->state() & Thread_ready);
52 assert_kdb(current() == recv);
54 if(!recv->sender_ok(this))
57 recv->vcpu_disable_irqs();
61 derived()->transfer_msg(recv);
63 recv->state_change(~(Thread_receiving
64 | Thread_transfer_in_progress
65 | Thread_ipc_in_progress),
68 if (derived()->dequeue_sender()) // last interrupt in queue?
70 sender_dequeue(recv->sender_list());
71 recv->vcpu_update_state();
74 // else remain queued if more interrupts are left
78 PROTECTED inline NEEDS["config.h", "globals.h", "thread_state.h"]
80 Ipc_sender_base::handle_shortcut(Syscall_frame *dst_regs,
84 ((current() != receiver
85 && receiver->sched()->deblock(current_cpu(), current()->sched(), true)
86 // avoid race in do_ipc() after Thread_send_in_progress
87 // flag was deleted from receiver's thread state
88 // also: no shortcut for alien threads, they need to see the
89 // after-syscall exception
90 && !(receiver->state()
91 & (Thread_ready_mask | Thread_delayed_deadline | Thread_alien))
92 && !current()->schedule_in_progress()))) // no schedule in progress
94 // we don't need to manipulate the state in a safe way
95 // because we are still running with interrupts turned off
96 receiver->state_add_dirty(Thread_ready);
98 if (!Config::Irq_shortcut)
100 // no shortcut: switch to the interrupt thread which will
101 // calls Irq::ipc_receiver_ready
102 current()->switch_to_locked(receiver);
106 // The following shortcut optimization does not work if PROFILE
107 // is defined because fast_ret_from_irq does not handle the
108 // different implementation of the kernel lock in profiling mode
110 // At this point we are sure that the connected interrupt
111 // thread is waiting for the next interrupt and that its
112 // thread priority is higher than the current one. So we
113 // choose a short cut: Instead of doing the full ipc handshake
114 // we simply build up the return stack frame and go out as
115 // quick as possible.
117 // XXX We must own the kernel lock for this optimization!
120 Mword *esp = reinterpret_cast<Mword*>(dst_regs);
122 // set return address of irq_thread
123 *--esp = reinterpret_cast<Mword>(fast_ret_from_irq);
125 // XXX set stack pointer of irq_thread
126 receiver->set_kernel_sp(esp);
128 // directly switch to the interrupt thread context and go out
129 // fast using fast_ret_from_irq (implemented in assembler).
130 // kernel-unlock is done in switch_exec() (on switchee's side).
132 // no shortcut if profiling: switch to the interrupt thread
133 current()->switch_to_locked (receiver);
140 PROTECTED template< typename Derived >
141 inline NEEDS["config.h","globals.h", "thread_state.h",
142 Ipc_sender_base::handle_shortcut]
144 Ipc_sender<Derived>::send_msg(Receiver *receiver)
146 set_receiver(receiver);
148 if (!Config::Irq_shortcut)
150 // in profile mode, don't optimize
151 // in non-profile mode, enqueue _after_ shortcut if still necessary
152 sender_enqueue(receiver->sender_list(), 255);
153 receiver->vcpu_set_irq_pending();
156 // if the thread is waiting for this interrupt, make it ready;
157 // this will cause it to run irq->receiver_ready(), which
160 // XXX careful! This code may run in midst of an do_ipc()
161 // operation (or similar)!
162 if (Receiver::Rcv_state s = receiver->sender_ok(this))
164 Syscall_frame *dst_regs = derived()->transfer_msg(receiver);
166 if (derived()->requeue_sender())
168 sender_enqueue(receiver->sender_list(), 255);
169 receiver->vcpu_set_irq_pending();
173 receiver->state_change_dirty(~Thread_ipc_mask, 0);
175 // in case a timeout was set
176 receiver->reset_timeout();
178 if (s == Receiver::Rs_ipc_receive)
180 if (handle_shortcut(dst_regs, receiver))
183 // we don't need to manipulate the state in a safe way
184 // because we are still running with interrupts turned off
185 receiver->state_add_dirty(Thread_ready);
186 receiver->sched()->deblock(receiver->cpu());
190 if (Config::Irq_shortcut)
192 // in profile mode, don't optimize
193 // in non-profile mode, enqueue after shortcut if still necessary
194 sender_enqueue(receiver->sender_list(), 255);
195 receiver->vcpu_set_irq_pending();