00001 // AUTOMATICALLY GENERATED -- DO NOT EDIT! -*- c++ -*- 00002 00003 #ifndef dirq_h 00004 #define dirq_h 00005 00006 #include "irq.h" 00007 #include "initcalls.h" 00008 #include "types.h" 00009 00010 // 00011 // INTERFACE definition follows 00012 // 00013 00014 00015 class Receiver; 00016 00017 class Dirq : public Irq 00018 { 00019 public: 00020 static void init() FIASCO_INIT; 00021 void *operator new (size_t); 00022 00023 bool alloc(Receiver *t, bool ack_in_kernel); 00024 bool free(Receiver *t); 00025 00026 private: 00027 Dirq(); 00028 Dirq(Dirq&); 00029 00030 public: 00031 explicit inline Dirq(unsigned irqnum); 00032 00033 inline void hit(); 00034 00035 void acknowledge(); 00036 }; 00037 00048 extern "C" FIASCO_FASTCALL void irq_interrupt(Mword irqnum, Mword ip); 00049 00050 // 00051 // IMPLEMENTATION includes follow (for use by inline functions) 00052 // 00053 00054 00055 #include "config.h" 00056 #include "vkey.h" 00057 #include "entry_frame.h" 00058 #include "globals.h" 00059 #include "kdb_ke.h" 00060 #include "pic.h" 00061 #include "receiver.h" 00062 #include "thread_state.h" 00063 #include "thread_lock.h" 00064 00065 // 00066 // IMPLEMENTATION of inline functions (and needed classes) 00067 // 00068 00069 00070 00071 00072 inline Dirq::Dirq(unsigned irqnum) : Irq(irqnum) 00073 {} 00074 00075 00076 00077 inline void 00078 Dirq::hit() 00079 { 00080 // We're entered holding the kernel lock, which also means irqs are 00081 // disabled on this CPU (XXX always correct?). We never enable irqs 00082 // in this stack frame (except maybe in a nonnested invocation of 00083 // switch_exec() -> switchin_context()) -- they will be re-enabled 00084 // once we return from it (iret in entry.S:all_irqs) or we switch to 00085 // a different thread. 00086 00087 if (EXPECT_FALSE (!_irq_thread)) 00088 Pic::disable_locked(id().irq()); 00089 00090 else if (EXPECT_FALSE (_irq_thread == (void*)-1)) 00091 { 00092 // debugger attached to IRQ 00093 #if defined(CONFIG_KDB) || defined(CONFIG_JDB) 00094 if (!Vkey::check_(id().irq())) 00095 kdb_ke("IRQ ENTRY"); 00096 #endif 00097 Pic::enable_locked(id().irq(), ~0U); 00098 return; 00099 } 00100 00101 else if (EXPECT_TRUE (_queued++ == 0)) // increase hit counter 00102 { 00103 set_receiver (_irq_thread); 00104 if (!Config::Irq_shortcut) 00105 { 00106 // for LIPC, we are denying LIPC send 00107 // reason: an LIPC operation always consists of a send+receive part 00108 // so we force the LIPC sender to a kernel ipc call/reply_wait 00109 // to finisch this irq IPC 00110 _irq_thread->deny_lipc_snd(); 00111 00112 // in profile mode, don't optimize 00113 // in non-profile mode, enqueue _after_ shortcut if still necessary 00114 sender_enqueue(_irq_thread->sender_list()); 00115 } 00116 00117 // if the thread is waiting for this interrupt, make it ready; 00118 // this will cause it to run irq->receiver_ready(), which 00119 // handles the rest 00120 00121 // XXX careful! This code may run in midst of an ipc_send_regs 00122 // operation (or similar)! 00123 00124 if (_irq_thread->sender_ok (this)) 00125 { 00126 if (EXPECT_TRUE 00127 (current() != _irq_thread 00128 && Context::can_preempt_current (_irq_thread->sched()) 00129 // avoid race in ipc_send_regs() after Thread_send_in_progress 00130 // flag was deleted from _irq_thread's thread state 00131 && !(_irq_thread->state() & 00132 (Thread_ready | Thread_delayed_deadline)) 00133 && !_irq_thread->thread_lock()->test() // irq_thread not locked? 00134 && !Context::schedule_in_progress())) // no schedule in progress 00135 { 00136 // we don't need to manipulate the state in a safe way 00137 // because we are still running with interrupts turned off 00138 _irq_thread->state_change_dirty(~Thread_busy, Thread_ready); 00139 00140 if (!Config::Irq_shortcut) 00141 { 00142 // no shortcut: switch to the interrupt thread which will 00143 // calls Irq::ipc_receiver_ready 00144 current()->switch_to_locked (_irq_thread); 00145 return; 00146 } 00147 00148 // The following shortcut optimization does not work if PROFILE 00149 // is defined because fast_ret_from_irq does not handle the 00150 // different implementation of the kernel lock in profiling mode 00151 00152 // At this point we are sure that the connected interrupt 00153 // thread is waiting for the next interrupt and that its 00154 // thread priority is higher than the current one. So we 00155 // choose a short cut: Instead of doing the full ipc handshake 00156 // we simply build up the return stack frame and go out as 00157 // quick as possible. 00158 // 00159 // XXX We must own the kernel lock for this optimization! 00160 00161 Sys_ipc_frame* dst_regs = _irq_thread->rcv_regs(); 00162 Mword *esp = reinterpret_cast<Mword*>(dst_regs); 00163 00164 // set return address of irq_thread 00165 *--esp = reinterpret_cast<Mword>(fast_ret_from_irq); 00166 00167 // XXX set stack pointer of irq_thread 00168 _irq_thread->set_kernel_sp(esp); 00169 00170 // set ipc return value: OK 00171 dst_regs->msg_dope(0); 00172 00173 // set ipc source thread id 00174 dst_regs->rcv_src(id()); 00175 00176 assert(_queued == 1); 00177 _queued = 0; 00178 00179 // Now that the interrupt has been delivered, it is OK for it to 00180 // occur again. 00181 maybe_enable(); 00182 00183 // ipc completed 00184 _irq_thread->deny_lipc(); 00185 _irq_thread->state_change_dirty(~Thread_ipc_mask, 0); 00186 00187 // in case a timeout was set 00188 _irq_thread->reset_timeout(); 00189 00190 // directly switch to the interrupt thread context and go out 00191 // fast using fast_ret_from_irq (implemented in assembler). 00192 // kernel-unlock is done in switch_exec() (on switchee's side). 00193 00194 // no shortcut if profiling: switch to the interrupt thread 00195 current()->switch_to_locked (_irq_thread); 00196 return; 00197 } 00198 // we don't need to manipulate the state in a safe way 00199 // because we are still running with interrupts turned off 00200 _irq_thread->deny_lipc(); 00201 _irq_thread->state_change_dirty(~Thread_busy, Thread_ready); 00202 _irq_thread->ready_enqueue(); 00203 } 00204 00205 if (Config::Irq_shortcut) 00206 // in profile mode, don't optimize 00207 // in non-profile mode, enqueue after shortcut if still necessary 00208 sender_enqueue(_irq_thread->sender_list()); 00209 } 00210 } 00211 00212 #endif // dirq_h