You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@ -0,0 +1,206 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="CompilationLock.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//#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 = StringUtil.GetNonRandomizedHashCode("CompilationLock" + HttpRuntime.AppDomainAppId.ToLower(CultureInfo.InvariantCulture));
|
||||
|
||||
|
||||
_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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user