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 Int32 _statePending = 0; private const Int32 _stateCompletedSynchronously = 1; private const Int32 _stateCompletedAsynchronously = 2; private Int32 _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 EndInvoke has been called on the current AsyncResult. /// /// /// true if EndInvoke has been called on the current AsyncResult; otherwise, false. /// public bool EndInvokeCalled { get; private set; } /// /// Initializes a new instance of the class. /// /// The async callback. /// The state. public AsyncResult(AsyncCallback asyncCallback, Object state) { this._asyncCallback = asyncCallback; this._asyncState = state; } /// /// Marks asynchronous operation as completed. /// /// The exception. /// if set to true [completed synchronously]. public void SetAsCompleted(Exception exception, Boolean completedSynchronously) { // Passing null for exception means no error occurred; this is the common case this._exception = exception; // The m_CompletedState field MUST be set prior calling the callback Int32 prevState = Interlocked.Exchange(ref this._completedState, completedSynchronously ? _stateCompletedSynchronously : _stateCompletedAsynchronously); if (prevState != _statePending) throw new InvalidOperationException("You can set a result only once"); // If the event exists, set it if (this._asyncWaitHandle != null) this._asyncWaitHandle.Set(); // If a callback method was set, call it if (this._asyncCallback != null) this._asyncCallback(this); } /// /// Waits until the asynchronous operation completes, and then returns. /// public void EndInvoke() { // This method assumes that only 1 thread calls EndInvoke for this object if (!this.IsCompleted) { // If the operation isn't done, wait for it AsyncWaitHandle.WaitOne(); AsyncWaitHandle.Close(); this._asyncWaitHandle = null; // Allow early GC } this.EndInvokeCalled = true; // Operation is done: if an exception occurred, throw it if (this._exception != null) throw new SshException(this._exception.Message, this._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 this._asyncState; } } /// /// Gets a value that indicates whether the asynchronous operation completed synchronously. /// /// true if the asynchronous operation completed synchronously; otherwise, false. public Boolean CompletedSynchronously { get { return this._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 (this._asyncWaitHandle == null) { Boolean done = this.IsCompleted; ManualResetEvent mre = new ManualResetEvent(done); if (Interlocked.CompareExchange(ref this._asyncWaitHandle, mre, null) != null) { // Another thread created this object's event; dispose the event we just created mre.Close(); } else { if (!done && this.IsCompleted) { // If the operation wasn't done when we created // the event but now it is done, set the event this._asyncWaitHandle.Set(); } } } return this._asyncWaitHandle; } } /// /// Gets a value that indicates whether the asynchronous operation has completed. /// /// true if the operation is complete; otherwise, false. public Boolean IsCompleted { get { return this._completedState != _statePending; } } #endregion } /// /// Base class to encapsulates the results of an asynchronous operation that returns result. /// public abstract class AsyncResult : AsyncResult { // Field set when operation completes private TResult _result = default(TResult); /// /// Initializes a new instance of the class. /// /// The async callback. /// The state. public 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, Boolean completedSynchronously) { // Save the asynchronous operation's result this._result = result; // Tell the base class that the operation completed successfully (no exception) base.SetAsCompleted(null, completedSynchronously); } /// /// Waits until the asynchronous operation completes, and then returns the value generated by the asynchronous operation. /// /// new public TResult EndInvoke() { base.EndInvoke(); // Wait until operation has completed return _result; // Return the result (if above didn't throw) } } }