2
0

AsyncResult.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using System;
  2. using System.Threading;
  3. namespace Renci.SshNet.Common
  4. {
  5. /// <summary>
  6. /// Base class to encapsulates the results of an asynchronous operation.
  7. /// </summary>
  8. public abstract class AsyncResult : IAsyncResult
  9. {
  10. // Fields set at construction which never change while operation is pending
  11. private readonly AsyncCallback _asyncCallback;
  12. private readonly Object _asyncState;
  13. // Field set at construction which do change after operation completes
  14. private const Int32 _statePending = 0;
  15. private const Int32 _stateCompletedSynchronously = 1;
  16. private const Int32 _stateCompletedAsynchronously = 2;
  17. private Int32 _completedState = _statePending;
  18. // Field that may or may not get set depending on usage
  19. private ManualResetEvent _asyncWaitHandle;
  20. // Fields set when operation completes
  21. private Exception _exception;
  22. /// <summary>
  23. /// Gets or sets a value indicating whether EndInvoke has been called on the current AsyncResult.
  24. /// </summary>
  25. /// <value>
  26. /// <c>true</c> if EndInvoke has been called on the current AsyncResult; otherwise, <c>false</c>.
  27. /// </value>
  28. public bool EndInvokeCalled { get; private set; }
  29. /// <summary>
  30. /// Initializes a new instance of the <see cref="AsyncResult"/> class.
  31. /// </summary>
  32. /// <param name="asyncCallback">The async callback.</param>
  33. /// <param name="state">The state.</param>
  34. public AsyncResult(AsyncCallback asyncCallback, Object state)
  35. {
  36. this._asyncCallback = asyncCallback;
  37. this._asyncState = state;
  38. }
  39. /// <summary>
  40. /// Marks asynchronous operation as completed.
  41. /// </summary>
  42. /// <param name="exception">The exception.</param>
  43. /// <param name="completedSynchronously">if set to <c>true</c> [completed synchronously].</param>
  44. public void SetAsCompleted(Exception exception, Boolean completedSynchronously)
  45. {
  46. // Passing null for exception means no error occurred; this is the common case
  47. this._exception = exception;
  48. // The m_CompletedState field MUST be set prior calling the callback
  49. Int32 prevState = Interlocked.Exchange(ref this._completedState,
  50. completedSynchronously ? _stateCompletedSynchronously : _stateCompletedAsynchronously);
  51. if (prevState != _statePending)
  52. throw new InvalidOperationException("You can set a result only once");
  53. // If the event exists, set it
  54. if (this._asyncWaitHandle != null)
  55. this._asyncWaitHandle.Set();
  56. // If a callback method was set, call it
  57. if (this._asyncCallback != null)
  58. this._asyncCallback(this);
  59. }
  60. /// <summary>
  61. /// Waits until the asynchronous operation completes, and then returns.
  62. /// </summary>
  63. public void EndInvoke()
  64. {
  65. // This method assumes that only 1 thread calls EndInvoke for this object
  66. if (!this.IsCompleted)
  67. {
  68. // If the operation isn't done, wait for it
  69. AsyncWaitHandle.WaitOne();
  70. AsyncWaitHandle.Close();
  71. this._asyncWaitHandle = null; // Allow early GC
  72. }
  73. this.EndInvokeCalled = true;
  74. // Operation is done: if an exception occurred, throw it
  75. if (this._exception != null)
  76. throw new SshException(this._exception.Message, this._exception);
  77. }
  78. #region Implementation of IAsyncResult
  79. /// <summary>
  80. /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
  81. /// </summary>
  82. /// <returns>A user-defined object that qualifies or contains information about an asynchronous operation.</returns>
  83. public Object AsyncState { get { return this._asyncState; } }
  84. /// <summary>
  85. /// Gets a value that indicates whether the asynchronous operation completed synchronously.
  86. /// </summary>
  87. /// <returns>true if the asynchronous operation completed synchronously; otherwise, false.</returns>
  88. public Boolean CompletedSynchronously
  89. {
  90. get { return this._completedState == _stateCompletedSynchronously; }
  91. }
  92. /// <summary>
  93. /// Gets a <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.
  94. /// </summary>
  95. /// <returns>A <see cref="T:System.Threading.WaitHandle"/> that is used to wait for an asynchronous operation to complete.</returns>
  96. public WaitHandle AsyncWaitHandle
  97. {
  98. get
  99. {
  100. if (this._asyncWaitHandle == null)
  101. {
  102. var done = this.IsCompleted;
  103. var mre = new ManualResetEvent(done);
  104. if (Interlocked.CompareExchange(ref this._asyncWaitHandle, mre, null) != null)
  105. {
  106. // Another thread created this object's event; dispose the event we just created
  107. mre.Close();
  108. }
  109. else
  110. {
  111. if (!done && this.IsCompleted)
  112. {
  113. // If the operation wasn't done when we created
  114. // the event but now it is done, set the event
  115. this._asyncWaitHandle.Set();
  116. }
  117. }
  118. }
  119. return this._asyncWaitHandle;
  120. }
  121. }
  122. /// <summary>
  123. /// Gets a value that indicates whether the asynchronous operation has completed.
  124. /// </summary>
  125. /// <returns>true if the operation is complete; otherwise, false.</returns>
  126. public Boolean IsCompleted
  127. {
  128. get { return this._completedState != _statePending; }
  129. }
  130. #endregion
  131. }
  132. /// <summary>
  133. /// Base class to encapsulates the results of an asynchronous operation that returns result.
  134. /// </summary>
  135. /// <typeparam name="TResult">The type of the result.</typeparam>
  136. public abstract class AsyncResult<TResult> : AsyncResult
  137. {
  138. // Field set when operation completes
  139. private TResult _result = default(TResult);
  140. /// <summary>
  141. /// Initializes a new instance of the <see cref="AsyncResult&lt;TResult&gt;"/> class.
  142. /// </summary>
  143. /// <param name="asyncCallback">The async callback.</param>
  144. /// <param name="state">The state.</param>
  145. public AsyncResult(AsyncCallback asyncCallback, Object state)
  146. : base(asyncCallback, state)
  147. {
  148. }
  149. /// <summary>
  150. /// Marks asynchronous operation as completed.
  151. /// </summary>
  152. /// <param name="result">The result.</param>
  153. /// <param name="completedSynchronously">if set to <c>true</c> [completed synchronously].</param>
  154. public void SetAsCompleted(TResult result, Boolean completedSynchronously)
  155. {
  156. // Save the asynchronous operation's result
  157. this._result = result;
  158. // Tell the base class that the operation completed successfully (no exception)
  159. base.SetAsCompleted(null, completedSynchronously);
  160. }
  161. /// <summary>
  162. /// Waits until the asynchronous operation completes, and then returns the value generated by the asynchronous operation.
  163. /// </summary>
  164. /// <returns>Invocation result</returns>
  165. new public TResult EndInvoke()
  166. {
  167. base.EndInvoke(); // Wait until operation has completed
  168. return _result; // Return the result (if above didn't throw)
  169. }
  170. }
  171. }