Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
RunspacePoolInternal.cs1670 linesDownload Raw Back to hostifaces
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Collections.ObjectModel;6using System.Management.Automation.Internal;7using System.Management.Automation.Security;8using System.Management.Automation.Tracing;9using System.Threading;10 11using Dbg = System.Management.Automation.Diagnostics;12using PSHost = System.Management.Automation.Host.PSHost;13 14namespace System.Management.Automation.Runspaces.Internal15{16    /// <summary>17    /// Class which supports pooling local powerShell runspaces.18    /// </summary>19    internal class RunspacePoolInternal : IDisposable20    {21        #region Private data22 23        protected int maxPoolSz;24        protected int minPoolSz;25        // we need total active runspaces to avoid lock() statements everywhere26        protected int totalRunspaces;27        protected List<Runspace> runspaceList = new List<Runspace>(); // info of all the runspaces in the pool.28        protected Stack<Runspace> pool; // stack of runspaces that are available.29        protected Queue<GetRunspaceAsyncResult> runspaceRequestQueue; // request queue.30        // let requesters request on the runspaceRequestQueue..internally31        // pool services on this queue.32        protected Queue<GetRunspaceAsyncResult> ultimateRequestQueue;33        protected RunspacePoolStateInfo stateInfo;34        protected InitialSessionState _initialSessionState;35        protected PSHost host;36        protected Guid instanceId;37        private bool _isDisposed;38        protected bool isServicingRequests;39        protected object syncObject = new object();40 41        private static readonly TimeSpan s_defaultCleanupPeriod = new TimeSpan(0, 15, 0);   // 15 minutes.42        private TimeSpan _cleanupInterval;43        private readonly Timer _cleanupTimer;44 45        #endregion46 47        #region Constructor48 49        /// <summary>50        /// Constructor which creates a RunspacePool using the51        /// supplied <paramref name="configuration"/>, <paramref name="minRunspaces"/>52        /// and <paramref name="maxRunspaces"/>53        /// </summary>54        /// <param name="maxRunspaces">55        /// The maximum number of Runspaces that can exist in this pool.56        /// Should be greater than or equal to 1.57        /// </param>58        /// <param name="minRunspaces">59        /// The minimum number of Runspaces that can exist in this pool.60        /// Should be greater than or equal to 1.61        /// </param>62        /// <param name="host">63        /// The explicit PSHost implementation.64        /// </param>65        /// <exception cref="ArgumentNullException">66        /// Host is null.67        /// </exception>68        /// <exception cref="ArgumentException">69        /// Maximum runspaces is less than 1.70        /// Minimum runspaces is less than 1.71        /// </exception>72        public RunspacePoolInternal(int minRunspaces,73                int maxRunspaces,74                PSHost host)75            : this(minRunspaces, maxRunspaces)76        {77            if (host == null)78            {79                throw PSTraceSource.NewArgumentNullException(nameof(host));80            }81 82            this.host = host;83            pool = new Stack<Runspace>();84            runspaceRequestQueue = new Queue<GetRunspaceAsyncResult>();85            ultimateRequestQueue = new Queue<GetRunspaceAsyncResult>();86            _initialSessionState = InitialSessionState.CreateDefault();87        }88 89        /// <summary>90        /// Constructor which creates a RunspacePool using the91        /// supplied <paramref name="configuration"/>, <paramref name="minRunspaces"/>92        /// and <paramref name="maxRunspaces"/>93        /// </summary>94        /// <param name="initialSessionState">95        /// InitialSessionState to use when creating a new Runspace.96        /// </param>97        /// <param name="maxRunspaces">98        /// The maximum number of Runspaces that can exist in this pool.99        /// Should be greater than or equal to 1.100        /// </param>101        /// <param name="minRunspaces">102        /// The minimum number of Runspaces that can exist in this pool.103        /// Should be greater than or equal to 1.104        /// </param>105        /// <param name="host">106        /// The explicit PSHost implementation.107        /// </param>108        /// <exception cref="ArgumentNullException">109        /// initialSessionState is null.110        /// Host is null.111        /// </exception>112        /// <exception cref="ArgumentException">113        /// Maximum runspaces is less than 1.114        /// Minimum runspaces is less than 1.115        /// </exception>116        public RunspacePoolInternal(int minRunspaces,117                int maxRunspaces,118                InitialSessionState initialSessionState,119                PSHost host)120            : this(minRunspaces, maxRunspaces)121        {122            if (initialSessionState == null)123            {124                throw PSTraceSource.NewArgumentNullException(nameof(initialSessionState));125            }126 127            if (host == null)128            {129                throw PSTraceSource.NewArgumentNullException(nameof(host));130            }131 132            _initialSessionState = initialSessionState.Clone();133            this.host = host;134            ThreadOptions = initialSessionState.ThreadOptions;135            this.ApartmentState = initialSessionState.ApartmentState;136            pool = new Stack<Runspace>();137            runspaceRequestQueue = new Queue<GetRunspaceAsyncResult>();138            ultimateRequestQueue = new Queue<GetRunspaceAsyncResult>();139        }140 141        /// <summary>142        /// Constructor for doing common initialization between143        /// this class and its derivatives.144        /// </summary>145        /// <param name="maxRunspaces">146        /// The maximum number of Runspaces that can exist in this pool.147        /// Should be greater than or equal to 1.148        /// </param>149        /// <param name="minRunspaces">150        /// The minimum number of Runspaces that can exist in this pool.151        /// Should be greater than or equal to 1.152        /// </param>153        protected RunspacePoolInternal(int minRunspaces, int maxRunspaces)154        {155            if (maxRunspaces < 1)156            {157                throw PSTraceSource.NewArgumentException(nameof(maxRunspaces), RunspacePoolStrings.MaxPoolLessThan1);158            }159 160            if (minRunspaces < 1)161            {162                throw PSTraceSource.NewArgumentException(nameof(minRunspaces), RunspacePoolStrings.MinPoolLessThan1);163            }164 165            if (minRunspaces > maxRunspaces)166            {167                throw PSTraceSource.NewArgumentException(nameof(minRunspaces), RunspacePoolStrings.MinPoolGreaterThanMaxPool);168            }169 170            maxPoolSz = maxRunspaces;171            minPoolSz = minRunspaces;172            stateInfo = new RunspacePoolStateInfo(RunspacePoolState.BeforeOpen, null);173            instanceId = Guid.NewGuid();174            PSEtwLog.SetActivityIdForCurrentThread(instanceId);175 176            _cleanupInterval = s_defaultCleanupPeriod;177            _cleanupTimer = new Timer(new TimerCallback(CleanupCallback), null, Timeout.Infinite, Timeout.Infinite);178        }179 180        /// <summary>181        /// Default constructor.182        /// </summary>183        internal RunspacePoolInternal() { }184 185        #endregion186 187        #region Public Properties188 189        /// <summary>190        /// Get unique id for this instance of runspace pool. It is primarily used191        /// for logging purposes.192        /// </summary>193        public Guid InstanceId194        {195            get196            {197                return instanceId;198            }199        }200 201        /// <summary>202        /// Gets a boolean which describes if the runspace pool is disposed.203        /// </summary>204        public bool IsDisposed205        {206            get207            {208                return _isDisposed;209            }210        }211 212        /// <summary>213        /// Gets State of the current runspace pool.214        /// </summary>215        public RunspacePoolStateInfo RunspacePoolStateInfo216        {217            get218            {219                return stateInfo;220            }221        }222 223        /// <summary>224        /// Private data to be used by applications built on top of PowerShell.225        ///226        /// Local runspace pool is created with application private data set to an empty <see cref="PSPrimitiveDictionary"/>.227        /// </summary>228        internal virtual PSPrimitiveDictionary GetApplicationPrivateData()229        {230            if (_applicationPrivateData == null)231            {232                lock (this.syncObject)233                {234                    _applicationPrivateData ??= new PSPrimitiveDictionary();235                }236            }237 238            return _applicationPrivateData;239        }240 241        internal virtual void PropagateApplicationPrivateData(Runspace runspace)242        {243            runspace.SetApplicationPrivateData(this.GetApplicationPrivateData());244        }245 246        private PSPrimitiveDictionary _applicationPrivateData;247 248        /// <summary>249        /// Gets the InitialSessionState object that this pool uses250        /// to create the runspaces.251        /// </summary>252        public InitialSessionState InitialSessionState253        {254            get255            {256                return _initialSessionState;257            }258        }259 260        /// <summary>261        /// The connection associated with this runspace pool.262        /// </summary>263        public virtual RunspaceConnectionInfo ConnectionInfo264        {265            get266            {267                return null;268            }269        }270 271        /// <summary>272        /// Specifies how often unused runspaces are disposed.273        /// </summary>274        public TimeSpan CleanupInterval275        {276            get277            {278                return _cleanupInterval;279            }280 281            set282            {283                lock (this.syncObject)284                {285                    _cleanupInterval = value;286                }287            }288        }289 290        /// <summary>291        /// Returns runspace pool availability.292        /// </summary>293        public virtual RunspacePoolAvailability RunspacePoolAvailability294        {295            get296            {297                return (stateInfo.State == RunspacePoolState.Opened) ?298                    RunspacePoolAvailability.Available :299                    RunspacePoolAvailability.None;300            }301        }302 303        #endregion304 305        #region events306 307        /// <summary>308        /// Event raised when RunspacePoolState changes.309        /// </summary>310        public event EventHandler<RunspacePoolStateChangedEventArgs> StateChanged;311 312        /// <summary>313        /// Event raised when one of the runspaces in the pool forwards an event to this instance.314        /// </summary>315        public event EventHandler<PSEventArgs> ForwardEvent;316 317        /// <summary>318        /// Event raised when a new Runspace is created by the pool.319        /// </summary>320        internal event EventHandler<RunspaceCreatedEventArgs> RunspaceCreated;321 322        #endregion events323 324        #region Disconnect-Connect Methods325 326        /// <summary>327        /// Synchronously disconnect runspace pool.328        /// </summary>329        public virtual void Disconnect()330        {331            throw PSTraceSource.NewInvalidOperationException(RunspacePoolStrings.RunspaceDisconnectConnectNotSupported);332        }333 334        /// <summary>335        /// Asynchronously disconnect runspace pool.336        /// </summary>337        /// <param name="callback"></param>338        /// <param name="state"></param>339        /// <returns></returns>340        public virtual IAsyncResult BeginDisconnect(AsyncCallback callback, object state)341        {342            throw PSTraceSource.NewInvalidOperationException(RunspacePoolStrings.RunspaceDisconnectConnectNotSupported);343        }344 345        /// <summary>346        /// Wait for BeginDisconnect to complete.347        /// </summary>348        /// <param name="asyncResult"></param>349        public virtual void EndDisconnect(IAsyncResult asyncResult)350        {351            throw PSTraceSource.NewInvalidOperationException(RunspacePoolStrings.RunspaceDisconnectConnectNotSupported);352        }353 354        /// <summary>355        /// Synchronously connect runspace pool.356        /// </summary>357        public virtual void Connect()358        {359            throw PSTraceSource.NewInvalidOperationException(RunspacePoolStrings.RunspaceDisconnectConnectNotSupported);360        }361 362        /// <summary>363        /// Asynchronously connect runspace pool.364        /// </summary>365        /// <param name="callback"></param>366        /// <param name="state"></param>367        /// <returns></returns>368        public virtual IAsyncResult BeginConnect(AsyncCallback callback, object state)369        {370            throw PSTraceSource.NewInvalidOperationException(RunspacePoolStrings.RunspaceDisconnectConnectNotSupported);371        }372 373        /// <summary>374        /// Wait for BeginConnect to complete.375        /// </summary>376        /// <param name="asyncResult"></param>377        public virtual void EndConnect(IAsyncResult asyncResult)378        {379            throw PSTraceSource.NewInvalidOperationException(RunspacePoolStrings.RunspaceDisconnectConnectNotSupported);380        }381 382        /// <summary>383        /// Creates an array of PowerShell objects that are in the Disconnected state for384        /// all currently disconnected running commands associated with this runspace pool.385        /// </summary>386        /// <returns></returns>387        public virtual Collection<PowerShell> CreateDisconnectedPowerShells(RunspacePool runspacePool)388        {389            throw PSTraceSource.NewInvalidOperationException(RunspacePoolStrings.RunspaceDisconnectConnectNotSupported);390        }391 392        /// <summary>393        /// Returns RunspacePool capabilities.394        /// </summary>395        /// <returns>RunspacePoolCapability.</returns>396        public virtual RunspacePoolCapability GetCapabilities()397        {398            return RunspacePoolCapability.Default;399        }400 401        #endregion402 403        #region Public Methods404 405        /// <summary>406        /// Resets the runspace state on a runspace pool with a single407        /// runspace.408        /// This is currently supported *only* for remote runspaces.409        /// </summary>410        /// <returns>True if successful.</returns>411        internal virtual bool ResetRunspaceState()412        {413            throw new PSNotSupportedException();414        }415 416        /// <summary>417        /// Sets the maximum number of Runspaces that can be active concurrently418        /// in the pool. All requests above that number remain queued until419        /// runspaces become available.420        /// </summary>421        /// <param name="maxRunspaces">422        /// The maximum number of runspaces in the pool.423        /// </param>424        /// <returns>425        /// true if the change is successful; otherwise, false.426        /// </returns>427        /// <remarks>428        /// You cannot set the number of runspaces to a number smaller than429        /// the minimum runspaces.430        /// </remarks>431        internal virtual bool SetMaxRunspaces(int maxRunspaces)432        {433            bool isSizeIncreased = false;434 435            lock (pool)436            {437                if (maxRunspaces < this.minPoolSz)438                {439                    return false;440                }441 442                if (maxRunspaces > this.maxPoolSz)443                {444                    isSizeIncreased = true;445                }446                else447                {448                    // since maxrunspaces limit is decreased449                    // destroy unwanted runspaces from the top450                    // of the pool.451                    while (pool.Count > maxRunspaces)452                    {453                        Runspace rsToDestroy = pool.Pop();454                        DestroyRunspace(rsToDestroy);455                    }456                }457 458                maxPoolSz = maxRunspaces;459            }460 461            // pool size is incremented.. check if we can release462            // some requests.463            if (isSizeIncreased)464            {465                EnqueueCheckAndStartRequestServicingThread(null, false);466            }467 468            return true;469        }470 471        /// <summary>472        /// Retrieves the maximum number of runspaces the pool maintains.473        /// </summary>474        /// <returns>475        /// The maximum number of runspaces in the pool476        /// </returns>477        public int GetMaxRunspaces()478        {479            return maxPoolSz;480        }481 482        /// <summary>483        /// Sets the minimum number of Runspaces that the pool maintains484        /// in anticipation of new requests.485        /// </summary>486        /// <param name="minRunspaces">487        /// The minimum number of runspaces in the pool.488        /// </param>489        /// <returns>490        /// true if the change is successful; otherwise, false.491        /// </returns>492        /// <remarks>493        /// You cannot set the number of idle runspaces to a number smaller than494        /// 1 or greater than maximum number of active runspaces.495        /// </remarks>496        internal virtual bool SetMinRunspaces(int minRunspaces)497        {498            lock (pool)499            {500                if ((minRunspaces < 1) || (minRunspaces > this.maxPoolSz))501                {502                    return false;503                }504 505                minPoolSz = minRunspaces;506            }507 508            return true;509        }510 511        /// <summary>512        /// Retrieves the minimum number of runspaces the pool maintains.513        /// </summary>514        /// <returns>515        /// The minimum number of runspaces in the pool516        /// </returns>517        public int GetMinRunspaces()518        {519            return minPoolSz;520        }521 522        /// <summary>523        /// Retrieves the number of runspaces available at the time of calling524        /// this method.525        /// </summary>526        /// <exception cref="ArgumentException">527        /// If the RunspacePool failed or has been closed528        /// </exception>529        /// <returns>530        /// The number of available runspace in the pool.531        /// </returns>532        internal virtual int GetAvailableRunspaces()533        {534            // Dont allow state changes while we get the count535            lock (syncObject)536            {537                if (stateInfo.State == RunspacePoolState.Opened)538                {539                    // Win8: 169492 RunspacePool can report that there are negative runspaces available.540                    // totalRunspaces represents all the runspaces that were ever created by ths RunspacePool541                    // pool.Count represents the runspaces that are currently available542                    // maxPoolSz represents the total capacity w.r.t runspaces for this RunspacePool543                    // Once the RunspacePool allocates a runspace to a consumer, RunspacePool cannot reclaim the544                    // runspace until the consumer released the runspace back to the pool. A SetMaxRunspaces()545                    // call can arrive before the runspace is released..It is bad to make SetMaxRunspaces()546                    // wait for the consumers to release runspaces, so we let SetMaxRunspaces() go by changing547                    // maxPoolSz. Because of this there may be cases where maxPoolSz - totalRunspaces will become548                    // less than 0.549                    int unUsedCapacity = (maxPoolSz - totalRunspaces) < 0 ? 0 : (maxPoolSz - totalRunspaces);550                    return (pool.Count + unUsedCapacity);551                }552                else if (stateInfo.State == RunspacePoolState.Disconnected)553                {554                    throw new InvalidOperationException(RunspacePoolStrings.CannotWhileDisconnected);555                }556                else if (stateInfo.State != RunspacePoolState.BeforeOpen && stateInfo.State != RunspacePoolState.Opening)557                {558                    throw new InvalidOperationException(HostInterfaceExceptionsStrings.RunspacePoolNotOpened);559                }560                else561                {562                    return maxPoolSz;563                }564            }565        }566 567        /// <summary>568        /// Opens the runspacepool synchronously. RunspacePool must569        /// be opened before it can be used.570        /// </summary>571        /// <exception cref="InvalidRunspacePoolStateException">572        /// RunspacePoolState is not BeforeOpen573        /// </exception>574        public virtual void Open()575        {576            CoreOpen(false, null, null);577        }578 579        /// <summary>580        /// Opens the RunspacePool asynchronously. RunspacePool must581        /// be opened before it can be used.582        /// To get the exceptions that might have occurred, call583        /// EndOpen.584        /// </summary>585        /// <param name="callback">586        /// A AsyncCallback to call once the BeginOpen completes.587        /// </param>588        /// <param name="state">589        /// A user supplied state to call the <paramref name="callback"/>590        /// with.591        /// </param>592        /// <returns>593        /// An AsyncResult object to monitor the state of the async594        /// operation.595        /// </returns>596        public IAsyncResult BeginOpen(AsyncCallback callback, object state)597        {598            return CoreOpen(true, callback, state);599        }600 601        /// <summary>602        /// Waits for the pending asynchronous BeginOpen to complete.603        /// </summary>604        /// <exception cref="ArgumentNullException">605        /// asyncResult is a null reference.606        /// </exception>607        /// <exception cref="ArgumentException">608        /// asyncResult object was not created by calling BeginOpen609        /// on this runspacepool instance.610        /// </exception>611        /// <exception cref="InvalidRunspacePoolStateException">612        /// RunspacePoolState is not BeforeOpen.613        /// </exception>614        /// <remarks>615        /// TODO: Behavior if EndOpen is called multiple times.616        /// </remarks>617        public void EndOpen(IAsyncResult asyncResult)618        {619            if (asyncResult == null)620            {621                throw PSTraceSource.NewArgumentNullException(nameof(asyncResult));622            }623 624            RunspacePoolAsyncResult rsAsyncResult = asyncResult as RunspacePoolAsyncResult;625 626            if ((rsAsyncResult == null) ||627                (rsAsyncResult.OwnerId != instanceId) ||628                (!rsAsyncResult.IsAssociatedWithAsyncOpen))629            {630                throw PSTraceSource.NewArgumentException(nameof(asyncResult),631                                                         RunspacePoolStrings.AsyncResultNotOwned,632                                                         "IAsyncResult",633                                                         "BeginOpen");634            }635 636            rsAsyncResult.EndInvoke();637        }638 639        /// <summary>640        /// Closes the RunspacePool and cleans all the internal641        /// resources. This will close all the runspaces in the642        /// runspacepool and release all the async operations643        /// waiting for a runspace. If the pool is already closed644        /// or broken or closing this will just return.645        /// </summary>646        public virtual void Close()647        {648            CoreClose(false, null, null);649        }650 651        /// <summary>652        /// Closes the RunspacePool asynchronously and cleans all the internal653        /// resources. This will close all the runspaces in the654        /// runspacepool and release all the async operations655        /// waiting for a runspace. If the pool is already closed656        /// or broken or closing this will just return.657        /// </summary>658        /// <param name="callback">659        /// A AsyncCallback to call once the BeginClose completes.660        /// </param>661        /// <param name="state">662        /// A user supplied state to call the <paramref name="callback"/>663        /// with.664        /// </param>665        /// <returns>666        /// An AsyncResult object to monitor the state of the async667        /// operation.668        /// </returns>669        public virtual IAsyncResult BeginClose(AsyncCallback callback, object state)670        {671            return CoreClose(true, callback, state);672        }673 674        /// <summary>675        /// Waits for the pending asynchronous BeginClose to complete.676        /// </summary>677        /// <exception cref="ArgumentException">678        /// asyncResult object was not created by calling BeginClose679        /// on this runspacepool instance.680        /// </exception>681        /// <remarks>682        /// TODO: Behavior if EndClose is called multiple times.683        /// </remarks>684        public virtual void EndClose(IAsyncResult asyncResult)685        {686            if (asyncResult == null)687            {688                throw PSTraceSource.NewArgumentNullException(nameof(asyncResult));689            }690 691            RunspacePoolAsyncResult rsAsyncResult = asyncResult as RunspacePoolAsyncResult;692 693            if ((rsAsyncResult == null) ||694                (rsAsyncResult.OwnerId != instanceId) ||695                (rsAsyncResult.IsAssociatedWithAsyncOpen))696            {697                throw PSTraceSource.NewArgumentException(nameof(asyncResult),698                                                         RunspacePoolStrings.AsyncResultNotOwned,699                                                         "IAsyncResult",700                                                         "BeginClose");701            }702 703            rsAsyncResult.EndInvoke();704        }705 706        /// <summary>707        /// Gets a Runspace from the pool. If no free runspace is available708        /// and if max pool size is not reached, a new runspace is created.709        /// Otherwise this will block a runspace is released and available.710        /// </summary>711        /// <returns>712        /// An opened Runspace.713        /// </returns>714        /// <exception cref="InvalidRunspacePoolStateException">715        /// Cannot perform operation because RunspacePool is716        /// not in the opened state.717        /// </exception>718        public Runspace GetRunspace()719        {720            AssertPoolIsOpen();721            // Get the runspace asynchronously.722            GetRunspaceAsyncResult asyncResult = (GetRunspaceAsyncResult)BeginGetRunspace(null, null);723            // Wait for async operation to complete.724            asyncResult.AsyncWaitHandle.WaitOne();725 726            // throw the exception that occurred while727            // processing the async operation728            if (asyncResult.Exception != null)729            {730                throw asyncResult.Exception;731            }732 733            return asyncResult.Runspace;734        }735 736        /// <summary>737        /// Releases a Runspace to the pool. If pool is closed, this738        /// will be a no-op.739        /// </summary>740        /// <param name="runspace">741        /// Runspace to release to the pool.742        /// </param>743        /// <exception cref="ArgumentException">744        /// <paramref name="runspace"/> is null.745        /// </exception>746        /// <exception cref="InvalidRunspacePoolStateException">747        /// Runspool is not in Opened state.748        /// </exception>749        /// <exception cref="InvalidOperationException">750        /// Cannot release the runspace to this pool as the runspace751        /// doesn't belong to this pool.752        /// </exception>753        public void ReleaseRunspace(Runspace runspace)754        {755            if (runspace == null)756            {757                throw PSTraceSource.NewArgumentNullException(nameof(runspace));758            }759 760            AssertPoolIsOpen();761 762            bool isRunspaceReleased = false;763            bool destroyRunspace = false;764 765            // check if the runspace is owned by the pool766            lock (runspaceList)767            {768                if (!runspaceList.Contains(runspace))769                {770                    throw PSTraceSource.NewInvalidOperationException(RunspacePoolStrings.RunspaceNotBelongsToPool);771                }772            }773 774            // Release this runspace only if it is in valid state and is775            // owned by this pool.776            if (runspace.RunspaceStateInfo.State == RunspaceState.Opened)777            {778                lock (pool)779                {780                    if (pool.Count < maxPoolSz)781                    {782                        isRunspaceReleased = true;783                        pool.Push(runspace);784                    }785                    else786                    {787                        // this runspace is not going to be pooled as maxPoolSz is reduced.788                        // so release the runspace and destroy it.789                        isRunspaceReleased = true;790                        destroyRunspace = true;791                    }792                }793            }794            else795            {796                destroyRunspace = true;797                isRunspaceReleased = true;798            }799 800            if (destroyRunspace)801            {802                // Destroying a runspace might be costly.803                // so doing this outside of the lock.804                DestroyRunspace(runspace);805            }806 807            // it is important to release lock on Pool so that808            // other threads can service requests.809            if (isRunspaceReleased)810            {811                // service any pending runspace requests.812                EnqueueCheckAndStartRequestServicingThread(null, false);813            }814        }815 816        /// <summary>817        /// Release all resources.818        /// </summary>819        public void Dispose()820        {821            Dispose(true);822 823            GC.SuppressFinalize(this);824        }825 826        /// <summary>827        /// Dispose off the current runspace pool.828        /// </summary>829        /// <param name="disposing">830        /// true to release all the internal resources.831        /// </param>832        protected virtual void Dispose(bool disposing)833        {834            if (!_isDisposed)835            {836                if (disposing)837                {838                    Close();839                    _cleanupTimer.Dispose();840                    _initialSessionState = null;841                    host = null;842                }843 844                _isDisposed = true;845            }846        }847 848        #endregion849 850        #region Internal Methods851 852        /// <summary>853        /// The value of this property is propagated to all the Runspaces in this pool;854        /// it determines whether a new thread is create when a pipeline is executed.855        /// </summary>856        /// <remarks>857        /// Any updates to the value of this property must be done before the RunspacePool is opened858        /// </remarks>859        internal PSThreadOptions ThreadOptions { get; set; } = PSThreadOptions.Default;860 861        /// <summary>862        /// The value of this property is propagated to all the Runspaces in this pool.863        /// </summary>864        /// <remarks>865        /// Any updates to the value of this property must be done before the RunspacePool is opened866        /// </remarks>867        internal ApartmentState ApartmentState { get; set; } = Runspace.DefaultApartmentState;868 869        /// <summary>870        /// Gets Runspace asynchronously from the runspace pool. The caller871        /// will get notified with the runspace using <paramref name="callback"/>872        /// </summary>873        /// <param name="callback">874        /// A AsyncCallback to call once the runspace is available.875        /// </param>876        /// <param name="state">877        /// A user supplied state to call the <paramref name="callback"/>878        /// with.879        /// </param>880        /// <returns>881        /// An IAsyncResult object to track the status of the Async operation.882        /// </returns>883        internal IAsyncResult BeginGetRunspace(884            AsyncCallback callback, object state)885        {886            AssertPoolIsOpen();887 888            GetRunspaceAsyncResult asyncResult = new GetRunspaceAsyncResult(this.InstanceId,889                callback, state);890 891            // Enqueue and start servicing thread in one go..saving multiple locks.892            EnqueueCheckAndStartRequestServicingThread(asyncResult, true);893 894            return asyncResult;895        }896 897        /// <summary>898        /// Cancels the pending asynchronous BeginGetRunspace operation.899        /// </summary>900        /// <param name="asyncResult">901        /// </param>902        internal void CancelGetRunspace(IAsyncResult asyncResult)903        {904            if (asyncResult == null)905            {906                throw PSTraceSource.NewArgumentNullException(nameof(asyncResult));907            }908 909            GetRunspaceAsyncResult grsAsyncResult =910                asyncResult as GetRunspaceAsyncResult;911 912            if ((grsAsyncResult == null) || (grsAsyncResult.OwnerId != instanceId))913            {914                throw PSTraceSource.NewArgumentException(nameof(asyncResult),915                                                         RunspacePoolStrings.AsyncResultNotOwned,916                                                         "IAsyncResult",917                                                         "BeginGetRunspace");918            }919 920            grsAsyncResult.IsActive = false;921        }922 923        /// <summary>924        /// Waits for the pending asynchronous BeginGetRunspace to complete.925        /// </summary>926        /// <param name="asyncResult">927        /// </param>928        /// <exception cref="ArgumentNullException">929        /// asyncResult is a null reference.930        /// </exception>931        /// <exception cref="ArgumentException">932        /// asyncResult object was not created by calling BeginGetRunspace933        /// on this runspacepool instance.934        /// </exception>935        /// <exception cref="InvalidRunspacePoolStateException">936        /// RunspacePoolState is not BeforeOpen.937        /// </exception>938        /// <remarks>939        /// TODO: Behavior if EndGetRunspace is called multiple times.940        /// </remarks>941        internal Runspace EndGetRunspace(IAsyncResult asyncResult)942        {943            if (asyncResult == null)944            {945                throw PSTraceSource.NewArgumentNullException(nameof(asyncResult));946            }947 948            GetRunspaceAsyncResult grsAsyncResult =949                asyncResult as GetRunspaceAsyncResult;950 951            if ((grsAsyncResult == null) || (grsAsyncResult.OwnerId != instanceId))952            {953                throw PSTraceSource.NewArgumentException(nameof(asyncResult),954                                                         RunspacePoolStrings.AsyncResultNotOwned,955                                                         "IAsyncResult",956                                                         "BeginGetRunspace");957            }958 959            grsAsyncResult.EndInvoke();960            return grsAsyncResult.Runspace;961        }962 963        /// <summary>964        /// Opens the runspacepool synchronously / asynchronously.965        /// Runspace pool must be opened before it can be used.966        /// </summary>967        /// <param name="isAsync">968        /// true to open asynchronously969        /// </param>970        /// <param name="callback">971        /// A AsyncCallback to call once the BeginOpen completes.972        /// </param>973        /// <param name="asyncState">974        /// A user supplied state to call the <paramref name="callback"/>975        /// with.976        /// </param>977        /// <returns>978        /// asyncResult object to monitor status of the async979        /// open operation. This is returned only if <paramref name="isAsync"/>980        /// is true.981        /// </returns>982        /// <exception cref="InvalidRunspacePoolStateException">983        /// Cannot open RunspacePool because RunspacePool is not in984        /// the BeforeOpen state.985        /// </exception>986        /// <exception cref="OutOfMemoryException">987        /// There is not enough memory available to start this asynchronously.988        /// </exception>989        protected virtual IAsyncResult CoreOpen(bool isAsync, AsyncCallback callback,990            object asyncState)991        {992            lock (syncObject)993            {994                AssertIfStateIsBeforeOpen();995 996                stateInfo = new RunspacePoolStateInfo(RunspacePoolState.Opening, null);997            }998 999            // only one thread will reach here, so no1000            // need to lock.1001            RaiseStateChangeEvent(stateInfo);1002 1003            if (isAsync)1004            {1005                AsyncResult asyncResult = new RunspacePoolAsyncResult(instanceId, callback, asyncState, true);1006                // Open pool in another thread1007                ThreadPool.QueueUserWorkItem(new WaitCallback(OpenThreadProc), asyncResult);1008                return asyncResult;1009            }1010 1011            // open the runspace synchronously1012            OpenHelper();1013            return null;1014        }1015 1016        /// <summary>1017        /// Creates a Runspace + opens it synchronously and1018        /// pushes it into the stack.1019        /// </summary>1020        /// <remarks>1021        /// Caller to make sure this is thread safe.1022        /// </remarks>1023        protected void OpenHelper()1024        {1025            try1026            {1027                PSEtwLog.SetActivityIdForCurrentThread(this.InstanceId);1028                // Create a Runspace and store it in the pool1029                // for future use. This will validate whether1030                // a runspace can be created + opened successfully1031                Runspace rs = CreateRunspace();1032                pool.Push(rs);1033            }1034            catch (Exception exception)1035            {1036                SetStateToBroken(exception);1037                // rethrow the exception1038                throw;1039            }1040 1041            bool shouldRaiseEvents = false;1042            // RunspacePool might be closed while we are still opening1043            // we should not change state from closed to opened..1044            lock (syncObject)1045            {1046                if (stateInfo.State == RunspacePoolState.Opening)1047                {1048                    // Change state to opened and notify the user.1049                    stateInfo = new RunspacePoolStateInfo(RunspacePoolState.Opened, null);1050                    shouldRaiseEvents = true;1051                }1052            }1053 1054            if (shouldRaiseEvents)1055            {1056                RaiseStateChangeEvent(stateInfo);1057            }1058        }1059 1060        private void SetStateToBroken(Exception reason)1061        {1062            bool shouldRaiseEvents = false;1063            lock (syncObject)1064            {1065                if ((stateInfo.State == RunspacePoolState.Opening) ||1066                    (stateInfo.State == RunspacePoolState.Opened) ||1067                    (stateInfo.State == RunspacePoolState.Disconnecting) ||1068                    (stateInfo.State == RunspacePoolState.Disconnected) ||1069                    (stateInfo.State == RunspacePoolState.Connecting))1070                {1071                    stateInfo = new RunspacePoolStateInfo(RunspacePoolState.Broken, null);1072                    shouldRaiseEvents = true;1073                }1074            }1075 1076            if (shouldRaiseEvents)1077            {1078                RunspacePoolStateInfo stateInfo = new RunspacePoolStateInfo(this.stateInfo.State,1079                    reason);1080                RaiseStateChangeEvent(stateInfo);1081            }1082        }1083 1084        /// <summary>1085        /// Starting point for asynchronous thread.1086        /// </summary>1087        /// <remarks>1088        /// asyncResult object1089        /// </remarks>1090        protected void OpenThreadProc(object o)1091        {1092            Dbg.Assert(o is AsyncResult, "OpenThreadProc expects AsyncResult");1093            // Since this is an internal method, we can safely cast the1094            // object to AsyncResult object.1095            AsyncResult asyncObject = (AsyncResult)o;1096            // variable to keep track of exceptions.1097            Exception exception = null;1098 1099            try1100            {1101                OpenHelper();1102            }1103            catch (Exception e)1104            {1105                // report non-severe exceptions to the user via the1106                // asyncresult object1107                exception = e;1108            }1109            finally1110            {1111                asyncObject.SetAsCompleted(exception);1112            }1113        }1114 1115        /// <summary>1116        /// Closes the runspacepool synchronously / asynchronously.1117        /// </summary>1118        /// <param name="isAsync">1119        /// true to close asynchronously1120        /// </param>1121        /// <param name="callback">1122        /// A AsyncCallback to call once the BeginClose completes.1123        /// </param>1124        /// <param name="asyncState">1125        /// A user supplied state to call the <paramref name="callback"/>1126        /// with.1127        /// </param>1128        /// <returns>1129        /// asyncResult object to monitor status of the async1130        /// open operation. This is returned only if <paramref name="isAsync"/>1131        /// is true.1132        /// </returns>1133        private IAsyncResult CoreClose(bool isAsync, AsyncCallback callback, object asyncState)1134        {1135            lock (syncObject)1136            {1137                if ((stateInfo.State == RunspacePoolState.Closed) ||1138                    (stateInfo.State == RunspacePoolState.Broken) ||1139                    (stateInfo.State == RunspacePoolState.Closing) ||1140                    (stateInfo.State == RunspacePoolState.Disconnecting) ||1141                    (stateInfo.State == RunspacePoolState.Disconnected))1142                {1143                    if (isAsync)1144                    {1145                        RunspacePoolAsyncResult asyncResult = new RunspacePoolAsyncResult(instanceId, callback, asyncState, false);1146                        asyncResult.SetAsCompleted(null);1147                        return asyncResult;1148                    }1149                    else1150                    {1151                        return null;1152                    }1153                }1154 1155                stateInfo = new RunspacePoolStateInfo(RunspacePoolState.Closing, null);1156            }1157 1158            // only one thread will reach here.1159            RaiseStateChangeEvent(stateInfo);1160 1161            if (isAsync)1162            {1163                RunspacePoolAsyncResult asyncResult = new RunspacePoolAsyncResult(instanceId, callback, asyncState, false);1164                // Open pool in another thread1165                ThreadPool.QueueUserWorkItem(new WaitCallback(CloseThreadProc), asyncResult);1166                return asyncResult;1167            }1168 1169            // open the runspace synchronously1170            CloseHelper();1171            return null;1172        }1173 1174        private void CloseHelper()1175        {1176            try1177            {1178                InternalClearAllResources();1179            }1180            finally1181            {1182                stateInfo = new RunspacePoolStateInfo(RunspacePoolState.Closed, null);1183                RaiseStateChangeEvent(stateInfo);1184            }1185        }1186 1187        private void CloseThreadProc(object o)1188        {1189            Dbg.Assert(o is AsyncResult, "CloseThreadProc expects AsyncResult");1190            // Since this is an internal method, we can safely cast the1191            // object to AsyncResult object.1192            AsyncResult asyncObject = (AsyncResult)o;1193            // variable to keep track of exceptions.1194            Exception exception = null;1195 1196            try1197            {1198                CloseHelper();1199            }1200            catch (Exception e)

Showing the first 1,200 of 1670 lines. Download the file for the rest.