Main Page | Modules | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

dirq.h

Go to the documentation of this file.
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

Generated on Mon Sep 26 14:20:10 2005 for Fiasco by  doxygen 1.4.2