CompilationLock.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / xsp / System / Web / Compilation / CompilationLock.cs / 1305376 / CompilationLock.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

//#define MUTEXINSTRUMENTATION 
 
namespace System.Web.Compilation {
 
using System;
using System.Threading;
using System.Globalization;
using System.Security.Principal; 
using System.Web.Util;
using System.Web.Configuration; 
using System.Runtime.InteropServices; 
using System.Web.Management;
using System.Runtime.Versioning; 
using System.Diagnostics;
using Debug = System.Web.Util.Debug;

internal sealed class CompilationMutex : IDisposable { 

    private String  _name; 
    private String  _comment; 
#if MUTEXINSTRUMENTATION
    // Used to keep track of the stack when the mutex is obtained 
    private string _stackTrace;
#endif

    // ROTORTODO: replace unmanaged aspnet_isapi mutex with managed implementation 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis
    private HandleRef   _mutexHandle; 
 
    // Lock Status is used to drain out all worker threads out of Mutex ownership on
    // app domain shutdown: -1 locked for good, 0 unlocked, N locked by a worker thread(s) 
    private int     _lockStatus;
    private bool    _draining = false;
#endif // !FEATURE_PAL
 
    internal CompilationMutex(String name, String comment) {
 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis 

        // Attempt to get the mutex string from the registry (VSWhidbey 415795) 
        string mutexRandomName = (string) Misc.GetAspNetRegValue("CompilationMutexName",
            null /*valueName*/, null /*defaultValue*/);

        if (mutexRandomName != null) { 
            // If we were able to use the registry value, use it.  Also, we need to prepend "Global\"
            // to the mutex name, to make sure it can be shared between a terminal server session 
            // and IIS (VSWhidbey 307523). 
            _name += @"Global\" + name + "-" + mutexRandomName;
        } 
        else {
            // If we couldn't get the reg value, don't use it, and prepend "Local\" to the mutex
            // name to make it local to the session (and hence prevent hijacking)
            _name += @"Local\" + name; 
        }
 
        _comment = comment; 

        Debug.Trace("Mutex", "Creating Mutex " + MutexDebugName); 

        _mutexHandle = new HandleRef(this, UnsafeNativeMethods.InstrumentedMutexCreate(_name));

        if (_mutexHandle.Handle == IntPtr.Zero) { 
            Debug.Trace("Mutex", "Failed to create Mutex " + MutexDebugName);
 
            throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Create)); 
        }
 
        Debug.Trace("Mutex", "Successfully created Mutex " + MutexDebugName);
#endif // !FEATURE_PAL
    }
 
    ~CompilationMutex() {
        Close(); 
    } 

    void IDisposable.Dispose() { 
        Close();
        System.GC.SuppressFinalize(this);
    }
 
    internal /*public*/ void Close() {
 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis 

        if (_mutexHandle.Handle != IntPtr.Zero) { 
            UnsafeNativeMethods.InstrumentedMutexDelete(_mutexHandle);
            _mutexHandle = new HandleRef(this, IntPtr.Zero);
        }
#endif // !FEATURE_PAL 
    }
 
    [ResourceExposure(ResourceScope.None)] 
    internal /*public*/ void WaitOne() {
 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis

        if (_mutexHandle.Handle == IntPtr.Zero)
            throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Null)); 

        // check the lock status 
        for (;;) { 
            int lockStatus = _lockStatus;
 
            if (lockStatus == -1 || _draining)
                throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Drained));

            if (Interlocked.CompareExchange(ref _lockStatus, lockStatus+1, lockStatus) == lockStatus) 
                break; // got the lock
        } 
 
        Debug.Trace("Mutex", "Waiting for mutex " + MutexDebugName);
 
        if (UnsafeNativeMethods.InstrumentedMutexGetLock(_mutexHandle, -1) == -1) {
            // failed to get the lock
            Interlocked.Decrement(ref _lockStatus);
            throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Failed)); 
        }
 
#if MUTEXINSTRUMENTATION 
        // Remember the stack trace for debugging purpose
        _stackTrace = (new StackTrace()).ToString(); 
#endif

        Debug.Trace("Mutex", "Got mutex " + MutexDebugName);
