| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.Runtime
- {
- using System;
- using System.Diagnostics;
- using System.Diagnostics.CodeAnalysis;
- using System.Threading;
- // 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;
- object state;
- Action beforePrepareAsyncCompletionAction;
- Func<IAsyncResult, bool> checkSyncValidationFunc;
- [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<AsyncResult, Exception> 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<AsyncCallback, IAsyncResult> VirtualCallback
- {
- get;
- set;
- }
- protected void Complete(bool completedSynchronously)
- {
- if (this.isCompleted)
- {
- throw Fx.Exception.AsError(new InvalidOperationException(InternalSR.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(InternalSR.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(InternalSR.InvalidNullAsyncResult));
- }
- if (result.CompletedSynchronously)
- {
- return;
- }
- AsyncResult thisPtr = (AsyncResult)result.AsyncState;
- if (!thisPtr.OnContinueAsyncCompletion(result))
- {
- 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);
- }
- }
- // Note: this should be only derived by the TransactedAsyncResult
- protected virtual bool OnContinueAsyncCompletion(IAsyncResult result)
- {
- return true;
- }
- // Note: this should be used only by the TransactedAsyncResult
- protected void SetBeforePrepareAsyncCompletionAction(Action beforePrepareAsyncCompletionAction)
- {
- this.beforePrepareAsyncCompletionAction = beforePrepareAsyncCompletionAction;
- }
- // Note: this should be used only by the TransactedAsyncResult
- protected void SetCheckSyncValidationFunc(Func<IAsyncResult, bool> checkSyncValidationFunc)
- {
- this.checkSyncValidationFunc = checkSyncValidationFunc;
- }
- protected AsyncCallback PrepareAsyncCompletion(AsyncCompletion callback)
- {
- if (this.beforePrepareAsyncCompletionAction != null)
- {
- this.beforePrepareAsyncCompletionAction();
- }
- this.nextAsyncCompletion = callback;
- if (AsyncResult.asyncCompletionWrapperCallback == null)
- {
- AsyncResult.asyncCompletionWrapperCallback = Fx.ThunkCallback(new AsyncCallback(AsyncCompletionWrapperCallback));
- }
- return AsyncResult.asyncCompletionWrapperCallback;
- }
- 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(InternalSR.InvalidNullAsyncResult));
- }
- callback = null;
- if (this.checkSyncValidationFunc != null)
- {
- if (!this.checkSyncValidationFunc(result))
- {
- return false;
- }
- }
- else if (!result.CompletedSynchronously)
- {
- 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.nextAsyncCompletion = null;
- return result;
- }
- protected static void ThrowInvalidAsyncResult(IAsyncResult result)
- {
- throw Fx.Exception.AsError(new InvalidOperationException(InternalSR.InvalidAsyncResultImplementation(result.GetType())));
- }
- protected static void ThrowInvalidAsyncResult(string debugText)
- {
- string message = InternalSR.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<TAsyncResult>(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", InternalSR.InvalidAsyncResult);
- }
- if (asyncResult.endCalled)
- {
- throw Fx.Exception.AsError(new InvalidOperationException(InternalSR.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;
- }
- // 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
- }
- }
|