//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: Mutex.cs // // Note: // using System; using System.Threading; using System.Runtime.CompilerServices; using Microsoft.Singularity; using Microsoft.Singularity.Io; using Microsoft.Singularity.Scheduling; namespace System.Threading { [CLSCompliant(false)] public enum MutexEvent { AcquireAgain = 1, Acquire = 2, Enqueue = 3, } //| [NoCCtor] [CLSCompliant(false)] public sealed class Mutex : WaitHandle { private int acquired = 0; // Number of times acquired by same thread. //| public Mutex(bool initiallyOwned) : base(initiallyOwned ? 0 : 1) { if (initiallyOwned) { owner = Thread.CurrentThread; acquired = 1; } } //| public Mutex() : base(1) { } public bool AcquireMutex() { return WaitOne(); } public bool AcquireMutex(SchedulerTime stop) { return WaitOne(stop); } //| public void ReleaseMutex() { #if DEBUG_DISPATCH DebugStub.Print("Mutex:ReleaseMutex 001\n"); #endif // DEBUG_DISPATCH if (Thread.CurrentThread != owner) { VTable.Assert(Thread.CurrentThread == owner); return; } bool iflag = Processor.DisableInterrupts(); try { Scheduler.DispatchLock(); try { VTable.Assert(acquired >= 0); acquired--; if (acquired == 0) { #if DEBUG_DISPATCH DebugStub.Print("Mutex:ReleaseMutex 002\n"); #endif // DEBUG_DISPATCH if (NotifyOne()) { #if DEBUG_DISPATCH DebugStub.Print("Mutex:ReleaseMutex 003\n"); #endif // DEBUG_DISPATCH signaled = 0; acquired = 1; } else { signaled = 1; owner = null; } } } finally { Scheduler.DispatchRelease(); } } finally { Processor.RestoreInterrupts(iflag); } } // Called by monitor to see if its lock is held by the current thread. internal bool IsOwnedByCurrentThread() { return (Thread.CurrentThread == owner); } // Called with dispatch lock held and interrupts off. // Returns true if the mutex was acquired. internal override bool AcquireOrEnqueue(ThreadEntry entry) { if (owner == entry.Thread) { #if DEBUG_DISPATCH DebugStub.Print("Mutex:AcquireOrEnqueue 001\n"); #endif // DEBUG_DISPATCH acquired++; Monitoring.Log(Monitoring.Provider.Mutex, (ushort)MutexEvent.AcquireAgain, 0, (uint)this.id, (uint)entry.Thread.threadIndex, 0, 0, 0); return true; } else if (signaled != 0) { #if DEBUG_DISPATCH DebugStub.Print("Mutex:AcquireOrEnqueue 002\n"); #endif // DEBUG_DISPATCH signaled = 0; owner = entry.Thread; acquired = 1; Monitoring.Log(Monitoring.Provider.Mutex, (ushort)MutexEvent.Acquire, 0, (uint)this.id, (uint)entry.Thread.threadIndex, 0, 0, 0); return true; } else { #if DEBUG_DISPATCH DebugStub.Print("Mutex:AcquireOrEnqueue 003\n"); #endif // DEBUG_DISPATCH queue.EnqueueTail(entry); Monitoring.Log(Monitoring.Provider.Mutex, (ushort)MutexEvent.Enqueue, 0, (uint)this.id, (uint)entry.Thread.threadIndex, 0, 0, 0); return false; } } // Return mutex owner. [NoHeapAllocation] internal override Thread GetBeneficiary() { return owner; } } }