e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
104 lines
4.5 KiB
C#
104 lines
4.5 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="AsyncResultBase.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* IAsyncResult for asynchronous reads.
|
|
*
|
|
* Copyright (c) 2010 Microsoft Corporation
|
|
*/
|
|
|
|
namespace System.Web.Hosting {
|
|
using System;
|
|
using System.Runtime.ExceptionServices;
|
|
using System.Threading;
|
|
using System.Web.Util;
|
|
|
|
internal abstract class AsyncResultBase : IAsyncResult {
|
|
private ManualResetEventSlim _mre; // unlike ManualResetEvent, this creates a kernel object lazily
|
|
private AsyncCallback _callback;
|
|
private Object _asyncState;
|
|
private volatile bool _completed;
|
|
private volatile bool _completedSynchronously;
|
|
private volatile int _hresult;
|
|
private Thread _threadWhichStartedOperation;
|
|
private volatile ExceptionDispatchInfo _error;
|
|
|
|
protected AsyncResultBase(AsyncCallback cb, Object state) {
|
|
_callback = cb;
|
|
_asyncState = state;
|
|
_mre = new ManualResetEventSlim();
|
|
}
|
|
|
|
internal abstract void Complete(int bytesCompleted, int hresult, IntPtr pAsyncCompletionContext, bool synchronous);
|
|
|
|
protected void Complete(int hresult, bool synchronous) {
|
|
if (Volatile.Read(ref _threadWhichStartedOperation) == Thread.CurrentThread) {
|
|
// If we're calling Complete on the same thread which kicked off the operation, then
|
|
// we ignore the 'synchronous' value that the caller provided to us since we know
|
|
// for a fact that this is really a synchronous completion. This is only checked if
|
|
// the caller calls the MarkCallToBeginMethod* routines below, which only occurs in
|
|
// the Classic Mode pipeline.
|
|
synchronous = true;
|
|
}
|
|
|
|
_hresult = hresult;
|
|
_completed = true;
|
|
_completedSynchronously = synchronous;
|
|
_mre.Set();
|
|
|
|
if (_callback != null)
|
|
_callback(this);
|
|
}
|
|
|
|
// If the caller needs to invoke an asynchronous method where the only way of knowing whether the
|
|
// method actually completed synchronously is to inspect which thread the callback was invoked on,
|
|
// then the caller should surround the asynchronous call with calls to the below Started / Completed
|
|
// methods. The callback can compare the captured thread against the current thread to see if the
|
|
// completion was synchronous. The caller calls the Completed method when unwinding so that the
|
|
// captured thread can be cleared out, preventing an asynchronous invocation on the same thread
|
|
// from being mistaken for a synchronous invocation.
|
|
|
|
internal void MarkCallToBeginMethodStarted() {
|
|
Thread originalThread = Interlocked.CompareExchange(ref _threadWhichStartedOperation, Thread.CurrentThread, null);
|
|
Debug.Assert(originalThread == null, "Another thread already called MarkCallToBeginMethodStarted.");
|
|
}
|
|
|
|
internal void MarkCallToBeginMethodCompleted() {
|
|
Thread originalThread = Interlocked.Exchange(ref _threadWhichStartedOperation, null);
|
|
Debug.Assert(originalThread == Thread.CurrentThread, "This thread did not call MarkCallToBeginMethodStarted.");
|
|
}
|
|
|
|
internal void ReleaseWaitHandleWhenSignaled() {
|
|
try {
|
|
_mre.Wait();
|
|
}
|
|
finally {
|
|
_mre.Dispose();
|
|
}
|
|
}
|
|
|
|
internal void SetError(Exception error) {
|
|
Debug.Assert(error != null);
|
|
_error = ExceptionDispatchInfo.Capture(error);
|
|
}
|
|
|
|
// Properties that are not part of IAsyncResult
|
|
//
|
|
|
|
internal int HResult { get { return _hresult; } set { _hresult = value; } }
|
|
internal ExceptionDispatchInfo Error { get { return _error; } }
|
|
|
|
//
|
|
// IAsyncResult implementation
|
|
//
|
|
|
|
public bool IsCompleted { get { return _completed; } }
|
|
public bool CompletedSynchronously { get { return _completedSynchronously; } }
|
|
public Object AsyncState { get { return _asyncState; } }
|
|
public WaitHandle AsyncWaitHandle { get { return _mre.WaitHandle; } } // wait not supported
|
|
}
|
|
}
|