using System; using System.Threading; namespace Renci.SshNet.Common { /// /// Base class to encapsulates the results of an asynchronous operation. /// public abstract class AsyncResult : IAsyncResult { // Fields set at construction which never change while operation is pending private readonly AsyncCallback _asyncCallback; private readonly object _asyncState; // Field set at construction which do change after operation completes private const int StatePending = 0; private const int StateCompletedSynchronously = 1; private const int StateCompletedAsynchronously = 2; private int _completedState = StatePending; // Field that may or may not get set depending on usage private ManualResetEvent _asyncWaitHandle; // Fields set when operation completes private Exception _exception; /// /// Gets or sets a value indicating whether has been called on the current /// . /// /// /// true if has been called on the current ; /// otherwise, false. /// public bool EndInvokeCalled { get; private set; } /// /// Initializes a new instance of the class. /// /// The async callback. /// The state. protected AsyncResult(AsyncCallback asyncCallback, object state) { _asyncCallback = asyncCallback; _asyncState = state; } /// /// Marks asynchronous operation as completed. /// /// The exception. /// if set to true [completed synchronously]. public void SetAsCompleted(Exception exception, bool completedSynchronously) { // Passing null for exception means no error occurred; this is the common case _exception = exception; // The m_CompletedState field MUST be set prior calling the callback var prevState = Interlocked.Exchange(ref _completedState, completedSynchronously ? StateCompletedSynchronously : StateCompletedAsynchronously); if (prevState != StatePending) throw new InvalidOperationException("You can set a result only once"); // If the event exists, set it if (_asyncWaitHandle != null) _asyncWaitHandle.Set(); // If a callback method was set, call it if (_asyncCallback != null) _asyncCallback(this); } /// /// Waits until the asynchronous operation completes, and then returns. /// internal void EndInvoke() { // This method assumes that only 1 thread calls EndInvoke for this object if (!IsCompleted) { // If the operation isn't done, wait for it AsyncWaitHandle.WaitOne(); _asyncWaitHandle = null; // Allow early GC AsyncWaitHandle.Dispose(); } EndInvokeCalled = true; // Operation is done: if an exception occurred, throw it if (_exception != null) throw _exception; } #region Implementation of IAsyncResult /// /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. /// /// A user-defined object that qualifies or contains information about an asynchronous operation. public object AsyncState { get { return _asyncState; } } /// /// Gets a value that indicates whether the asynchronous operation completed synchronously. /// /// true if the asynchronous operation completed synchronously; otherwise, false. public bool CompletedSynchronously { get { return _completedState == StateCompletedSynchronously; } } /// /// Gets a that is used to wait for an asynchronous operation to complete. /// /// A that is used to wait for an asynchronous operation to complete. public WaitHandle AsyncWaitHandle { get { if (_asyncWaitHandle == null) { var done = IsCompleted; var mre = new ManualResetEvent(done); if (Interlocked.CompareExchange(ref _asyncWaitHandle, mre, null) != null) { // Another thread created this object's event; dispose the event we just created mre.Dispose(); } else { if (!done && IsCompleted) { // If the operation wasn't done when we created // the event but now it is done, set the event _asyncWaitHandle.Set(); } } } return _asyncWaitHandle; } } /// /// Gets a value that indicates whether the asynchronous operation has completed. /// /// /// true if the operation is complete; otherwise, false. public bool IsCompleted { get { return _completedState != StatePending; } } #endregion } /// /// Base class to encapsulates the results of an asynchronous operation that returns result. /// /// The type of the result. public abstract class AsyncResult : AsyncResult { // Field set when operation completes private TResult _result; /// /// Initializes a new instance of the class. /// /// The async callback. /// The state. protected AsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) { } /// /// Marks asynchronous operation as completed. /// /// The result. /// if set to true [completed synchronously]. public void SetAsCompleted(TResult result, bool completedSynchronously) { // Save the asynchronous operation's result _result = result; // Tell the base class that the operation completed successfully (no exception) SetAsCompleted(null, completedSynchronously); } /// /// Waits until the asynchronous operation completes, and then returns the value generated by the asynchronous operation. /// /// /// The invocation result. /// public new TResult EndInvoke() { base.EndInvoke(); // Wait until operation has completed return _result; // Return the result (if above didn't throw) } } }