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_send_msg(Receiver *recv)
50 derived()->transfer_msg(recv);
51 if (derived()->dequeue_sender())
53 sender_dequeue(recv->sender_list());
54 recv->vcpu_update_state();
58 PROTECTED inline NEEDS["config.h", "globals.h", "thread_state.h"]
60 Ipc_sender_base::handle_shortcut(Syscall_frame *dst_regs,
64 ((current() != receiver
65 && receiver->sched()->deblock(current_cpu(), current()->sched(), true)
66 // avoid race in do_ipc() after Thread_send_in_progress
67 // flag was deleted from receiver's thread state
68 // also: no shortcut for alien threads, they need to see the
69 // after-syscall exception
70 && !(receiver->state()
71 & (Thread_ready_mask | Thread_alien))
72 && !current()->schedule_in_progress()))) // no schedule in progress
74 // we don't need to manipulate the state in a safe way
75 // because we are still running with interrupts turned off
76 receiver->state_add_dirty(Thread_ready);
78 if (!Config::Irq_shortcut)
80 // no shortcut: switch to the interrupt thread which will
81 // calls Irq::ipc_receiver_ready
82 current()->switch_to_locked(receiver);
86 // The following shortcut optimization does not work if PROFILE
87 // is defined because fast_ret_from_irq does not handle the
88 // different implementation of the kernel lock in profiling mode
90 // At this point we are sure that the connected interrupt
91 // thread is waiting for the next interrupt and that its
92 // thread priority is higher than the current one. So we
93 // choose a short cut: Instead of doing the full ipc handshake
94 // we simply build up the return stack frame and go out as
97 // XXX We must own the kernel lock for this optimization!
100 Mword *esp = reinterpret_cast<Mword*>(dst_regs);
102 // set return address of irq_thread
103 *--esp = reinterpret_cast<Mword>(fast_ret_from_irq);
105 // XXX set stack pointer of irq_thread
106 receiver->set_kernel_sp(esp);
108 // directly switch to the interrupt thread context and go out
109 // fast using fast_ret_from_irq (implemented in assembler).
110 // kernel-unlock is done in switch_exec() (on switchee's side).
112 // no shortcut if profiling: switch to the interrupt thread
113 current()->switch_to_locked (receiver);
120 PROTECTED template< typename Derived >
121 inline NEEDS["config.h","globals.h", "thread_state.h",
122 Ipc_sender_base::handle_shortcut]
124 Ipc_sender<Derived>::send_msg(Receiver *receiver)
126 set_receiver(receiver);
128 if (!Config::Irq_shortcut)
130 // in profile mode, don't optimize
131 // in non-profile mode, enqueue _after_ shortcut if still necessary
132 sender_enqueue(receiver->sender_list(), 255);
133 receiver->vcpu_set_irq_pending();
136 // if the thread is waiting for this interrupt, make it ready;
137 // this will cause it to run irq->receiver_ready(), which
140 // XXX careful! This code may run in midst of an do_ipc()
141 // operation (or similar)!
142 if (Receiver::Rcv_state s = receiver->sender_ok(this))
144 Syscall_frame *dst_regs = derived()->transfer_msg(receiver);
146 if (derived()->requeue_sender())
148 sender_enqueue(receiver->sender_list(), 255);
149 receiver->vcpu_set_irq_pending();
153 receiver->state_change_dirty(~Thread_ipc_mask, 0);
155 // in case a timeout was set
156 receiver->reset_timeout();
158 if (s == Receiver::Rs_ipc_receive)
160 if (handle_shortcut(dst_regs, receiver))
163 // we don't need to manipulate the state in a safe way
164 // because we are still running with interrupts turned off
165 receiver->state_add_dirty(Thread_ready);
166 receiver->sched()->deblock(receiver->cpu());
170 if (Config::Irq_shortcut)
172 // in profile mode, don't optimize
173 // in non-profile mode, enqueue after shortcut if still necessary
174 sender_enqueue(receiver->sender_list(), 255);
175 receiver->vcpu_set_irq_pending();