#endif // !FEATURE_PAL 
    }
 
    internal /*public*/ void ReleaseMutex() { 

#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis 
        if (_mutexHandle.Handle == IntPtr.Zero)
            throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Null));

        Debug.Trace("Mutex", "Releasing mutex " + MutexDebugName); 

#if MUTEXINSTRUMENTATION 
        // Clear out the stack trace 
        _stackTrace = null;
#endif 

        if (UnsafeNativeMethods.InstrumentedMutexReleaseLock(_mutexHandle) != 0)
            Interlocked.Decrement(ref _lockStatus);
#endif // !FEATURE_PAL 
    }
 
 
    private String MutexDebugName {
        get { 
#if DBG
            return (_comment != null) ? _name + " (" + _comment + ")" : _name;
#else
            return _name; 
#endif
        } 
    } 
}
 
internal static class CompilationLock {

    private static CompilationMutex _mutex;
 
    static CompilationLock() {
 
        // Create the mutex (or just get it if another process created it). 
        // Make the mutex unique per application
        int hashCode = ("CompilationLock" + HttpRuntime.AppDomainAppIdInternal.ToLower(CultureInfo.InvariantCulture)).GetHashCode(); 

        _mutex = new CompilationMutex(
                        "CL" + hashCode.ToString("x", CultureInfo.InvariantCulture),
                        "CompilationLock for " + HttpRuntime.AppDomainAppVirtualPath); 
    }
 
    internal static void GetLock(ref bool gotLock) { 

        // The idea of this try/finally is to make sure that the statements are always 
        // executed together (VSWhidbey 319154)
        // This code should be using a constrained execution region.
        try {
        } 
        finally {
            // Always take the BuildManager lock *before* taking the mutex, to avoid possible 
            // deadlock situations (VSWhidbey 530732) 
#pragma warning disable 0618
            //@TODO: This overload of Monitor.Enter is obsolete.  Please change this to use Monitor.Enter(ref bool), and remove the pragmas   -- [....] 
            Monitor.Enter(BuildManager.TheBuildManager);
#pragma warning restore 0618
            _mutex.WaitOne();
            gotLock = true; 
        }
    } 
 
    internal static void ReleaseLock() {
        _mutex.ReleaseMutex(); 
        Monitor.Exit(BuildManager.TheBuildManager);
    }

} 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

//#define MUTEXINSTRUMENTATION 
 
namespace System.Web.Compilation {
 
using System;
using System.Threading;
using System.Globalization;
using System.Security.Principal; 
using System.Web.Util;
using System.Web.Configuration; 
using System.Runtime.InteropServices; 
using System.Web.Management;
using System.Runtime.Versioning; 
using System.Diagnostics;
using Debug = System.Web.Util.Debug;

internal sealed class CompilationMutex : IDisposable { 

    private String  _name; 
    private String  _comment; 
#if MUTEXINSTRUMENTATION
    // Used to keep track of the stack when the mutex is obtained 
    private string _stackTrace;
#endif

    // ROTORTODO: replace unmanaged aspnet_isapi mutex with managed implementation 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis
    private HandleRef   _mutexHandle; 
 
    // Lock Status is used to drain out all worker threads out of Mutex ownership on
    // app domain shutdown: -1 locked for good, 0 unlocked, N locked by a worker thread(s) 
    private int     _lockStatus;
    private bool    _draining = false;
#endif // !FEATURE_PAL
 
    internal CompilationMutex(String name, String comment) {
 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis 

        // Attempt to get the mutex string from the registry (VSWhidbey 415795) 
        string mutexRandomName = (string) Misc.GetAspNetRegValue("CompilationMutexName",
            null /*valueName*/, null /*defaultValue*/);

        if (mutexRandomName != null) { 
            // If we were able to use the registry value, use it.  Also, we need to prepend "Global\"
            // to the mutex name, to make sure it can be shared between a terminal server session 
            // and IIS (VSWhidbey 307523). 
            _name += @"Global\" + name + "-" + mutexRandomName;
        } 
        else {
            // If we couldn't get the reg value, don't use it, and prepend "Local\" to the mutex
            // name to make it local to the session (and hence prevent hijacking)
            _name += @"Local\" + name; 
        }
 
        _comment = comment; 

        Debug.Trace("Mutex", "Creating Mutex " + MutexDebugName); 

        _mutexHandle = new HandleRef(this, UnsafeNativeMethods.InstrumentedMutexCreate(_name));

        if (_mutexHandle.Handle == IntPtr.Zero) { 
            Debug.Trace("Mutex", "Failed to create Mutex " + MutexDebugName);
 
            throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Create)); 
        }
 
