MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Threading;5 6using Dbg = System.Management.Automation.Diagnostics;7 8namespace System.Management.Automation.Runspaces9{10 /// <summary>11 /// Base class for AsyncResult objects that are returned by various12 /// Async operations supported by RunspacePool , PowerShell types.13 /// </summary>14 internal class AsyncResult : IAsyncResult15 {16 #region Private Data17 18 private ManualResetEvent _completedWaitHandle;19 // exception occurred in the async thread.20 // user supplied state object21 22 // Invoke on thread (remote debugging support).23 private AutoResetEvent _invokeOnThreadEvent;24 private WaitCallback _invokeCallback;25 private object _invokeCallbackState;26 27 #endregion28 29 #region Constructor30 31 /// <summary>32 /// Constructor.33 /// </summary>34 /// <param name="ownerId">35 /// Instance Id of the object creating this instance36 /// </param>37 /// <param name="callback">38 /// A AsyncCallback to call once the async operation completes.39 /// </param>40 /// <param name="state">41 /// A user supplied state object42 /// </param>43 internal AsyncResult(Guid ownerId, AsyncCallback callback, object state)44 {45 Dbg.Assert(ownerId != Guid.Empty, "ownerId cannot be empty");46 OwnerId = ownerId;47 Callback = callback;48 AsyncState = state;49 }50 51 #endregion52 53 #region IAsync Overrides54 55 /// <summary>56 /// This always returns false.57 /// </summary>58 public bool CompletedSynchronously59 {60 get61 {62 return false;63 }64 }65 66 /// <summary>67 /// Gets an indication whether the asynchronous operation has completed.68 /// </summary>69 public bool IsCompleted { get; private set; }70 71 /// <summary>72 /// This is not supported and returns null.73 /// </summary>74 public object AsyncState { get; }75 76 /// <summary>77 /// Gets a System.Threading.WaitHandle that is used to wait for an asynchronous78 /// operation to complete.79 /// </summary>80 public WaitHandle AsyncWaitHandle81 {82 get83 {84 if (_completedWaitHandle == null)85 {86 lock (SyncObject)87 {88 _completedWaitHandle ??= new ManualResetEvent(IsCompleted);89 }90 }91 92 return _completedWaitHandle;93 }94 }95 96 #endregion97 98 #region properties / methods99 100 /// <summary>101 /// Instance Id of the object owning this async result.102 /// </summary>103 internal Guid OwnerId { get; }104 105 /// <summary>106 /// Gets the exception that occurred while processing the107 /// async operation.108 /// </summary>109 internal Exception Exception { get; private set; }110 111 /// <summary>112 /// User supplied callback.113 /// </summary>114 internal AsyncCallback Callback { get; }115 116 /// <summary>117 /// SyncObject.118 /// </summary>119 internal object SyncObject { get; } = new object();120 121 /// <summary>122 /// Marks the async operation as completed.123 /// </summary>124 /// <param name="exception">125 /// Exception occurred. null if no exception occurred126 /// </param>127 internal void SetAsCompleted(Exception exception)128 {129 // Dbg.Assert(!isCompleted, "AsynResult already completed");130 if (IsCompleted)131 {132 return;133 }134 135 lock (SyncObject)136 {137 if (IsCompleted)138 {139 return;140 }141 else142 {143 Exception = exception;144 IsCompleted = true;145 146 // release the threads waiting on this operation.147 SignalWaitHandle();148 }149 }150 151 // call the user supplied callback152 Callback?.Invoke(this);153 }154 155 /// <summary>156 /// Release the asyncResult without calling the callback.157 /// </summary>158 internal void Release()159 {160 if (!IsCompleted)161 {162 IsCompleted = true;163 SignalWaitHandle();164 }165 }166 167 #endregion168 169 #region internal methods170 171 /// <summary>172 /// Signal wait handle of this async result.173 /// </summary>174 internal void SignalWaitHandle()175 {176 lock (SyncObject)177 {178 _completedWaitHandle?.Set();179 }180 }181 182 /// <summary>183 /// Wait for the operation to complete and throw the exception if any.184 /// </summary>185 internal void EndInvoke()186 {187 _invokeOnThreadEvent = new AutoResetEvent(false);188 189 // Start the thread wait loop.190 WaitHandle[] waitHandles = new WaitHandle[2] { AsyncWaitHandle, _invokeOnThreadEvent };191 bool waiting = true;192 while (waiting)193 {194 int waitIndex = WaitHandle.WaitAny(waitHandles);195 196 if (waitIndex == 0)197 {198 waiting = false;199 }200 else201 {202 // Invoke callback on thread.203 try204 {205 _invokeCallback(_invokeCallbackState);206 }207 catch (Exception)208 {209 }210 }211 }212 213 AsyncWaitHandle.Dispose();214 _completedWaitHandle = null; // Allow early GC215 216 _invokeOnThreadEvent.Dispose();217 _invokeOnThreadEvent = null; // Allow early GC218 219 // Operation is done: if an exception occurred, throw it220 if (Exception != null)221 {222 throw Exception;223 }224 }225 226 /// <summary>227 /// Use blocked thread to invoke callback delegate.228 /// </summary>229 /// <param name="callback">Callback delegate.</param>230 /// <param name="state">Callback state.</param>231 internal bool InvokeCallbackOnThread(WaitCallback callback, object state)232 {233 if (callback == null)234 {235 throw new PSArgumentNullException(nameof(callback));236 }237 238 _invokeCallback = callback;239 _invokeCallbackState = state;240 241 // Signal thread to run callback.242 if (_invokeOnThreadEvent != null)243 {244 _invokeOnThreadEvent.Set();245 return true;246 }247 248 return false;249 }250 251 #endregion252 }253}254 