Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
ConnectionBase.cs1612 linesDownload Raw Back to hostifaces
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Linq;6using System.Management.Automation.Host;7using System.Management.Automation.Internal;8using System.Threading;9#if LEGACYTELEMETRY10using Microsoft.PowerShell.Telemetry.Internal;11#endif12using Dbg = System.Management.Automation.Diagnostics;13 14#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings15 16namespace System.Management.Automation.Runspaces17{18    /// <summary>19    /// Runspaces is base class for different kind of Runspaces.20    /// </summary>21    /// <remarks>There should be a class derived from it for each type of22    /// Runspace. Types of Runspace which we support are Local, X-AppDomain,23    /// X-Process and X-Machine.</remarks>24    internal abstract class RunspaceBase : Runspace25    {26        #region constructors27 28        /// <summary>29        /// Initialize powershell AssemblyLoadContext and register the 'Resolving' event, if it's not done already.30        /// If powershell is hosted by a native host such as DSC, then PS ALC may be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A.31        /// </summary>32        /// <remarks>33        /// We do this both here and during the initialization of the 'ClrFacade' type.34        /// This is because we want to make sure the assembly/library resolvers are:35        ///  1. registered before any script/cmdlet can run.36        ///  2. registered before 'ClrFacade' gets used for assembly related operations.37        ///38        /// The 'ClrFacade' type may be used without a Runspace created, for example, by calling type conversion methods in the 'LanguagePrimitive' type.39        /// And at the mean time, script or cmdlet may run without the 'ClrFacade' type initialized.40        /// That's why we attempt to create the singleton of 'PowerShellAssemblyLoadContext' at both places.41        /// </remarks>42        static RunspaceBase()43        {44            if (PowerShellAssemblyLoadContext.Instance is null)45            {46                PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty, throwOnReentry: false);47            }48        }49 50        /// <summary>51        /// Construct an instance of an Runspace using a custom52        /// implementation of PSHost.53        /// </summary>54        /// <param name="host">The explicit PSHost implementation.</param>55        /// <exception cref="System.ArgumentNullException">56        /// Host is null.57        /// </exception>58        /// <exception cref="System.ArgumentNullException">59        /// host is null.60        /// </exception>61        protected RunspaceBase(PSHost host)62        {63            if (host == null)64            {65                throw PSTraceSource.NewArgumentNullException(nameof(host));66            }67 68            InitialSessionState = InitialSessionState.CreateDefault();69            Host = host;70        }71 72        /// <summary>73        /// Construct an instance of an Runspace using a custom74        /// implementation of PSHost.75        /// </summary>76        /// <param name="host">The explicit PSHost implementation.</param>77        /// <exception cref="System.ArgumentNullException">78        /// Host is null.79        /// </exception>80        /// <exception cref="System.ArgumentNullException">81        /// host is null.82        /// </exception>83        /// <param name="initialSessionState">84        /// configuration information for this runspace instance.85        /// </param>86        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "OK to call ThreadOptions")]87        protected RunspaceBase(PSHost host, InitialSessionState initialSessionState)88        {89            if (host == null)90            {91                throw PSTraceSource.NewArgumentNullException(nameof(host));92            }93 94            if (initialSessionState == null)95            {96                throw PSTraceSource.NewArgumentNullException(nameof(initialSessionState));97            }98 99            Host = host;100            InitialSessionState = initialSessionState.Clone();101            this.ThreadOptions = initialSessionState.ThreadOptions;102            this.ApartmentState = initialSessionState.ApartmentState;103        }104 105        /// <summary>106        /// Construct an instance of an Runspace using a custom107        /// implementation of PSHost.108        /// </summary>109        /// <param name="host">110        /// The explicit PSHost implementation111        /// </param>112        /// <param name="initialSessionState">113        /// configuration information for this runspace instance.114        /// </param>115        /// <param name="suppressClone">116        /// If true, don't make a copy of the initial session state object.117        /// </param>118        /// <exception cref="System.ArgumentNullException">119        /// Host is null.120        /// </exception>121        /// <exception cref="System.ArgumentNullException">122        /// host is null.123        /// </exception>124        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors", Justification = "OK to call ThreadOptions")]125        protected RunspaceBase(PSHost host, InitialSessionState initialSessionState, bool suppressClone)126        {127            if (host == null)128            {129                throw PSTraceSource.NewArgumentNullException(nameof(host));130            }131 132            if (initialSessionState == null)133            {134                throw PSTraceSource.NewArgumentNullException(nameof(initialSessionState));135            }136 137            Host = host;138            if (suppressClone)139            {140                InitialSessionState = initialSessionState;141            }142            else143            {144                InitialSessionState = initialSessionState.Clone();145            }146 147            this.ThreadOptions = initialSessionState.ThreadOptions;148            this.ApartmentState = initialSessionState.ApartmentState;149        }150 151        /// <summary>152        /// The host implemented PSHost interface.153        /// </summary>154        protected PSHost Host { get; }155 156        /// <summary>157        /// InitialSessionState information for this runspace.158        /// </summary>159        public override InitialSessionState InitialSessionState { get; }160 161        #endregion constructors162 163        #region properties164 165        /// <summary>166        /// Return version of this runspace.167        /// </summary>168        public override Version Version { get; } = PSVersionInfo.PSVersion;169 170        private RunspaceStateInfo _runspaceStateInfo = new RunspaceStateInfo(RunspaceState.BeforeOpen);171 172        /// <summary>173        /// Retrieve information about current state of the runspace.174        /// </summary>175        public override RunspaceStateInfo RunspaceStateInfo176        {177            get178            {179                lock (SyncRoot)180                {181                    // Do not return internal state.182                    return _runspaceStateInfo.Clone();183                }184            }185        }186 187        /// <summary>188        /// Gets the current availability of the Runspace.189        /// </summary>190        public override RunspaceAvailability RunspaceAvailability191        {192            get { return _runspaceAvailability; }193 194            protected set { _runspaceAvailability = value; }195        }196 197        private RunspaceAvailability _runspaceAvailability = RunspaceAvailability.None;198 199        /// <summary>200        /// Object used for synchronization.201        /// </summary>202        protected internal object SyncRoot { get; } = new object();203 204        /// <summary>205        /// Information about the computer where this runspace is created.206        /// </summary>207        public override RunspaceConnectionInfo ConnectionInfo208        {209            get210            {211                // null refers to local case for path212                return null;213            }214        }215 216        /// <summary>217        /// Original Connection Info that the user passed.218        /// </summary>219        public override RunspaceConnectionInfo OriginalConnectionInfo220        {221            get { return null; }222        }223 224        #endregion properties225 226        #region Open227 228        /// <summary>229        /// Open the runspace synchronously.230        /// </summary>231        /// <exception cref="InvalidRunspaceStateException">232        /// RunspaceState is not BeforeOpen233        /// </exception>234        public override void Open()235        {236            CoreOpen(true);237        }238 239        /// <summary>240        /// Open the runspace Asynchronously.241        /// </summary>242        /// <exception cref="InvalidRunspaceStateException">243        /// RunspaceState is not BeforeOpen244        /// </exception>245        public override void OpenAsync()246        {247            CoreOpen(false);248        }249 250        /// <summary>251        /// Opens the runspace.252        /// </summary>253        /// <param name="syncCall">If true runspace is opened synchronously254        /// else runspaces is opened asynchronously255        /// </param>256        /// <exception cref="InvalidRunspaceStateException">257        /// RunspaceState is not BeforeOpen258        /// </exception>259        private void CoreOpen(bool syncCall)260        {261            bool etwEnabled = RunspaceEventSource.Log.IsEnabled();262            if (etwEnabled)263            {264                RunspaceEventSource.Log.OpenRunspaceStart();265            }266 267            lock (SyncRoot)268            {269                // Call fails if RunspaceState is not BeforeOpen.270                if (RunspaceState != RunspaceState.BeforeOpen)271                {272                    InvalidRunspaceStateException e =273                        new InvalidRunspaceStateException274                        (275                            StringUtil.Format(RunspaceStrings.CannotOpenAgain, new object[] { RunspaceState.ToString() }),276                            RunspaceState,277                            RunspaceState.BeforeOpen278                        );279                    throw e;280                }281 282                SetRunspaceState(RunspaceState.Opening);283            }284 285            // Raise event outside the lock286            RaiseRunspaceStateEvents();287 288            OpenHelper(syncCall);289            if (etwEnabled)290            {291                RunspaceEventSource.Log.OpenRunspaceStop();292            }293 294#if LEGACYTELEMETRY295            // We report startup telemetry when opening the runspace - because this is the first time296            // we are really using PowerShell. This isn't the cleanest place though, because297            // sometimes there are many runspaces created - the callee ensures telemetry is only298            // reported once. Note that if the host implements IHostProvidesTelemetryData, we rely299            // on the host calling ReportStartupTelemetry.300            if (this.Host is not IHostProvidesTelemetryData)301            {302                TelemetryAPI.ReportStartupTelemetry(null);303            }304#endif305        }306 307        /// <summary>308        /// Derived class's open implementation.309        /// </summary>310        protected abstract void OpenHelper(bool syncCall);311 312        #endregion open313 314        #region close315        /// <summary>316        /// Close the runspace synchronously.317        /// </summary>318        /// <remarks>319        /// Attempts to execute pipelines after a call to close will fail.320        /// </remarks>321        /// <exception cref="InvalidRunspaceStateException">322        /// RunspaceState is BeforeOpen or Opening323        /// </exception>324        public override void Close()325        {326            CoreClose(true);327        }328 329        /// <summary>330        /// Close the runspace Asynchronously.331        /// </summary>332        /// <remarks>333        /// Attempts to execute pipelines after a call to334        /// close will fail.335        /// </remarks>336        /// <exception cref="InvalidRunspaceStateException">337        /// RunspaceState is BeforeOpen or Opening338        /// </exception>339        public override void CloseAsync()340        {341            CoreClose(false);342        }343 344        /// <summary>345        /// Close the runspace.346        /// </summary>347        /// <param name="syncCall">If true runspace is closed synchronously348        /// else runspaces is closed asynchronously349        /// </param>350        /// <exception cref="InvalidRunspaceStateException">351        /// RunspaceState is BeforeOpen or Opening352        /// </exception>353        /// <exception cref="InvalidOperationException">354        /// If SessionStateProxy has some method call in progress355        /// </exception>356        private void CoreClose(bool syncCall)357        {358            bool alreadyClosing = false;359 360            lock (SyncRoot)361            {362                if (RunspaceState == RunspaceState.Closed ||363                    RunspaceState == RunspaceState.Broken)364                {365                    return;366                }367                else if (RunspaceState == RunspaceState.BeforeOpen)368                {369                    SetRunspaceState(RunspaceState.Closing, null);370                    SetRunspaceState(RunspaceState.Closed, null);371 372                    RaiseRunspaceStateEvents();373 374                    return;375                }376                else if (RunspaceState == RunspaceState.Opening)377                {378                    // Wait till the runspace is opened - This is set in DoOpenHelper()379                    // Release the lock before we wait380                    Monitor.Exit(SyncRoot);381                    try382                    {383                        RunspaceOpening.Wait();384                    }385                    finally386                    {387                        // Acquire the lock before we carry on with the rest operations388                        Monitor.Enter(SyncRoot);389                    }390                }391 392                if (_bSessionStateProxyCallInProgress)393                {394                    throw PSTraceSource.NewInvalidOperationException(RunspaceStrings.RunspaceCloseInvalidWhileSessionStateProxy);395                }396 397                if (RunspaceState == RunspaceState.Closing)398                {399                    alreadyClosing = true;400                }401                else402                {403                    if (RunspaceState != RunspaceState.Opened)404                    {405                        InvalidRunspaceStateException e =406                            new InvalidRunspaceStateException407                            (408                                StringUtil.Format(RunspaceStrings.RunspaceNotInOpenedState, RunspaceState.ToString()),409                                RunspaceState,410                                RunspaceState.Opened411                            );412                        throw e;413                    }414 415                    SetRunspaceState(RunspaceState.Closing);416                }417            }418 419            if (alreadyClosing)420            {421                // Already closing is set to true if Runspace is already422                // in closing. In this case wait for runspace to close.423                // This can happen in two scenarios:424                // 1) User calls Runspace.Close from two threads.425                // 2) In remoting, some error from data structure handler layer can start426                // runspace closure. At the same time, user can call427                // remove runspace.428                //429 430                if (syncCall)431                {432                    WaitForFinishofPipelines();433                }434 435                return;436            }437 438            // Raise Event outside the lock439            RaiseRunspaceStateEvents();440 441            // Call the derived class implementation to do the actual work442            CloseHelper(syncCall);443        }444 445        /// <summary>446        /// Derived class's close implementation.447        /// </summary>448        /// <param name="syncCall">If true runspace is closed synchronously449        /// else runspaces is closed asynchronously450        /// </param>451        protected abstract void CloseHelper(bool syncCall);452 453        #endregion close454 455        #region Disconnect-Connect456 457        /// <summary>458        /// Disconnects the runspace synchronously.459        /// </summary>460        public override void Disconnect()461        {462            //463            // Disconnect operation is not supported on local runspaces.464            //465            throw new InvalidRunspaceStateException(466                            RunspaceStrings.DisconnectNotSupported);467        }468 469        /// <summary>470        /// Disconnects the runspace asynchronously.471        /// </summary>472        public override void DisconnectAsync()473        {474            //475            // Disconnect operation is not supported on local runspaces.476            //477            throw new InvalidRunspaceStateException(478                            RunspaceStrings.DisconnectNotSupported);479        }480 481        /// <summary>482        /// Connects a runspace to its remote counterpart synchronously.483        /// </summary>484        public override void Connect()485        {486            //487            // Connect operation is not supported on local runspaces.488            //489            throw new InvalidRunspaceStateException(490                            RunspaceStrings.ConnectNotSupported);491        }492 493        /// <summary>494        /// Connects a runspace to its remote counterpart asynchronously.495        /// </summary>496        public override void ConnectAsync()497        {498            //499            // Connect operation is not supported on local runspaces.500            //501            throw new InvalidRunspaceStateException(502                            RunspaceStrings.ConnectNotSupported);503        }504 505        /// <summary>506        /// Creates a pipeline object in the Disconnected state.507        /// </summary>508        /// <returns>Pipeline.</returns>509        public override Pipeline CreateDisconnectedPipeline()510        {511            //512            // Disconnect-Connect is not supported on local runspaces.513            //514            throw new InvalidRunspaceStateException(515                            RunspaceStrings.DisconnectConnectNotSupported);516        }517 518        /// <summary>519        /// Creates a powershell object in the Disconnected state.520        /// </summary>521        /// <returns>PowerShell.</returns>522        public override PowerShell CreateDisconnectedPowerShell()523        {524            //525            // Disconnect-Connect is not supported on local runspaces.526            //527            throw new InvalidRunspaceStateException(528                            RunspaceStrings.DisconnectConnectNotSupported);529        }530 531        /// <summary>532        /// Returns Runspace capabilities.533        /// </summary>534        /// <returns>RunspaceCapability.</returns>535        public override RunspaceCapability GetCapabilities()536        {537            return RunspaceCapability.Default;538        }539 540        #endregion541 542        #region CreatePipeline543 544        /// <summary>545        /// Create an empty pipeline.546        /// </summary>547        /// <returns>An empty pipeline.</returns>548        public override Pipeline CreatePipeline()549        {550            return CoreCreatePipeline(null, false, false);551        }552 553        /// <summary>554        /// Create a pipeline from a command string.555        /// </summary>556        /// <param name="command">A valid command string.</param>557        /// <returns>558        /// A pipeline pre-filled with Commands specified in commandString.559        /// </returns>560        /// <exception cref="ArgumentNullException">561        /// command is null562        /// </exception>563        public override Pipeline CreatePipeline(string command)564        {565            if (command == null)566            {567                throw PSTraceSource.NewArgumentNullException(nameof(command));568            }569 570            return CoreCreatePipeline(command, false, false);571        }572 573        /// <summary>574        /// Create a pipeline from a command string.575        /// </summary>576        /// <param name="command">A valid command string.</param>577        /// <param name="addToHistory">If true command is added to history.</param>578        /// <returns>579        /// A pipeline pre-filled with Commands specified in commandString.580        /// </returns>581        /// <exception cref="ArgumentNullException">582        /// command is null583        /// </exception>584        public override Pipeline CreatePipeline(string command, bool addToHistory)585        {586            if (command == null)587            {588                throw PSTraceSource.NewArgumentNullException(nameof(command));589            }590 591            return CoreCreatePipeline(command, addToHistory, false);592        }593 594        /// <summary>595        /// Creates a nested pipeline.596        /// </summary>597        /// <remarks>598        /// Nested pipelines are needed for nested prompt scenario. Nested599        /// prompt requires that we execute new pipelines( child pipelines)600        /// while current pipeline (lets call it parent pipeline) is blocked.601        /// </remarks>602        public override Pipeline CreateNestedPipeline()603        {604            return CoreCreatePipeline(null, false, true);605        }606 607        /// <summary>608        /// Creates a nested pipeline.609        /// </summary>610        /// <param name="command">A valid command string.</param>611        /// <param name="addToHistory">If true command is added to history.</param>612        /// <returns>613        /// A pipeline pre-filled with Commands specified in commandString.614        /// </returns>615        /// <exception cref="ArgumentNullException">616        /// command is null617        /// </exception>618        public override Pipeline CreateNestedPipeline(string command, bool addToHistory)619        {620            if (command == null)621            {622                throw PSTraceSource.NewArgumentNullException(nameof(command));623            }624 625            return CoreCreatePipeline(command, addToHistory, true);626        }627 628        /// <summary>629        /// Create a pipeline from a command string.630        /// </summary>631        /// <param name="command">A valid command string or string.Empty.</param>632        /// <param name="addToHistory">If true command is added to history.</param>633        /// <param name="isNested">True for nested pipeline.</param>634        /// <returns>635        /// A pipeline pre-filled with Commands specified in commandString.636        /// </returns>637        protected abstract Pipeline CoreCreatePipeline(string command, bool addToHistory, bool isNested);638 639        #endregion CreatePipeline640 641        #region state change event642 643        /// <summary>644        /// Event raised when RunspaceState changes.645        /// </summary>646        public override event EventHandler<RunspaceStateEventArgs> StateChanged;647 648        /// <summary>649        /// Event raised when the availability of the Runspace changes.650        /// </summary>651        public override event EventHandler<RunspaceAvailabilityEventArgs> AvailabilityChanged;652 653        /// <summary>654        /// Returns true if there are any subscribers to the AvailabilityChanged event.655        /// </summary>656        internal override bool HasAvailabilityChangedSubscribers657        {658            get { return this.AvailabilityChanged != null; }659        }660 661        /// <summary>662        /// Raises the AvailabilityChanged event.663        /// </summary>664        protected override void OnAvailabilityChanged(RunspaceAvailabilityEventArgs e)665        {666            EventHandler<RunspaceAvailabilityEventArgs> eh = this.AvailabilityChanged;667 668            if (eh != null)669            {670                try671                {672                    eh(this, e);673                }674                catch (Exception)675                {676                }677            }678        }679 680        /// <summary>681        /// Retrieve the current state of the runspace.682        /// <see cref="RunspaceState"/>683        /// </summary>684        protected RunspaceState RunspaceState685        {686            get687            {688                return _runspaceStateInfo.State;689            }690        }691 692        /// <summary>693        /// This is queue of all the state change event which have occurred for694        /// this runspace. RaiseRunspaceStateEvents raises event for each695        /// item in this queue. We don't raise events from with SetRunspaceState696        /// because SetRunspaceState is often called from with in the a lock.697        /// Raising event with in a lock introduces chances of deadlock in GUI698        /// applications.699        /// </summary>700        private Queue<RunspaceEventQueueItem> _runspaceEventQueue = new Queue<RunspaceEventQueueItem>();701 702        private sealed class RunspaceEventQueueItem703        {704            public RunspaceEventQueueItem(RunspaceStateInfo runspaceStateInfo, RunspaceAvailability currentAvailability, RunspaceAvailability newAvailability)705            {706                this.RunspaceStateInfo = runspaceStateInfo;707                this.CurrentRunspaceAvailability = currentAvailability;708                this.NewRunspaceAvailability = newAvailability;709            }710 711            public RunspaceStateInfo RunspaceStateInfo;712            public RunspaceAvailability CurrentRunspaceAvailability;713            public RunspaceAvailability NewRunspaceAvailability;714        }715 716        // This is to notify once runspace has been opened (RunspaceState.Opened)717        internal ManualResetEventSlim RunspaceOpening = new ManualResetEventSlim(false);718 719        /// <summary>720        /// Set the new runspace state.721        /// </summary>722        /// <param name="state">The new state.</param>723        /// <param name="reason">An exception indicating the state change is the724        /// result of an error, otherwise; null.725        /// </param>726        /// <remarks>727        /// Sets the internal runspace state information member variable. It also728        /// adds RunspaceStateInfo to a queue.729        /// RaiseRunspaceStateEvents raises event for each item in this queue.730        /// </remarks>731        protected void SetRunspaceState(RunspaceState state, Exception reason)732        {733            lock (SyncRoot)734            {735                if (state != RunspaceState)736                {737                    _runspaceStateInfo = new RunspaceStateInfo(state, reason);738 739                    // Add _runspaceStateInfo to _runspaceEventQueue.740                    // RaiseRunspaceStateEvents will raise event for each item741                    // in this queue.742                    // Note:We are doing clone here instead of passing the member743                    // _runspaceStateInfo because we donot want outside744                    // to change our runspace state.745                    RunspaceAvailability previousAvailability = _runspaceAvailability;746 747                    this.UpdateRunspaceAvailability(_runspaceStateInfo.State, false);748 749                    _runspaceEventQueue.Enqueue(750                        new RunspaceEventQueueItem(751                            _runspaceStateInfo.Clone(),752                            previousAvailability,753                            _runspaceAvailability));754                }755            }756        }757 758        /// <summary>759        /// Set the current runspace state - no error.760        /// </summary>761        /// <param name="state">The new state.</param>762        protected void SetRunspaceState(RunspaceState state)763        {764            this.SetRunspaceState(state, null);765        }766 767        /// <summary>768        /// Raises events for changes in runspace state.769        /// </summary>770        protected void RaiseRunspaceStateEvents()771        {772            Queue<RunspaceEventQueueItem> tempEventQueue = null;773            EventHandler<RunspaceStateEventArgs> stateChanged = null;774            bool hasAvailabilityChangedSubscribers = false;775 776            lock (SyncRoot)777            {778                stateChanged = this.StateChanged;779                hasAvailabilityChangedSubscribers = this.HasAvailabilityChangedSubscribers;780 781                if (stateChanged != null || hasAvailabilityChangedSubscribers)782                {783                    tempEventQueue = _runspaceEventQueue;784                    _runspaceEventQueue = new Queue<RunspaceEventQueueItem>();785                }786                else787                {788                    // Clear the events if there are no EventHandlers. This789                    // ensures that events do not get called for state790                    // changes prior to their registration.791                    _runspaceEventQueue.Clear();792                }793            }794 795            if (tempEventQueue != null)796            {797                while (tempEventQueue.Count > 0)798                {799                    RunspaceEventQueueItem queueItem = tempEventQueue.Dequeue();800 801                    if (hasAvailabilityChangedSubscribers && queueItem.NewRunspaceAvailability != queueItem.CurrentRunspaceAvailability)802                    {803                        this.OnAvailabilityChanged(new RunspaceAvailabilityEventArgs(queueItem.NewRunspaceAvailability));804                    }805 806#pragma warning disable 56500807                    // Exception raised by events are not error condition for runspace808                    // object.809                    if (stateChanged != null)810                    {811                        try812                        {813                            stateChanged(this, new RunspaceStateEventArgs(queueItem.RunspaceStateInfo));814                        }815                        catch (Exception)816                        {817                        }818                    }819#pragma warning restore 56500820                }821            }822        }823 824        #endregion state change event825 826        #region running pipeline management827 828        /// <summary>829        /// In RemoteRunspace, it is required to invoke pipeline830        /// as part of open call (i.e. while state is Opening).831        /// If this property is true, runspace state check is832        /// not performed in AddToRunningPipelineList call.833        /// </summary>834        protected bool ByPassRunspaceStateCheck { get; set; }835 836        private readonly object _pipelineListLock = new object();837 838        /// <summary>839        /// List of pipeline which are currently executing in this runspace.840        /// </summary>841        protected List<Pipeline> RunningPipelines { get; } = new List<Pipeline>();842 843        /// <summary>844        /// Add the pipeline to list of pipelines in execution.845        /// </summary>846        /// <param name="pipeline">Pipeline to add to the847        /// list of pipelines in execution</param>848        /// <exception cref="InvalidRunspaceStateException">849        /// Thrown if the runspace is not in the Opened state.850        /// <see cref="RunspaceState"/>.851        /// </exception>852        /// <exception cref="ArgumentNullException">Thrown if853        /// <paramref name="pipeline"/> is null.854        /// </exception>855        internal void AddToRunningPipelineList(PipelineBase pipeline)856        {857            Dbg.Assert(pipeline != null, "caller should validate the parameter");858 859            lock (_pipelineListLock)860            {861                if (!ByPassRunspaceStateCheck && RunspaceState != RunspaceState.Opened)862                {863                    InvalidRunspaceStateException e =864                        new InvalidRunspaceStateException865                        (866                            StringUtil.Format(RunspaceStrings.RunspaceNotOpenForPipeline, RunspaceState.ToString()),867                            RunspaceState,868                            RunspaceState.Opened869                        );870                    throw e;871                }872 873                // Add the pipeline to list of Executing pipeline.874                // Note:_runningPipelines is always accessed with the lock so875                // there is no need to create a synchronized version of list876                RunningPipelines.Add(pipeline);877                _currentlyRunningPipeline = pipeline;878            }879        }880 881        /// <summary>882        /// Remove the pipeline from list of pipelines in execution.883        /// </summary>884        /// <param name="pipeline">Pipeline to remove from the885        /// list of pipelines in execution</param>886        /// <exception cref="ArgumentNullException">887        /// Thrown if <paramref name="pipeline"/> is null.888        /// </exception>889        internal void RemoveFromRunningPipelineList(PipelineBase pipeline)890        {891            Dbg.Assert(pipeline != null, "caller should validate the parameter");892 893            lock (_pipelineListLock)894            {895                Dbg.Assert(RunspaceState != RunspaceState.BeforeOpen,896                             "Runspace should not be before open when pipeline is running");897 898                // Remove the pipeline to list of Executing pipeline.899                // Note:_runningPipelines is always accessed with the lock so900                // there is no need to create a synchronized version of list901                RunningPipelines.Remove(pipeline);902 903                // Update the running pipeline904                if (RunningPipelines.Count == 0)905                {906                    _currentlyRunningPipeline = null;907                }908                else909                {910                    _currentlyRunningPipeline = RunningPipelines[RunningPipelines.Count - 1];911                }912 913                pipeline.PipelineFinishedEvent.Set();914            }915        }916 917        /// <summary>918        /// Waits till all the pipelines running in the runspace have919        /// finished execution.920        /// </summary>921        internal bool WaitForFinishofPipelines()922        {923            // Take a snapshot of list of active pipelines.924            // Note:Before we enter to this CloseHelper routine925            // CoreClose has already set the state of Runspace926            // to closing. So no new pipelines can be executed on this927            // runspace and so no new pipelines will be added to928            // _runningPipelines. However we still need to lock because929            // running pipelines can be removed from this.930            PipelineBase[] runningPipelines;931 932            lock (_pipelineListLock)933            {934                runningPipelines = RunningPipelines.Cast<PipelineBase>().ToArray();935            }936 937            if (runningPipelines.Length > 0)938            {939                WaitHandle[] waitHandles = new WaitHandle[runningPipelines.Length];940 941                for (int i = 0; i < runningPipelines.Length; i++)942                {943                    waitHandles[i] = runningPipelines[i].PipelineFinishedEvent;944                }945 946                // WaitAll for multiple handles on a STA (single-thread apartment) thread is not supported as WaitAll will prevent the message pump to run947                if (runningPipelines.Length > 1 && Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)948                {949                    // We use a worker thread to wait for all handles, and the STA thread can just wait on the worker thread -- the worker950                    // threads from the ThreadPool are MTA.951                    using (ManualResetEvent waitAllIsDone = new ManualResetEvent(false))952                    {953                        Tuple<WaitHandle[], ManualResetEvent> stateInfo = new Tuple<WaitHandle[], ManualResetEvent>(waitHandles, waitAllIsDone);954 955                        ThreadPool.QueueUserWorkItem(new WaitCallback(956                            (object state) =>957                            {958                                var tuple = (Tuple<WaitHandle[], ManualResetEvent>)state;959                                WaitHandle.WaitAll(tuple.Item1);960                                tuple.Item2.Set();961                            }),962                            stateInfo);963                        return waitAllIsDone.WaitOne();964                    }965                }966 967                return WaitHandle.WaitAll(waitHandles);968            }969            else970            {971                return true;972            }973        }974 975        /// <summary>976        /// Stops all the running pipelines.977        /// </summary>978        protected void StopPipelines()979        {980            PipelineBase[] runningPipelines;981 982            lock (_pipelineListLock)983            {984                runningPipelines = RunningPipelines.Cast<PipelineBase>().ToArray();985            }986 987            if (runningPipelines.Length > 0)988            {989                // Start from the most recent pipeline.990                for (int i = runningPipelines.Length - 1; i >= 0; i--)991                {992                    runningPipelines[i].Stop();993                }994            }995        }996 997        internal bool CanRunActionInCurrentPipeline()998        {999            lock (_pipelineListLock)1000            {1001                // If we have no running pipeline, or if the currently running pipeline is1002                // the same as the current thread, then execute the action.1003                var pipelineRunning = _currentlyRunningPipeline as PipelineBase;1004                return pipelineRunning == null ||1005                    Thread.CurrentThread == pipelineRunning.NestedPipelineExecutionThread;1006            }1007        }1008 1009        /// <summary>1010        /// Gets the currently executing pipeline.1011        /// </summary>1012        /// <remarks>Internal because it is needed by invoke-history</remarks>1013        internal override Pipeline GetCurrentlyRunningPipeline()1014        {1015            return _currentlyRunningPipeline;1016        }1017 1018        private Pipeline _currentlyRunningPipeline = null;1019 1020        /// <summary>1021        /// This method stops all the pipelines which are nested1022        /// under specified pipeline.1023        /// </summary>1024        /// <param name="pipeline"></param>1025        /// <returns></returns>1026        internal void StopNestedPipelines(Pipeline pipeline)1027        {1028            List<Pipeline> nestedPipelines = null;1029 1030            lock (_pipelineListLock)1031            {1032                // first check if this pipeline is in the list of running1033                // pipelines. It is possible that pipeline has already1034                // completed.1035                if (!RunningPipelines.Contains(pipeline))1036                {1037                    return;1038                }1039 1040                // If this pipeline is currently running pipeline,1041                // then it does not have nested pipelines1042                if (GetCurrentlyRunningPipeline() == pipeline)1043                {1044                    return;1045                }1046 1047                // Build list of nested pipelines1048                nestedPipelines = new List<Pipeline>();1049                for (int i = RunningPipelines.Count - 1; i >= 0; i--)1050                {1051                    if (RunningPipelines[i] == pipeline)1052                        break;1053                    nestedPipelines.Add(RunningPipelines[i]);1054                }1055            }1056 1057            foreach (Pipeline np in nestedPipelines)1058            {1059                try1060                {1061                    np.Stop();1062                }1063                catch (InvalidPipelineStateException)1064                {1065                }1066            }1067        }1068 1069        internal1070        void1071        DoConcurrentCheckAndAddToRunningPipelines(PipelineBase pipeline, bool syncCall)1072        {1073            // Concurrency check should be done under runspace lock1074            lock (SyncRoot)1075            {1076                if (_bSessionStateProxyCallInProgress)1077                {1078                    throw PSTraceSource.NewInvalidOperationException(RunspaceStrings.NoPipelineWhenSessionStateProxyInProgress);1079                }1080 1081                // Delegate to pipeline to do check if it is fine to invoke if another1082                // pipeline is running.1083                pipeline.DoConcurrentCheck(syncCall, SyncRoot, true);1084                // Finally add to the list of running pipelines.1085                AddToRunningPipelineList(pipeline);1086            }1087        }1088 1089        // PowerShell support for async notifications happen through the1090        // CheckForInterrupts() method on ParseTreeNode. These are only called when1091        // the engine is active (and processing,) so the Pulse() method1092        // executes the equivalent of a NOP so that async events1093        // can be processed when the engine is idle.1094        internal void Pulse()1095        {1096            // If we don't already have a pipeline running, pulse the engine.1097            bool pipelineCreated = false;1098            if (GetCurrentlyRunningPipeline() == null)1099            {1100                lock (SyncRoot)1101                {1102                    if (GetCurrentlyRunningPipeline() == null)1103                    {1104                        // This is a pipeline that does the least amount possible.1105                        // It evaluates a constant, and results in the execution of only two parse tree nodes.1106                        // We don't need to void it, as we aren't using the results. In addition, voiding1107                        // (as opposed to ignoring) is 1.6x slower.1108                        try1109                        {1110                            PulsePipeline = (PipelineBase)CreatePipeline("0");1111                            PulsePipeline.IsPulsePipeline = true;1112                            pipelineCreated = true;1113                        }1114                        catch (ObjectDisposedException)1115                        {1116                            // Ignore. The runspace is closing. The event was not processed,1117                            // but this should not crash PowerShell.1118                        }1119                    }1120                }1121            }1122 1123            // Invoke pipeline outside the runspace lock.1124            // A concurrency check will be made on the runspace before this1125            // pipeline is invoked.1126            if (pipelineCreated)1127            {1128                try1129                {1130                    PulsePipeline.Invoke();1131                }1132                catch (PSInvalidOperationException)1133                {1134                    // Ignore. A pipeline was created between the time1135                    // we checked for it, and when we invoked the pipeline.1136                    // This is unlikely, but taking a lock on the runspace1137                    // means that OUR invoke will not be able to run.1138                }1139                catch (InvalidRunspaceStateException)1140                {1141                    // Ignore. The runspace is closing. The event was not processed,1142                    // but this should not crash PowerShell.1143                }1144                catch (ObjectDisposedException)1145                {1146                    // Ignore. The runspace is closing. The event was not processed,1147                    // but this should not crash PowerShell.1148                }1149            }1150        }1151 1152        internal PipelineBase PulsePipeline { get; private set; }1153 1154        #endregion running pipeline management1155 1156        #region session state proxy1157 1158        // Note: When SessionStateProxy calls are in progress,1159        // pipeline cannot be invoked. Also when pipeline is in1160        // progress, SessionStateProxy calls cannot be made.1161        private bool _bSessionStateProxyCallInProgress;1162 1163        /// <summary>1164        /// This method ensures that SessionStateProxy call is allowed and if1165        /// allowed it sets a variable to disallow further SessionStateProxy or1166        /// pipeline calls.1167        /// </summary>1168        private void DoConcurrentCheckAndMarkSessionStateProxyCallInProgress()1169        {1170            lock (SyncRoot)1171            {1172                if (RunspaceState != RunspaceState.Opened)1173                {1174                    InvalidRunspaceStateException e =1175                        new InvalidRunspaceStateException1176                        (1177                            StringUtil.Format(RunspaceStrings.RunspaceNotInOpenedState, RunspaceState.ToString()),1178                            RunspaceState,1179                            RunspaceState.Opened1180                        );1181                    throw e;1182                }1183 1184                if (_bSessionStateProxyCallInProgress)1185                {1186                    throw PSTraceSource.NewInvalidOperationException(RunspaceStrings.AnotherSessionStateProxyInProgress);1187                }1188 1189                Pipeline runningPipeline = GetCurrentlyRunningPipeline();1190                if (runningPipeline != null)1191                {1192                    // Detect if we're running an engine pulse, or we're running a nested pipeline1193                    // from an engine pulse1194                    if (runningPipeline == PulsePipeline ||1195                        (runningPipeline.IsNested && PulsePipeline != null))1196                    {1197                        // If so, wait and try again1198                        // Release the lock before we wait for the pulse pipelines1199                        Monitor.Exit(SyncRoot);1200 

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