        Debug.Trace("Mutex", "Successfully created Mutex " + MutexDebugName);
#endif // !FEATURE_PAL
    }
 
    ~CompilationMutex() {
        Close(); 
    } 

    void IDisposable.Dispose() { 
        Close();
        System.GC.SuppressFinalize(this);
    }
 
    internal /*public*/ void Close() {
 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis 

        if (_mutexHandle.Handle != IntPtr.Zero) { 
            UnsafeNativeMethods.InstrumentedMutexDelete(_mutexHandle);
            _mutexHandle = new HandleRef(this, IntPtr.Zero);
        }
#endif // !FEATURE_PAL 
    }
 
    [ResourceExposure(ResourceScope.None)] 
    internal /*public*/ void WaitOne() {
 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis

        if (_mutexHandle.Handle == IntPtr.Zero)
            throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Null)); 

        // check the lock status 
        for (;;) { 
            int lockStatus = _lockStatus;
 
            if (lockStatus == -1 || _draining)
                throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Drained));

            if (Interlocked.CompareExchange(ref _lockStatus, lockStatus+1, lockStatus) == lockStatus) 
                break; // got the lock
        } 
 
        Debug.Trace("Mutex", "Waiting for mutex " + MutexDebugName);
 
        if (UnsafeNativeMethods.InstrumentedMutexGetLock(_mutexHandle, -1) == -1) {
            // failed to get the lock
            Interlocked.Decrement(ref _lockStatus);
            throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Failed)); 
        }
 
#if MUTEXINSTRUMENTATION 
        // Remember the stack trace for debugging purpose
        _stackTrace = (new StackTrace()).ToString(); 
#endif

        Debug.Trace("Mutex", "Got mutex " + MutexDebugName);
#endif // !FEATURE_PAL 
    }
 
    internal /*public*/ void ReleaseMutex() { 

#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis 
        if (_mutexHandle.Handle == IntPtr.Zero)
            throw new InvalidOperationException(SR.GetString(SR.CompilationMutex_Null));

        Debug.Trace("Mutex", "Releasing mutex " + MutexDebugName); 

#if MUTEXINSTRUMENTATION 
        // Clear out the stack trace 
        _stackTrace = null;
#endif 

        if (UnsafeNativeMethods.InstrumentedMutexReleaseLock(_mutexHandle) != 0)
            Interlocked.Decrement(ref _lockStatus);
#endif // !FEATURE_PAL 
    }
 
 
    private String MutexDebugName {
        get { 
#if DBG
            return (_comment != null) ? _name + " (" + _comment + ")" : _name;
#else
            return _name; 
#endif
        } 
    } 
}
 
internal static class CompilationLock {

    private static CompilationMutex _mutex;
 
    static CompilationLock() {
 
        // Create the mutex (or just get it if another process created it). 
        // Make the mutex unique per application
        int hashCode = ("CompilationLock" + HttpRuntime.AppDomainAppIdInternal.ToLower(CultureInfo.InvariantCulture)).GetHashCode(); 

        _mutex = new CompilationMutex(
                        "CL" + hashCode.ToString("x", CultureInfo.InvariantCulture),
                        "CompilationLock for " + HttpRuntime.AppDomainAppVirtualPath); 
    }
 
    internal static void GetLock(ref bool gotLock) { 

        // The idea of this try/finally is to make sure that the statements are always 
        // executed together (VSWhidbey 319154)
        // This code should be using a constrained execution region.
        try {
        } 
        finally {
            // Always take the BuildManager lock *before* taking the mutex, to avoid possible 
            // deadlock situations (VSWhidbey 530732) 
#pragma warning disable 0618
            //@TODO: This overload of Monitor.Enter is obsolete.  Please change this to use Monitor.Enter(ref bool), and remove the pragmas   -- [....] 
            Monitor.Enter(BuildManager.TheBuildManager);
#pragma warning restore 0618
            _mutex.WaitOne();
            gotLock = true; 
        }
    } 
 
    internal static void ReleaseLock() {
        _mutex.ReleaseMutex(); 
        Monitor.Exit(BuildManager.TheBuildManager);
    }

} 

} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK