CompilationLock.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / DEVDIV / depot / DevDiv / releases / whidbey / QFE / ndp / fx / src / xsp / System / Web / Compilation / CompilationLock.cs / 3 / 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 ( 
        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 ( 
            _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 
    }
 
#if UNUSED_CODE 
    internal bool CheckOrFail() {
 
#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", "Checking on mutex " + MutexDebugName);
 
        if (UnsafeNativeMethods.InstrumentedMutexGetLock(_mutexHandle, 0) == -1) {
            // failed to get the lock
            Debug.Trace("Mutex", "Didn't get mutex " + MutexDebugName);
 
            Interlocked.Decrement(ref _lockStatus);
            return false; 
        } 

        Debug.Trace("Mutex", "Got mutex " + MutexDebugName); 
        return true;
#else
    return false;
#endif // !FEATURE_PAL 
    }
#endif 
 
    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
    } 
 
#if UNUSED
    internal /*public*/ void DrainMutex() { 

#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis
        // keep trying to set _lockStatus to -1 if it is 0
        Debug.Trace("Mutex", "Starting draining mutex " + MutexDebugName); 

        _draining = true; 
 
        for (;;) {
            if (_lockStatus == -1) 
                break;
            if (Interlocked.CompareExchange(ref _lockStatus, -1, 0) == 0)
                break; // got it
 
            Thread.Sleep(100);
        } 
 
        Debug.Trace("Mutex", "Completed drained mutex " + MutexDebugName);
#endif // !FEATURE_PAL 
    }

    internal /*public*/ void SetState(int state) {
 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis
 
        if (_mutexHandle.Handle != IntPtr.Zero) 
            UnsafeNativeMethods.InstrumentedMutexSetState(_mutexHandle, state);
#endif // FEATURE_PAL 
    }
#endif

    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)
            Monitor.Enter(BuildManager.TheBuildManager); 
            _mutex.WaitOne();
            gotLock = true; 
        } 
    }
 
    internal static void ReleaseLock() {
        _mutex.ReleaseMutex();
        Monitor.Exit(BuildManager.TheBuildManager);
    } 

#if UNUSED 
    internal static void DrainMutex() { 
        _mutex.DrainMutex();
    } 

    internal static void SetMutexState(int state) {
        _mutex.SetState(state);
    } 
#endif
} 
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------ 
// 
//     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 ( 
        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 ( 
            _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 
    }
 
#if UNUSED_CODE 
    internal bool CheckOrFail() {
 
#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", "Checking on mutex " + MutexDebugName);
 
        if (UnsafeNativeMethods.InstrumentedMutexGetLock(_mutexHandle, 0) == -1) {
            // failed to get the lock
            Debug.Trace("Mutex", "Didn't get mutex " + MutexDebugName);
 
            Interlocked.Decrement(ref _lockStatus);
            return false; 
        } 

        Debug.Trace("Mutex", "Got mutex " + MutexDebugName); 
        return true;
#else
    return false;
#endif // !FEATURE_PAL 
    }
#endif 
 
    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
    } 
 
#if UNUSED
    internal /*public*/ void DrainMutex() { 

#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis
        // keep trying to set _lockStatus to -1 if it is 0
        Debug.Trace("Mutex", "Starting draining mutex " + MutexDebugName); 

        _draining = true; 
 
        for (;;) {
            if (_lockStatus == -1) 
                break;
            if (Interlocked.CompareExchange(ref _lockStatus, -1, 0) == 0)
                break; // got it
 
            Thread.Sleep(100);
        } 
 
        Debug.Trace("Mutex", "Completed drained mutex " + MutexDebugName);
#endif // !FEATURE_PAL 
    }

    internal /*public*/ void SetState(int state) {
 
#if !FEATURE_PAL // No unmanaged aspnet_isapi mutex in Coriolis
 
        if (_mutexHandle.Handle != IntPtr.Zero) 
            UnsafeNativeMethods.InstrumentedMutexSetState(_mutexHandle, state);
#endif // FEATURE_PAL 
    }
#endif

    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)
            Monitor.Enter(BuildManager.TheBuildManager); 
            _mutex.WaitOne();
            gotLock = true; 
        } 
    }
 
    internal static void ReleaseLock() {
        _mutex.ReleaseMutex();
        Monitor.Exit(BuildManager.TheBuildManager);
    } 

#if UNUSED 
    internal static void DrainMutex() { 
        _mutex.DrainMutex();
    } 

    internal static void SetMutexState(int state) {
        _mutex.SetState(state);
    } 
#endif
} 
 
}

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

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