/// <summary> /// Waits temporarily for the pending asynchronous BeginInvoke call to be completed. /// </summary> /// <param name="millisecondsTimeout">The number of milliseconds to wait, or <see cref="Timeout.Infinite"/> (-1) to wait indefinitely. Beyond this limit, the <c>PooledJob</c>s that are still running are forcibly stopped.</param> /// <returns><value>true</value> if the pool receives a completion signal; otherwise, <value>false</value>.</returns> public bool EndInvoke(int millisecondsTimeout) { // The EndInvoke method should not be called if the pool is not either running or completed lock (_syncObject) { if (_invocationStateInfo.State != PooledPowershellInvocationState.Running && _invocationStateInfo.State != PooledPowershellInvocationState.Completed) throw new PooledPowershellInvalidOperationException("The pool is either not running or not completed."); } bool signalReceived = _invokeAsyncResult.AsyncWaitHandle.WaitOne(millisecondsTimeout); _invokeAsyncResult.AsyncWaitHandle.Close(); List<WaitHandle> stoppingJobsWaitHandles = new List<WaitHandle>(); lock (_syncObject) { // Let's check if all the jobs are completed and if some aren't, let's stop them foreach (PooledJob job in _jobs.Values) { // _executionHandler is set to null after job's completion (whatever it sucessed or failed) // So if it's not null, the job is still running and must be stopped if (job._executionHandler != null) { stoppingJobsWaitHandles.Add(job._ps.BeginStop(null, null).AsyncWaitHandle); job._executionHandler = null; } } } // Waiting for all the stop operations to complete if (stoppingJobsWaitHandles.Count > 0) WaitHandle.WaitAll(stoppingJobsWaitHandles.ToArray()); lock (_syncObject) { _invocationStateInfo = new PooledPowershellInvocationStateInfo(PooledPowershellInvocationState.Completed); } return signalReceived; }
/// <summary> /// Asynchronously runs the commands of the <c>PooledJob</c> objects pipeline by using a specified callback method to use when the invocation is complete. /// </summary> /// <param name="callback">An AsyncCallback delegate that is called when the command invoked by the method is complete.</param> /// <param name="state">A user-supplied state to use when the callback method is called.</param> /// <returns>An <c>IAsyncResult</c> interface that represents the status of the asynchronous operation. The <see cref="EndInvoke"/> method uses this interface to determine when to return the results of the operation.</returns> public IAsyncResult BeginInvoke(AsyncCallback callback, object state) { lock (_syncObject) { if (_isDisposed) throw new PooledPowershellObjectDisposedException(); if (_invocationStateInfo.State == PooledPowershellInvocationState.Running || _invocationStateInfo.State == PooledPowershellInvocationState.Stopping) throw new PooledPowershellInvalidOperationException("The pool is already running."); _invokeAsyncResult = new PooledPowershellAsyncResult(_poolGuid, callback, state); _invocationStateInfo = new PooledPowershellInvocationStateInfo(PooledPowershellInvocationState.Running); foreach (PooledJob job in _jobs.Values) job._executionHandler = job._ps.BeginInvoke((PSDataCollection<PSObject>)null, (PSInvocationSettings)null, _PSCallback, job.InstanceId); } return (IAsyncResult)_invokeAsyncResult; }
/// <summary> /// Method called by the object after each <c>PooledJob</c> has completed. /// </summary> /// <param name="asyncResult">The result of the asynchronous operation. Must actually contain the <c>PooledJob</c>'s Guid.</param> private void _PSCallback(IAsyncResult asyncResult) { lock (_syncObject) { PooledJob job = _jobs[(Guid)asyncResult.AsyncState]; if (asyncResult.IsCompleted) { try { job._result = job._ps.EndInvoke(job._executionHandler); } catch { /* Nothing to do. */ } finally { job._executionHandler = null; asyncResult.AsyncWaitHandle.Close(); _invokeAsyncResult._endedJobs++; if (_invokeAsyncResult._endedJobs == _jobs.Count) { _invokeAsyncResult.SetAsCompleted(null); _invocationStateInfo = new PooledPowershellInvocationStateInfo(PooledPowershellInvocationState.Completed); } } } } }
/// <summary> /// Removes all the jobs from the pool. /// </summary> /// <remarks>When calling this method, the underlying PowerShell pipelines will be disposed.</remarks> public void Purge() { lock (_syncObject) { if (_invocationStateInfo.State == PooledPowershellInvocationState.Running || _invocationStateInfo.State == PooledPowershellInvocationState.Stopping) throw new PooledPowershellInvalidOperationException("The pool is running. You must stop the pool prior to purge it."); _invocationStateInfo = new PooledPowershellInvocationStateInfo(); foreach (PooledJob job in _jobs.Values) { job._ps.RunspacePool = null; job._ps.Dispose(); } _jobs.Clear(); } }