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); } } }