You've already forked linux-packaging-mono
Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
223
external/referencesource/System.Web/LegacyAspNetSynchronizationContext.cs
vendored
Normal file
223
external/referencesource/System.Web/LegacyAspNetSynchronizationContext.cs
vendored
Normal file
@ -0,0 +1,223 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="LegacyAspNetSynchronizationContext.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Security.Permissions;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Util;
|
||||
|
||||
namespace System.Web {
|
||||
|
||||
// Represents a SynchronizationContext that has legacy behavior (<= FX 4.0) when it comes to asynchronous operations.
|
||||
// Characterized by locking on the HttpApplication to synchronize work, dispatching Posts as Sends.
|
||||
|
||||
internal sealed class LegacyAspNetSynchronizationContext : AspNetSynchronizationContextBase {
|
||||
private HttpApplication _application;
|
||||
private Action _appVerifierCallback;
|
||||
private bool _disabled;
|
||||
private bool _syncCaller;
|
||||
private bool _invalidOperationEncountered;
|
||||
private int _pendingCount;
|
||||
private ExceptionDispatchInfo _error;
|
||||
private WaitCallback _lastCompletionCallback;
|
||||
private object _lastCompletionCallbackLock;
|
||||
|
||||
internal LegacyAspNetSynchronizationContext(HttpApplication app) {
|
||||
_application = app;
|
||||
_appVerifierCallback = AppVerifier.GetSyncContextCheckDelegate(app);
|
||||
_lastCompletionCallbackLock = new object();
|
||||
}
|
||||
|
||||
private void CheckForRequestCompletionIfRequired() {
|
||||
if (_appVerifierCallback != null) {
|
||||
_appVerifierCallback();
|
||||
}
|
||||
}
|
||||
|
||||
private void CallCallback(SendOrPostCallback callback, Object state) {
|
||||
CheckForRequestCompletionIfRequired();
|
||||
|
||||
// don't take app lock for [....] caller to avoid deadlocks in case they poll for result
|
||||
if (_syncCaller) {
|
||||
CallCallbackPossiblyUnderLock(callback, state);
|
||||
}
|
||||
else {
|
||||
lock (_application) {
|
||||
CallCallbackPossiblyUnderLock(callback, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state) {
|
||||
ThreadContext threadContext = null;
|
||||
try {
|
||||
threadContext = _application.OnThreadEnter();
|
||||
try {
|
||||
callback(state);
|
||||
}
|
||||
catch (Exception e) {
|
||||
_error = ExceptionDispatchInfo.Capture(e);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (threadContext != null) {
|
||||
threadContext.DisassociateFromCurrentThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this property no-ops using the legacy [....] context
|
||||
internal override bool AllowAsyncDuringSyncStages {
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
internal override int PendingOperationsCount {
|
||||
get { return _pendingCount; }
|
||||
}
|
||||
|
||||
internal override ExceptionDispatchInfo ExceptionDispatchInfo {
|
||||
get { return _error; }
|
||||
}
|
||||
|
||||
internal override void ClearError() {
|
||||
_error = null;
|
||||
}
|
||||
|
||||
// Dev11 Bug 70908: Race condition involving SynchronizationContext allows ASP.NET requests to be abandoned in the pipeline
|
||||
//
|
||||
// When the last completion occurs, the _pendingCount is decremented and then the _lastCompletionCallbackLock is acquired to get
|
||||
// the _lastCompletionCallback. If the _lastCompletionCallback is non-null, then the last completion will invoke the callback;
|
||||
// otherwise, the caller of PendingCompletion will handle the completion.
|
||||
internal override bool PendingCompletion(WaitCallback callback) {
|
||||
Debug.Assert(_lastCompletionCallback == null); // only one at a time
|
||||
bool pending = false;
|
||||
if (_pendingCount != 0) {
|
||||
lock (_lastCompletionCallbackLock) {
|
||||
if (_pendingCount != 0) {
|
||||
pending = true;
|
||||
_lastCompletionCallback = callback;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pending;
|
||||
}
|
||||
|
||||
public override void Send(SendOrPostCallback callback, Object state) {
|
||||
#if DBG
|
||||
Debug.Trace("Async", "Send");
|
||||
Debug.Trace("AsyncStack", "Send from:\r\n" + GetDebugStackTrace());
|
||||
#endif
|
||||
CallCallback(callback, state);
|
||||
}
|
||||
|
||||
public override void Post(SendOrPostCallback callback, Object state) {
|
||||
#if DBG
|
||||
Debug.Trace("Async", "Post");
|
||||
Debug.Trace("AsyncStack", "Post from:\r\n" + GetDebugStackTrace());
|
||||
#endif
|
||||
CallCallback(callback, state);
|
||||
}
|
||||
|
||||
#if DBG
|
||||
[EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)]
|
||||
private void CreateCopyDumpStack() {
|
||||
Debug.Trace("Async", "CreateCopy");
|
||||
Debug.Trace("AsyncStack", "CreateCopy from:\r\n" + GetDebugStackTrace());
|
||||
}
|
||||
#endif
|
||||
|
||||
public override SynchronizationContext CreateCopy() {
|
||||
#if DBG
|
||||
CreateCopyDumpStack();
|
||||
#endif
|
||||
LegacyAspNetSynchronizationContext context = new LegacyAspNetSynchronizationContext(_application);
|
||||
context._disabled = _disabled;
|
||||
context._syncCaller = _syncCaller;
|
||||
context.AllowAsyncDuringSyncStages = AllowAsyncDuringSyncStages;
|
||||
return context;
|
||||
}
|
||||
|
||||
public override void OperationStarted() {
|
||||
if (_invalidOperationEncountered || (_disabled && _pendingCount == 0)) {
|
||||
_invalidOperationEncountered = true;
|
||||
throw new InvalidOperationException(SR.GetString(SR.Async_operation_disabled));
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref _pendingCount);
|
||||
#if DBG
|
||||
Debug.Trace("Async", "OperationStarted(count=" + _pendingCount + ")");
|
||||
Debug.Trace("AsyncStack", "OperationStarted(count=" + _pendingCount + ") from:\r\n" + GetDebugStackTrace());
|
||||
#endif
|
||||
}
|
||||
|
||||
public override void OperationCompleted() {
|
||||
if (_invalidOperationEncountered || (_disabled && _pendingCount == 0)) {
|
||||
// throw from operation started could cause extra operation completed
|
||||
return;
|
||||
}
|
||||
|
||||
int pendingCount = Interlocked.Decrement(ref _pendingCount);
|
||||
|
||||
#if DBG
|
||||
Debug.Trace("Async", "OperationCompleted(pendingCount=" + pendingCount + ")");
|
||||
Debug.Trace("AsyncStack", "OperationCompleted(pendingCount=" + pendingCount + ") from:\r\n" + GetDebugStackTrace());
|
||||
#endif
|
||||
|
||||
// notify (once) about the last completion to resume the async work
|
||||
if (pendingCount == 0) {
|
||||
WaitCallback callback = null;
|
||||
lock (_lastCompletionCallbackLock) {
|
||||
callback = _lastCompletionCallback;
|
||||
_lastCompletionCallback = null;
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
Debug.Trace("Async", "Queueing LastCompletionWorkItemCallback");
|
||||
ThreadPool.QueueUserWorkItem(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override bool Enabled {
|
||||
get { return !_disabled; }
|
||||
}
|
||||
|
||||
internal override void Enable() {
|
||||
_disabled = false;
|
||||
}
|
||||
|
||||
internal override void Disable() {
|
||||
_disabled = true;
|
||||
}
|
||||
|
||||
internal override void SetSyncCaller() {
|
||||
_syncCaller = true;
|
||||
}
|
||||
|
||||
internal override void ResetSyncCaller() {
|
||||
_syncCaller = false;
|
||||
}
|
||||
|
||||
internal override void AssociateWithCurrentThread() {
|
||||
Monitor.Enter(_application);
|
||||
}
|
||||
|
||||
internal override void DisassociateFromCurrentThread() {
|
||||
Monitor.Exit(_application);
|
||||
}
|
||||
|
||||
#if DBG
|
||||
[EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
|
||||
private static string GetDebugStackTrace() {
|
||||
return Environment.StackTrace;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user