/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: IoIrq.cs // //#define DEBUG_DISPATCH_IO using System; using System.Runtime.CompilerServices; using System.Threading; using Microsoft.Singularity.Hal; namespace Microsoft.Singularity.Io { [CLSCompliant(false)] public sealed class IoIrq { private readonly byte irq; private InterruptAwareAutoResetEvent! signal; private IoIrq next; private bool registered; ////////////////////////////////////////////////////////////////////// // // private const int MaxInterrupts = 256; private static IoIrq[]! irqTable; private static SpinLock regLock; static IoIrq() { irqTable = new IoIrq [MaxInterrupts]; regLock = new SpinLock(SpinLock.Types.IoIrq); } [NoHeapAllocation] private static bool AcquireLock() { bool enabled = Processor.DisableInterrupts(); #if SINGULARITY_MP regLock.Acquire(); #endif // SINGULARITY_MP return enabled; } [NoHeapAllocation] private static void ReleaseLock(bool enabled) { #if SINGULARITY_MP regLock.Release(); #endif // SINGULARITY_MP Processor.RestoreInterrupts(enabled); } // This doesn't need a lock because Register and Release // insure that the list is *always* valid (even when being updated). [NoHeapAllocation] public static void SignalInterrupt(byte irq) { #if DEBUG_DISPATCH_IO DebugStub.WriteLine("++ SetInterruptEvent: Irq={0:x2}", __arglist(irq)); #endif for (IoIrq step = irqTable[irq]; step != null; step = step.next) { step.signal.InterruptAwareSet(); } } public IoIrq(byte irq) { this.irq = irq; this.next = null; this.signal = new InterruptAwareAutoResetEvent(false); this.registered = false; } public byte Irq { [NoHeapAllocation] get { return irq; } } // Insert the IoIrq into the linked list for this irq. // If it is the first entry, then notify HAL to enable its irq. // Returns true if this IoIrq caused the irq to be enabled. public bool RegisterInterrupt() { bool enabled = AcquireLock(); try { Tracing.Log(Tracing.Debug, "Register Irq={0:x2}", irq); #if DEBUG_DISPATCH_IO DebugStub.WriteLine("++ Register Irq={0:x2}", __arglist(irq)); #endif this.next = irqTable[irq]; irqTable[irq] = this; this.registered = true; if (next == null) { Platform.EnableIoInterrupt(irq); return true; } } finally { ReleaseLock(enabled); } return false; } // Remove the IoIrq into the linked list for this irq. // If it is the last entry, then notify HAL to disable its irq. // Returns true if this IoIrq caused the irq to be disabled. public bool ReleaseInterrupt() { bool enabled = AcquireLock(); try { Tracing.Log(Tracing.Debug, "Release Irq={0:x2}", irq); #if DEBUG_DISPATCH_IO DebugStub.WriteLine("++ Release Irq={0:x2}", __arglist(irq)); #endif if (irqTable[irq] == this) { irqTable[irq] = this.next; } else { IoIrq! prev = (!)irqTable[irq]; while (prev.next != this) { prev = prev.next; } prev.next = this.next; } this.next = null; this.registered = false; if (irqTable[irq] == null) { Platform.DisableIoInterrupt(irq); return true; } } finally { ReleaseLock(enabled); } return true; } public bool WaitForInterrupt() { DebugStub.Assert(this.registered); if (signal != null) { signal.InterruptAwareWaitOne(); return true; } return false; } public void Pulse() { signal.InterruptAwareSet(); } public bool AckInterrupt() { #if DEBUG_DISPATCH_IO DebugStub.WriteLine("++ AckInterrupt: Irq={0:x2}", __arglist(irq)); #endif Platform.EnableIoInterrupt(irq); return true; } public override string! ToString() { return String.Format("IRQ:{0,2:x2}", irq); } } }