using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Threading;
namespace PleaseIgnore.IntelMap {
///
/// Implementation of , providing common
/// support for asynchronous function calls in PleaseIgnore.
///
///
/// The return of the EndName
/// call.
///
internal class IntelAsyncResult : IAsyncResult {
// The callback to call when execution has completed
private readonly AsyncCallback callback;
// The value of AsyncState
[ContractPublicPropertyName("AsyncState")]
private readonly object state;
// Number of waits made on End*()
private int waitCount;
// Set to true once the asynchronous execution has completed
[ContractPublicPropertyName("IsCompleted")]
private bool completed;
// Set to true if the execution was completed synchronously
[ContractPublicPropertyName("CompletedSynchronously")]
private bool synchronous;
// The return value of a successful asynchronous execution
private TResult result;
// The exception object for an unsuccessful asychronous execution
private Exception exception;
// The WaitHandle instance to use when waiting for completion. Populated
// by AsyncWaitHandle only as needed.
private ManualResetEvent waitHandle;
///
/// Initializes a new instance of the
/// class.
///
///
/// The to call when the asynchronous
/// operation completes. This can be .
///
///
/// The value of . This can be
/// .
///
///
/// is .
///
protected IntelAsyncResult(AsyncCallback callback, object state) {
Contract.Ensures(this.AsyncState == state);
Contract.Ensures(!this.IsCompleted);
this.callback = callback;
this.state = state;
}
///
/// Gets a user-defined object that qualifies or contains information
/// about an asynchronous operation.
///
public object AsyncState { get { return this.state; } }
///
/// Gets a value that indicates whether the asynchronous operation
/// completed synchronously.
///
public bool CompletedSynchronously { get { return this.synchronous; } }
///
/// Gets a value that indicates whether the asynchronous operation
/// has completed.
///
public bool IsCompleted { get { return this.completed; } }
///
/// Gets a that is used to wait for an
/// asynchronous operation to complete.
///
public WaitHandle AsyncWaitHandle {
get {
Contract.Ensures(Contract.Result() != null);
var handle = new ManualResetEvent(false);
var oldhandle = Interlocked.CompareExchange(
ref this.waitHandle,
handle,
null);
// XXX: CodeContracts doesn't seem to realize that CompareExchange
// (above) will leave this.waitHandle as not null.
Contract.Assume(this.waitHandle != null);
if (this.completed) {
this.waitHandle.Set();
}
if (oldhandle != null) {
// XXX: CompareExchange returns the /original/ value. If the
// original value is not null, it was not replaced, so we need
// to delete the new object we created.
handle.Close();
}
return this.waitHandle;
}
}
///
/// Signals that the asychronous operation has completed
/// successfully.
///
///
/// The return code for the End*() method.
///
///
/// The value to assign to .
///
///
/// If a callback was provided at
/// initialization, it will be queued onto the
/// .
///
protected void Complete(TResult result, bool completeSynchronously) {
Contract.Requires(!this.IsCompleted);
Contract.Ensures(this.CompletedSynchronously == completeSynchronously);
Contract.Ensures(this.IsCompleted);
this.completed = true;
this.result = result;
this.synchronous = completeSynchronously;
Thread.MemoryBarrier();
if (this.waitHandle != null) {
this.waitHandle.Set();
}
if (this.callback != null) {
ThreadPool.QueueUserWorkItem(this.UserCallback);
}
}
///
/// Signals that the asychronous operation was aborted due to
/// an error.
///
///
/// The exception to throw from the End*() method.
///
///
/// The value to assign to .
///
///
/// If a callback was provided at
/// initialization, it will be queued onto the
/// .
///
protected void Complete(Exception exception, bool completeSynchronously) {
Contract.Requires(exception != null);
Contract.Requires(!this.IsCompleted);
Contract.Ensures(this.CompletedSynchronously == completeSynchronously);
Contract.Ensures(this.IsCompleted);
this.completed = true;
this.exception = exception;
this.synchronous = completeSynchronously;
Thread.MemoryBarrier();
if (this.waitHandle != null) {
this.waitHandle.Set();
}
if (callback != null) {
ThreadPool.QueueUserWorkItem(this.UserCallback);
}
}
///
/// Waits for the asynchronous call to complete, returning the queued
/// value or throwing an exception as appropriate.
///
///
/// The name of the function being used to wait on this
/// .
///
///
/// The value provided to or
/// .
///
///
/// is or
/// .
///
///
/// A call has already been made to on this
/// instance of .
///
///
/// Any exception registered by calling
/// .
///
public TResult Wait(string methodName) {
Contract.Requires(!String.IsNullOrEmpty(methodName));
Contract.Ensures(this.completed);
var old = Interlocked.CompareExchange(ref waitCount, 1, 0);
if (old != 0) {
throw new InvalidOperationException(string.Format(
CultureInfo.CurrentCulture,
Properties.Resources.InvalidOperation_MultipleCalls,
methodName));
}
if (!this.completed) {
this.AsyncWaitHandle.WaitOne();
Contract.Assert(this.completed);
}
if (this.exception != null) {
throw this.exception;
} else {
return this.result;
}
}
///
/// ThreadPool callback.
///
private void UserCallback(object state) {
Contract.Requires(this.callback != null);
this.callback(this);
}
}
}