Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataWeb / Client / System / Data / Services / Client / BaseAsyncResult.cs / 1305376 / BaseAsyncResult.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// query object
//
//---------------------------------------------------------------------
namespace System.Data.Services.Client
{
using System;
using System.Diagnostics;
#if !ASTORIA_LIGHT // Data.Services http stack
using System.Net;
#else
using System.Data.Services.Http;
#endif
///
/// Implementation of IAsyncResult
///
internal abstract class BaseAsyncResult : IAsyncResult
{
/// Originating object, used to validate End*
internal readonly object Source;
/// Originating method on source, to differentiate between different methods from same source
internal readonly string Method;
/// User callback passed to Begin*
private readonly AsyncCallback userCallback;
/// User state passed to Begin*
private readonly object userState;
/// wait handle for user to wait until done, we only use this within lock of asyncWaitDisposeLock.
private System.Threading.ManualResetEvent asyncWait;
/// Holding exception to throw as a nested exception during to End*
private Exception failure;
/// Abortable request
private WebRequest abortable;
/// true unless something completes asynchronously
private bool completedSynchronously = true;
/// true when really completed for the user
private bool userCompleted;
/// true when no more changes are pending, 0 false, 1 completed, 2 aborted
private int completed;
/// verify we only invoke the user callback once, 0 false, 1 true
private int userNotified;
/// non-zero after End*, 0 false, 1, true
private int done;
/// true if the AsyncWaitHandle has already been disposed.
private bool asyncWaitDisposed;
/// delay created object to lock to prevent using disposed asyncWait handle.
private object asyncWaitDisposeLock;
///
/// ctor
///
/// source object of async request
/// async method name on source object
/// user callback to invoke when complete
/// user state
internal BaseAsyncResult(object source, string method, AsyncCallback callback, object state)
{
Debug.Assert(null != source, "null source");
this.Source = source;
this.Method = method;
this.userCallback = callback;
this.userState = state;
}
#if ASTORIA_LIGHT
///
/// Generic function delegate that is declared in .Net Framework 4.0, but not .Net Framework 3.5 or Silverlight
///
/// type of parameter 1
/// type of parameter 2
/// type of parameter 3
/// type of parameter 4
/// type of parameter 5
/// type of result
/// generic parameter 1
/// generic parameter 2
/// generic parameter 3
/// generic parameter 4
/// generic parameter 5
/// generic result
internal delegate TResult Func(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
#endif
#region IAsyncResult implmentation - AsyncState, AsyncWaitHandle, CompletedSynchronously, IsCompleted
/// user state object parameter
public object AsyncState
{
get { return this.userState; }
}
/// wait handle for when waiting is required
/// if displayed by debugger, it undesirable to create the WaitHandle
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public System.Threading.WaitHandle AsyncWaitHandle
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "WaitHandle is disposed during EndXXX(IAsyncResult) method")]
get
{
if (null == this.asyncWait)
{ // delay create the wait handle since the user may never use it
// like asyncWait which will be GC'd, the losers in creating the asyncWait will also be GC'd
System.Threading.Interlocked.CompareExchange(ref this.asyncWait, new System.Threading.ManualResetEvent(this.IsCompleted), null);
// multi-thread condition
// 1) thread 1 returned IAsyncResult and !IsCompleted so AsyncWaitHandle.WaitOne()
// 2) thread 2 signals complete, however thread 1 has retrieved this.completed but not assigned asyncWait
if (this.IsCompleted)
{ // yes, Set may be called multiple times - but user would have to assume ManualResetEvent and call Reset
//
// There is a very small window for race condition between setting the wait handle here and disposing
// the wait handle inside EndExecute(). Say thread1 calls EndExecute() and IsCompleted is already true we won't
// create asyncWait from inside thread1, and thread2 wakes up right before thread1 tries to dispose the handle and
// thread2 calls AsyncWaitHandle which creates a new asyncWait handle, if thread1 wakes up right before the Set event
// here and disposes the asyncWait handle we just created here, Set() will throw ObjectDisposedException.
// SetAsyncWaitHandle() will protect this scenario with a critical section.
this.SetAsyncWaitHandle();
}
}
// Note that if the first time AsyncWaitHandle gets called is after EndExecute() is completed, we don't dispose the
// newly created handle, it'll just get GC'd.
return this.asyncWait;
}
}
/// did the result complete synchronously?
public bool CompletedSynchronously
{
get { return this.completedSynchronously; }
internal set { this.completedSynchronously = value; }
}
/// is the result complete?
public bool IsCompleted
{
get { return this.userCompleted; }
}
/// is the result complete?
internal bool IsCompletedInternally
{
get { return (0 != this.completed); }
}
/// abort the result
internal bool IsAborted
{
get { return (2 == this.completed); }
}
#endregion
///
/// WebRequest available for DataServiceContext.CancelRequest
///
internal WebRequest Abortable
{
get
{
return this.abortable;
}
set
{
this.abortable = value;
if ((null != value) && this.IsAborted)
{ // if the value hadn't been set yet, but aborting then propogate the abort
value.Abort();
}
}
}
/// first exception that happened
internal Exception Failure
{
get { return this.failure; }
}
///
/// common handler for EndExecuteBatch & EndSaveChanges
///
/// derived type of the AsyncResult
/// source object of async request
/// async method name on source object
/// the asyncResult being ended
/// data service response for batch
internal static T EndExecute(object source, string method, IAsyncResult asyncResult) where T : BaseAsyncResult
{
Util.CheckArgumentNull(asyncResult, "asyncResult");
T result = (asyncResult as T);
if ((null == result) || (source != result.Source) || (result.Method != method))
{
throw Error.Argument(Strings.Context_DidNotOriginateAsync, "asyncResult");
}
Debug.Assert((result.CompletedSynchronously && result.IsCompleted) || !result.CompletedSynchronously, "CompletedSynchronously && !IsCompleted");
if (!result.IsCompleted)
{ // if the user doesn't want to wait forever, they should explictly wait on the handle with a timeout
result.AsyncWaitHandle.WaitOne();
Debug.Assert(result.IsCompleted, "not completed after waiting");
}
// Prevent EndExecute from being called more than once.
if (System.Threading.Interlocked.Exchange(ref result.done, 1) != 0)
{
throw Error.Argument(Strings.Context_AsyncAlreadyDone, "asyncResult");
}
// Dispose the wait handle.
if (null != result.asyncWait)
{
System.Threading.Interlocked.CompareExchange(ref result.asyncWaitDisposeLock, new object(), null);
lock (result.asyncWaitDisposeLock)
{
result.asyncWaitDisposed = true;
Util.Dispose(result.asyncWait);
}
}
if (result.IsAborted)
{
throw Error.InvalidOperation(Strings.Context_OperationCanceled);
}
if (null != result.Failure)
{
if (Util.IsKnownClientExcption(result.Failure))
{
throw result.Failure;
}
throw Error.InvalidOperation(Strings.DataServiceException_GeneralError, result.Failure);
}
return result;
}
///
/// Due to the unexpected behaviors of IAsyncResult.CompletedSynchronously in the System.Net networking stack, we have to make
/// async calls to their APIs using the specific pattern they've prescribed. This method runs in the caller thread and invokes
/// the BeginXXX methods. It then checks IAsyncResult.CompletedSynchronously and if it is true, we invoke the callback in the
/// caller thread.
///
///
/// This is the action that invokes the BeginXXX method. Note we MUST use our special callback from GetDataServiceAsyncCallback()
/// when invoking the async call.
///
/// async callback to be called when the operation is complete
/// A user-provided object that distinguishes this particular asynchronous request from other requests.
/// Returns the async result from the BeginXXX method.
///
/// CompletedSynchronously (for System.Net networking stack) means "was the operation completed before the first time
/// that somebody asked if it was completed synchronously"? They do this because some of their asynchronous operations
/// (particularly those in the Socket class) will avoid the cost of capturing and transferring the ExecutionContext
/// to the callback thread by checking CompletedSynchronously, and calling the callback from within BeginXxx instead of
/// on the completion port thread if the native winsock call completes quickly.
///
/// For other operations however (notably those in HttpWebRequest), they use the same underlying IAsyncResult implementation,
/// but do NOT check CompletedSynchronously before returning from BeginXxx. That means that CompletedSynchronously will
/// be false if and only if you checked it from the thread which called BeginXxx BEFORE the operation completed. It will
/// then continue to be false even after IsCompleted becomes true.
///
/// Note that CompletedSynchronously == true does not guarantee anything about how much of your callback has executed.
///
/// The usual pattern for handling synchronous completion is that both the caller and callback should check CompletedSynchronously.
/// If its true, the callback should do nothing and the caller should call EndRead and process the result.
/// This guarantees that the caller and callback are not accessing the stream or buffer concurrently without the need
/// for explicit synchronization between the two.
///
internal static IAsyncResult InvokeAsync(Func asyncAction, AsyncCallback callback, object state)
{
IAsyncResult asyncResult = asyncAction(BaseAsyncResult.GetDataServiceAsyncCallback(callback), state);
return PostInvokeAsync(asyncResult, callback);
}
///
/// Due to the unexpected behaviors of IAsyncResult.CompletedSynchronously in the System.Net networking stack, we have to make
/// async calls to their APIs using the specific pattern they've prescribed. This method runs in the caller thread and invokes
/// the BeginXXX methods. It then checks IAsyncResult.CompletedSynchronously and if it is true, we invoke the callback in the
/// caller thread.
///
///
/// This is the action that invokes the BeginXXX method. Note we MUST use our special callback from GetDataServiceAsyncCallback()
/// when invoking the async call.
///
/// buffer to transfer the data
/// byte offset in buffer
/// max number of bytes in the buffer
/// async callback to be called when the operation is complete
/// A user-provided object that distinguishes this particular asynchronous request from other requests.
/// An IAsyncResult that represents the asynchronous operation, which could still be pending
/// Please see remarks on the other InvokeAsync() overload.
internal static IAsyncResult InvokeAsync(Func asyncAction, byte[] buffer, int offset, int length, AsyncCallback callback, object state)
{
IAsyncResult asyncResult = asyncAction(buffer, offset, length, BaseAsyncResult.GetDataServiceAsyncCallback(callback), state);
return PostInvokeAsync(asyncResult, callback);
}
/// Set the AsyncWait and invoke the user callback.
///
/// If the background thread gets a ThreadAbort, the userCallback will never be invoked.
/// This is why it's generally important to never wait forever, but to have more specific
/// time limit. Also then cancel the operation, to make sure its stopped, to avoid
/// multi-threading if your wait time limit was just too short.
///
internal void HandleCompleted()
{
// Dev10 Bug #524145: even if background thread of async operation encounters
// an "uncatchable" exception, do the minimum to unblock the async result.
if (this.IsCompletedInternally && (System.Threading.Interlocked.Exchange(ref this.userNotified, 1) == 0))
{
this.abortable = null; // reset abort via CancelRequest
try
{
// avoid additional work when aborting for exceptional reasons
if (!Util.DoNotHandleException(this.Failure))
{
// the CompleteRequest may do additional work which is why
// it is important not to signal the user via either the
// IAsyncResult.IsCompleted, IAsyncResult.WaitHandle or the callback
this.CompletedRequest();
}
}
catch (Exception ex)
{
if (this.HandleFailure(ex))
{
throw;
}
}
finally
{
// 1. set IAsyncResult.IsCompleted, otherwise user was
// signalled on another thread, but the property may not be true.
this.userCompleted = true;
// 2. signal the wait handle because it can't be first nor can it be last.
//
// There is a very small window for race condition between setting the wait handle here and disposing
// the wait handle inside EndExecute(). Say thread1 is the async thread that executes up till this point, i.e. right
// after userCompleted is set to true and before the asyncWait is signaled; thread2 wakes up and calls EndExecute() till
// right before we try to dispose the wait handle; thread3 wakes up and calls AsyncWaitHandle which creates a new instance
// for this.asyncWait; thread2 then resumes to dispose this.asyncWait and if at this point thread1 sets this.asyncWait,
// we'll get an ObjectDisposedException on thread1. SetAsyncWaitHandle() will protect this scenario with a critical section.
this.SetAsyncWaitHandle();
// 3. invoke the callback because user may throw an exception and stop any further processing
if ((null != this.userCallback) && !(this.Failure is System.Threading.ThreadAbortException) && !(this.Failure is System.StackOverflowException))
{ // any exception thrown by user should be "unhandled"
// it's possible callback will be invoked while another creates and sets the asyncWait
this.userCallback(this);
}
}
}
}
/// Cache the exception that happened on the background thread for the caller of EndSaveChanges.
/// exception object from background thread
/// true if the exception (like StackOverflow or ThreadAbort) should be rethrown
internal bool HandleFailure(Exception e)
{
System.Threading.Interlocked.CompareExchange(ref this.failure, e, null);
this.SetCompleted();
return Util.DoNotHandleException(e);
}
/// Set the async result as completed and aborted.
internal void SetAborted()
{
System.Threading.Interlocked.Exchange(ref this.completed, 2);
}
/// Set the async result as completed.
internal void SetCompleted()
{
System.Threading.Interlocked.CompareExchange(ref this.completed, 1, 0);
}
/// invoked for derived classes to cleanup before callback is invoked
protected abstract void CompletedRequest();
///
/// Due to the unexpected behaviors of IAsyncResult.CompletedSynchronously in the System.Net networking stack, we have to make
/// async calls to their APIs using the specific pattern they've prescribed. This method runs in the caller thread after the
/// BeginXXX method returns. It checks IAsyncResult.CompletedSynchronously and if it is true, we invoke the callback in the
/// caller thread.
///
/// The IAsyncResult that represents the asynchronous operation we just called, which could still be pending
/// Callback to be invoked when IAsyncResult.CompletedSynchronously is true.
/// Returns an IAsyncResult that represents the asynchronous operation we just called, which could still be pending
/// Please see remarks on BaseAsyncResult.InvokeAsync().
private static IAsyncResult PostInvokeAsync(IAsyncResult asyncResult, AsyncCallback callback)
{
Debug.Assert(asyncResult != null, "asyncResult != null");
if (asyncResult.CompletedSynchronously)
{
Debug.Assert(asyncResult.IsCompleted, "asyncResult.IsCompleted");
callback(asyncResult);
}
return asyncResult;
}
///
/// Due to the unexpected behaviors of IAsyncResult.CompletedSynchronously in the System.Net networking stack, we have to make
/// async calls to their APIs using the specific pattern they've prescribed. This method returns an AsyncCallback which we can pass
/// to the BeginXXX methods in the caller thread. The returned callback will only run the wrapped callback if
/// IAsyncResult.CompletedSynchronously is false, otherwise it returns immediately.
///
/// callback to be wrapped
/// Returnes a callback which will only run the wrapped callback if IAsyncResult.CompletedSynchronously is false, otherwise it returns immediately.
/// Please see remarks on BaseAsyncResult.InvokeAsync().
private static AsyncCallback GetDataServiceAsyncCallback(AsyncCallback callback)
{
return (asyncResult) =>
{
Debug.Assert(asyncResult != null && asyncResult.IsCompleted, "asyncResult != null && asyncResult.IsCompleted");
if (asyncResult.CompletedSynchronously)
{
return;
}
callback(asyncResult);
};
}
///
/// Sets the async wait handle
///
private void SetAsyncWaitHandle()
{
if (null != this.asyncWait)
{
System.Threading.Interlocked.CompareExchange(ref this.asyncWaitDisposeLock, new object(), null);
lock (this.asyncWaitDisposeLock)
{
if (!this.asyncWaitDisposed)
{
this.asyncWait.Set();
}
}
}
}
}
}
// 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
- DataRelationCollection.cs
- StreamHelper.cs
- DefaultShape.cs
- StyleCollectionEditor.cs
- PageFunction.cs
- TextPattern.cs
- TextElementCollectionHelper.cs
- DbCommandTree.cs
- serverconfig.cs
- SqlCommandBuilder.cs
- SchemaInfo.cs
- TrustLevelCollection.cs
- TextTreeRootTextBlock.cs
- ConfigurationStrings.cs
- GridViewUpdateEventArgs.cs
- ParallelLoopState.cs
- NoPersistHandle.cs
- WebPartConnection.cs
- XappLauncher.cs
- TabPanel.cs
- Constants.cs
- NamespaceDecl.cs
- ResourceSetExpression.cs
- CopyAttributesAction.cs
- IncrementalCompileAnalyzer.cs
- DataBoundControlAdapter.cs
- LinqDataSourceDeleteEventArgs.cs
- Tag.cs
- XmlTextReader.cs
- HeaderUtility.cs
- DataServiceRequestException.cs
- DataTablePropertyDescriptor.cs
- TdsParserSafeHandles.cs
- EventSinkActivity.cs
- SetStateEventArgs.cs
- VisualStateGroup.cs
- HtmlInputButton.cs
- ArrayTypeMismatchException.cs
- XmlSchemaObjectTable.cs
- ParallelSeparator.xaml.cs
- XmlFormatExtensionAttribute.cs
- ProgressBarAutomationPeer.cs
- HotCommands.cs
- Attribute.cs
- EntityProxyFactory.cs
- RMEnrollmentPage3.cs
- Debug.cs
- TrackingStringDictionary.cs
- MdImport.cs
- XmlDocumentType.cs
- SendMessageChannelCache.cs
- PrintingPermission.cs
- TypeBinaryExpression.cs
- PopupRootAutomationPeer.cs
- DiscreteKeyFrames.cs
- ThreadAbortException.cs
- SetStoryboardSpeedRatio.cs
- SymLanguageType.cs
- GridItemProviderWrapper.cs
- SafeHandle.cs
- DispatcherTimer.cs
- TextServicesHost.cs
- MarkupCompilePass1.cs
- ToolStripComboBox.cs
- ProcessModelSection.cs
- WsdlExporter.cs
- SafeHandle.cs
- FacetEnabledSchemaElement.cs
- RIPEMD160.cs
- ItemsControlAutomationPeer.cs
- RMEnrollmentPage3.cs
- OpacityConverter.cs
- HttpConfigurationSystem.cs
- BaseTemplateCodeDomTreeGenerator.cs
- TextRange.cs
- NeedSkipTokenVisitor.cs
- DetailsViewUpdatedEventArgs.cs
- HtmlShim.cs
- CacheSection.cs
- PolicyVersion.cs
- UseAttributeSetsAction.cs
- AggregateNode.cs
- CmsInterop.cs
- WebHttpBehavior.cs
- PrintPreviewControl.cs
- HMACMD5.cs
- Thread.cs
- InputScopeNameConverter.cs
- ContextMenuAutomationPeer.cs
- BlurEffect.cs
- Permission.cs
- ImplicitInputBrush.cs
- StringArrayConverter.cs
- GridViewAutomationPeer.cs
- SynchronizationHandlesCodeDomSerializer.cs
- ListItem.cs
- DataGridViewCheckBoxCell.cs
- FontSizeConverter.cs
- SessionSwitchEventArgs.cs
- DelimitedListTraceListener.cs