Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / System.Runtime.DurableInstancing / System / Runtime / AsyncResult.cs / 1305376 / AsyncResult.cs
//------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.Runtime
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Transactions;
// AsyncResult starts acquired; Complete releases.
[Fx.Tag.SynchronizationPrimitive(Fx.Tag.BlocksUsing.ManualResetEvent, SupportsAsync = true, ReleaseMethod = "Complete")]
abstract class AsyncResult : IAsyncResult
{
static AsyncCallback asyncCompletionWrapperCallback;
AsyncCallback callback;
bool completedSynchronously;
bool endCalled;
Exception exception;
bool isCompleted;
AsyncCompletion nextAsyncCompletion;
IAsyncResult deferredTransactionalResult;
TransactionSignalScope transactionContext;
object state;
[Fx.Tag.SynchronizationObject]
ManualResetEvent manualResetEvent;
[Fx.Tag.SynchronizationObject(Blocking = false)]
object thisLock;
#if DEBUG
StackTrace endStack;
StackTrace completeStack;
UncompletedAsyncResultMarker marker;
#endif
protected AsyncResult(AsyncCallback callback, object state)
{
this.callback = callback;
this.state = state;
this.thisLock = new object();
#if DEBUG
this.marker = new UncompletedAsyncResultMarker(this);
#endif
}
public object AsyncState
{
get
{
return state;
}
}
public WaitHandle AsyncWaitHandle
{
get
{
if (manualResetEvent != null)
{
return manualResetEvent;
}
lock (ThisLock)
{
if (manualResetEvent == null)
{
manualResetEvent = new ManualResetEvent(isCompleted);
}
}
return manualResetEvent;
}
}
public bool CompletedSynchronously
{
get
{
return completedSynchronously;
}
}
public bool HasCallback
{
get
{
return this.callback != null;
}
}
public bool IsCompleted
{
get
{
return isCompleted;
}
}
// used in conjunction with PrepareAsyncCompletion to allow for finally blocks
protected Action OnCompleting { get; set; }
object ThisLock
{
get
{
return this.thisLock;
}
}
// subclasses like TraceAsyncResult can use this to wrap the callback functionality in a scope
protected Action VirtualCallback
{
get;
set;
}
protected void Complete(bool completedSynchronously)
{
if (this.isCompleted)
{
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.AsyncResultCompletedTwice(GetType())));
}
#if DEBUG
this.marker.AsyncResult = null;
this.marker = null;
if (!Fx.FastDebug && completeStack == null)
{
completeStack = new StackTrace();
}
#endif
this.completedSynchronously = completedSynchronously;
if (OnCompleting != null)
{
// Allow exception replacement, like a catch/throw pattern.
try
{
OnCompleting(this, this.exception);
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
{
throw;
}
this.exception = exception;
}
}
if (completedSynchronously)
{
// If we completedSynchronously, then there's no chance that the manualResetEvent was created so
// we don't need to worry about a ----
Fx.Assert(this.manualResetEvent == null, "No ManualResetEvent should be created for a synchronous AsyncResult.");
this.isCompleted = true;
}
else
{
lock (ThisLock)
{
this.isCompleted = true;
if (this.manualResetEvent != null)
{
this.manualResetEvent.Set();
}
}
}
if (this.callback != null)
{
try
{
if (VirtualCallback != null)
{
VirtualCallback(this.callback, this);
}
else
{
this.callback(this);
}
}
#pragma warning disable 1634
#pragma warning suppress 56500 // transferring exception to another thread
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
throw Fx.Exception.AsError(new CallbackException(SRCore.AsyncCallbackThrewException, e));
}
#pragma warning restore 1634
}
}
protected void Complete(bool completedSynchronously, Exception exception)
{
this.exception = exception;
Complete(completedSynchronously);
}
static void AsyncCompletionWrapperCallback(IAsyncResult result)
{
if (result == null)
{
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InvalidNullAsyncResult));
}
if (result.CompletedSynchronously)
{
return;
}
AsyncResult thisPtr = (AsyncResult)result.AsyncState;
if (thisPtr.transactionContext != null && !thisPtr.transactionContext.Signal(result))
{
// The TransactionScope isn't cleaned up yet and can't be done on this thread. Must defer
// the callback (which is likely to attempt to commit the transaction) until later.
return;
}
AsyncCompletion callback = thisPtr.GetNextCompletion();
if (callback == null)
{
ThrowInvalidAsyncResult(result);
}
bool completeSelf = false;
Exception completionException = null;
try
{
completeSelf = callback(result);
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
completeSelf = true;
completionException = e;
}
if (completeSelf)
{
thisPtr.Complete(false, completionException);
}
}
protected AsyncCallback PrepareAsyncCompletion(AsyncCompletion callback)
{
if (this.transactionContext != null)
{
// It might be an old, leftover one, if an exception was thrown within the last using (PrepareTransactionalCall()) block.
if (this.transactionContext.IsPotentiallyAbandoned)
{
this.transactionContext = null;
}
else
{
this.transactionContext.Prepared();
}
}
this.nextAsyncCompletion = callback;
if (AsyncResult.asyncCompletionWrapperCallback == null)
{
AsyncResult.asyncCompletionWrapperCallback = Fx.ThunkCallback(new AsyncCallback(AsyncCompletionWrapperCallback));
}
return AsyncResult.asyncCompletionWrapperCallback;
}
protected IDisposable PrepareTransactionalCall(Transaction transaction)
{
if (this.transactionContext != null && !this.transactionContext.IsPotentiallyAbandoned)
{
ThrowInvalidAsyncResult("PrepareTransactionalCall should only be called as the object of non-nested using statements. If the Begin succeeds, Check/SyncContinue must be called before another PrepareTransactionalCall.");
}
return this.transactionContext = transaction == null ? null : new TransactionSignalScope(this, transaction);
}
protected bool CheckSyncContinue(IAsyncResult result)
{
AsyncCompletion dummy;
return TryContinueHelper(result, out dummy);
}
protected bool SyncContinue(IAsyncResult result)
{
AsyncCompletion callback;
if (TryContinueHelper(result, out callback))
{
return callback(result);
}
else
{
return false;
}
}
bool TryContinueHelper(IAsyncResult result, out AsyncCompletion callback)
{
if (result == null)
{
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InvalidNullAsyncResult));
}
callback = null;
if (result.CompletedSynchronously)
{
// Once we pass the check, we know that we own forward progress, so transactionContext is correct. Verify its state.
if (this.transactionContext != null)
{
if (this.transactionContext.State != TransactionSignalState.Completed)
{
ThrowInvalidAsyncResult("Check/SyncContinue cannot be called from within the PrepareTransactionalCall using block.");
}
else if (this.transactionContext.IsSignalled)
{
// This is most likely to happen when result.CompletedSynchronously registers differently here and in the callback, which
// is the fault of 'result'.
ThrowInvalidAsyncResult(result);
}
}
}
else if (object.ReferenceEquals(result, this.deferredTransactionalResult))
{
// The transactionContext may not be current if forward progress has been made via the callback. Instead,
// use deferredTransactionalResult to see if we are supposed to execute a post-transaction callback.
//
// Once we pass the check, we know that we own forward progress, so transactionContext is correct. Verify its state.
if (this.transactionContext == null || !this.transactionContext.IsSignalled)
{
ThrowInvalidAsyncResult(result);
}
this.deferredTransactionalResult = null;
}
else
{
return false;
}
callback = GetNextCompletion();
if (callback == null)
{
ThrowInvalidAsyncResult("Only call Check/SyncContinue once per async operation (once per PrepareAsyncCompletion).");
}
return true;
}
AsyncCompletion GetNextCompletion()
{
AsyncCompletion result = this.nextAsyncCompletion;
this.transactionContext = null;
this.nextAsyncCompletion = null;
return result;
}
static void ThrowInvalidAsyncResult(IAsyncResult result)
{
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.InvalidAsyncResultImplementation(result.GetType())));
}
static void ThrowInvalidAsyncResult(string debugText)
{
string message = SRCore.InvalidAsyncResultImplementationGeneric;
if (debugText != null)
{
#if DEBUG
message += " " + debugText;
#endif
}
throw Fx.Exception.AsError(new InvalidOperationException(message));
}
[Fx.Tag.Blocking(Conditional = "!asyncResult.isCompleted")]
protected static TAsyncResult End(IAsyncResult result)
where TAsyncResult : AsyncResult
{
if (result == null)
{
throw Fx.Exception.ArgumentNull("result");
}
TAsyncResult asyncResult = result as TAsyncResult;
if (asyncResult == null)
{
throw Fx.Exception.Argument("result", SRCore.InvalidAsyncResult);
}
if (asyncResult.endCalled)
{
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.AsyncResultAlreadyEnded));
}
#if DEBUG
if (!Fx.FastDebug && asyncResult.endStack == null)
{
asyncResult.endStack = new StackTrace();
}
#endif
asyncResult.endCalled = true;
if (!asyncResult.isCompleted)
{
asyncResult.AsyncWaitHandle.WaitOne();
}
if (asyncResult.manualResetEvent != null)
{
asyncResult.manualResetEvent.Close();
}
if (asyncResult.exception != null)
{
throw Fx.Exception.AsError(asyncResult.exception);
}
return asyncResult;
}
enum TransactionSignalState
{
Ready = 0,
Prepared,
Completed,
Abandoned,
}
class TransactionSignalScope : SignalGate, IDisposable
{
TransactionScope transactionScope;
AsyncResult parent;
public TransactionSignalScope(AsyncResult result, Transaction transaction)
{
Fx.Assert(transaction != null, "Null Transaction provided to AsyncResult.TransactionSignalScope.");
this.parent = result;
this.transactionScope = Fx.CreateTransactionScope(transaction);
}
public TransactionSignalState State { get; private set; }
public bool IsPotentiallyAbandoned
{
get
{
return State == TransactionSignalState.Abandoned || (State == TransactionSignalState.Completed && !IsSignalled);
}
}
public void Prepared()
{
if (State != TransactionSignalState.Ready)
{
AsyncResult.ThrowInvalidAsyncResult("PrepareAsyncCompletion should only be called once per PrepareTransactionalCall.");
}
State = TransactionSignalState.Prepared;
}
void IDisposable.Dispose()
{
if (State == TransactionSignalState.Ready)
{
State = TransactionSignalState.Abandoned;
}
else if (State == TransactionSignalState.Prepared)
{
State = TransactionSignalState.Completed;
}
else
{
AsyncResult.ThrowInvalidAsyncResult("PrepareTransactionalCall should only be called in a using. Dispose called multiple times.");
}
try
{
Fx.CompleteTransactionScope(ref this.transactionScope);
}
catch (Exception exception)
{
if (Fx.IsFatal(exception))
{
throw;
}
// Complete and Dispose are not expected to throw. If they do it can mess up the AsyncResult state machine.
throw Fx.Exception.AsError(new InvalidOperationException(SRCore.AsyncTransactionException));
}
// This will release the callback to run, or tell us that we need to defer the callback to Check/SyncContinue.
//
// It's possible to avoid this Interlocked when CompletedSynchronously is true, but we have no way of knowing that
// from here, and adding a way would add complexity to the AsyncResult transactional calling pattern. This
// unnecessary Interlocked only happens when: PrepareTransactionalCall is called with a non-null transaction,
// PrepareAsyncCompletion is reached, and the operation completes synchronously or with an exception.
IAsyncResult result;
if (State == TransactionSignalState.Completed && Unlock(out result))
{
if (this.parent.deferredTransactionalResult != null)
{
AsyncResult.ThrowInvalidAsyncResult(this.parent.deferredTransactionalResult);
}
this.parent.deferredTransactionalResult = result;
}
}
}
// can be utilized by subclasses to write core completion code for both the [....] and async paths
// in one location, signalling chainable synchronous completion with the boolean result,
// and leveraging PrepareAsyncCompletion for conversion to an AsyncCallback.
// NOTE: requires that "this" is passed in as the state object to the asynchronous sub-call being used with a completion routine.
protected delegate bool AsyncCompletion(IAsyncResult result);
#if DEBUG
class UncompletedAsyncResultMarker
{
public UncompletedAsyncResultMarker(AsyncResult result)
{
AsyncResult = result;
}
[SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode,
Justification = "Debug-only facility")]
public AsyncResult AsyncResult { get; set; }
}
#endif
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- IPAddress.cs
- ExeContext.cs
- ResourceContainer.cs
- TabControl.cs
- MailWriter.cs
- DictationGrammar.cs
- ProjectionCamera.cs
- Mappings.cs
- DiscoveryDocumentLinksPattern.cs
- SymLanguageType.cs
- SqlCaseSimplifier.cs
- ScriptingRoleServiceSection.cs
- OLEDB_Enum.cs
- ConsumerConnectionPoint.cs
- SecUtil.cs
- ProcessModelInfo.cs
- StylusPlugin.cs
- _UncName.cs
- SpeechRecognizer.cs
- ProfessionalColors.cs
- SortQuery.cs
- TextParentUndoUnit.cs
- StoreItemCollection.cs
- JavaScriptObjectDeserializer.cs
- XmlSchemaResource.cs
- WebPartManagerInternals.cs
- StringConcat.cs
- SpeechDetectedEventArgs.cs
- FrameworkContentElement.cs
- TemplateBamlTreeBuilder.cs
- UnhandledExceptionEventArgs.cs
- UTF8Encoding.cs
- UnmanagedHandle.cs
- ContextMenu.cs
- WebServiceMethodData.cs
- GridViewHeaderRowPresenterAutomationPeer.cs
- DefaultTraceListener.cs
- ReturnType.cs
- SymbolTable.cs
- AutomationPatternInfo.cs
- DropDownList.cs
- ByteStack.cs
- ListDictionary.cs
- ServerIdentity.cs
- PKCS1MaskGenerationMethod.cs
- Transform.cs
- BackoffTimeoutHelper.cs
- ConnectionPoint.cs
- DateTimeValueSerializerContext.cs
- XmlSchemaValidator.cs
- RecipientInfo.cs
- FieldToken.cs
- BlockingCollection.cs
- LayoutTable.cs
- IISMapPath.cs
- Statements.cs
- CodeComment.cs
- ReadOnlyDataSourceView.cs
- ClientTargetSection.cs
- DbCommandDefinition.cs
- CustomSignedXml.cs
- EntityDataSourceMemberPath.cs
- DbException.cs
- XmlSchemaAny.cs
- HttpConfigurationContext.cs
- DbConnectionFactory.cs
- ThreadExceptionEvent.cs
- SchemaImporterExtension.cs
- SystemException.cs
- SByte.cs
- DataIdProcessor.cs
- CompiledRegexRunner.cs
- XmlSignificantWhitespace.cs
- SchemaCollectionCompiler.cs
- Point3DAnimation.cs
- Icon.cs
- StateManagedCollection.cs
- ControlValuePropertyAttribute.cs
- LicenseException.cs
- FormsAuthenticationCredentials.cs
- MouseBinding.cs
- MapPathBasedVirtualPathProvider.cs
- XmlSerializer.cs
- CodeMemberProperty.cs
- DataGridViewControlCollection.cs
- PackagingUtilities.cs
- Int16Converter.cs
- AppDomainProtocolHandler.cs
- PageBuildProvider.cs
- HtmlControlDesigner.cs
- GcHandle.cs
- BinaryQueryOperator.cs
- TextHidden.cs
- WindowsSolidBrush.cs
- StringInfo.cs
- figurelengthconverter.cs
- XmlSchemaAnyAttribute.cs
- QilValidationVisitor.cs
- MembershipUser.cs
- Vector3DKeyFrameCollection.cs