/// <summary> /// Check if anyother pipeline is executing. /// In case of nested pipeline, checks that it is called /// from currently executing pipeline's thread. /// </summary> /// <param name="syncCall">True if method is called from Invoke, false /// if called from InvokeAsync</param> /// <param name="syncObject">The sync object on which the lock is acquired.</param> /// <param name="isInLock">True if the method is invoked in a critical section.</param> /// <exception cref="InvalidOperationException"> /// 1) A pipeline is already executing. Pipeline cannot execute /// concurrently. /// 2) InvokeAsync is called on nested pipeline. Nested pipeline /// cannot be executed Asynchronously. /// 3) Attempt is made to invoke a nested pipeline directly. Nested /// pipeline must be invoked from a running pipeline. /// </exception> internal void DoConcurrentCheck(bool syncCall, object syncObject, bool isInLock) { PipelineBase currentPipeline = (PipelineBase)RunspaceBase.GetCurrentlyRunningPipeline(); if (IsNested == false) { if (currentPipeline == null) { return; } else { // Detect if we're running a pulse pipeline, or we're running a nested pipeline // in a pulse pipeline if (currentPipeline == RunspaceBase.PulsePipeline || (currentPipeline.IsNested && RunspaceBase.PulsePipeline != null)) { // If so, wait and try again if (isInLock) { // If the method is invoked in the lock statement, release the // lock before wait on the pulse pipeline Monitor.Exit(syncObject); } try { RunspaceBase.WaitForFinishofPipelines(); } finally { if (isInLock) { // If the method is invoked in the lock statement, acquire the // lock before we carry on with the rest operations Monitor.Enter(syncObject); } } DoConcurrentCheck(syncCall, syncObject, isInLock); return; } throw PSTraceSource.NewInvalidOperationException( RunspaceStrings.ConcurrentInvokeNotAllowed); } } else { if (_performNestedCheck) { if (syncCall == false) { throw PSTraceSource.NewInvalidOperationException( RunspaceStrings.NestedPipelineInvokeAsync); } if (currentPipeline == null) { if (this.IsChild) { // OK it's not really a nested pipeline but a call with RunspaceMode=UseCurrentRunspace // This shouldn't fail so we'll clear the IsNested and IsChild flags and then return // That way executions proceeds but everything gets clean up at the end when the pipeline completes this.IsChild = false; _isNested = false; return; } throw PSTraceSource.NewInvalidOperationException( RunspaceStrings.NestedPipelineNoParentPipeline); } Dbg.Assert(currentPipeline.NestedPipelineExecutionThread != null, "Current pipeline should always have NestedPipelineExecutionThread set"); Thread th = Thread.CurrentThread; if (currentPipeline.NestedPipelineExecutionThread.Equals(th) == false) { throw PSTraceSource.NewInvalidOperationException( RunspaceStrings.NestedPipelineNoParentPipeline); } } } }
/// <summary> /// Invoke the pipeline asynchronously with input. /// </summary> /// <param name="input">input to provide to pipeline. Input is /// used only for synchronous execution</param> /// <param name="syncCall">True if this method is called from /// synchronous invoke else false</param> /// <remarks> /// Results are returned through the <see cref="Pipeline.Output"/> reader. /// </remarks> /// <exception cref="InvalidOperationException"> /// No command is added to pipeline /// </exception> /// <exception cref="InvalidPipelineStateException"> /// PipelineState is not NotStarted. /// </exception> /// <exception cref="InvalidOperationException"> /// 1) A pipeline is already executing. Pipeline cannot execute /// concurrently. /// 2) InvokeAsync is called on nested pipeline. Nested pipeline /// cannot be executed Asynchronously. /// 3) Attempt is made to invoke a nested pipeline directly. Nested /// pipeline must be invoked from a running pipeline. /// </exception> /// <exception cref="InvalidRunspaceStateException"> /// RunspaceState is not Open /// </exception> /// <exception cref="ObjectDisposedException"> /// Pipeline already disposed /// </exception> private void CoreInvoke(IEnumerable input, bool syncCall) { lock (SyncRoot) { // NTRAID#Windows Out Of Band Releases-915851-2005/09/13 if (_disposed) { throw PSTraceSource.NewObjectDisposedException("pipeline"); } if (Commands == null || Commands.Count == 0) { throw PSTraceSource.NewInvalidOperationException( RunspaceStrings.NoCommandInPipeline); } if (PipelineState != PipelineState.NotStarted) { InvalidPipelineStateException e = new InvalidPipelineStateException ( StringUtil.Format(RunspaceStrings.PipelineReInvokeNotAllowed), PipelineState, PipelineState.NotStarted ); throw e; } if (syncCall && !(InputStream is PSDataCollectionStream <PSObject> || InputStream is PSDataCollectionStream <object>)) { // Method is called from synchronous invoke. if (input != null) { // TO-DO-Add a test make sure that ObjectDisposed // exception is thrown // Write input data in to inputStream and close the input // pipe. If Input stream is already closed an // ObjectDisposed exception will be thrown foreach (object temp in input) { InputStream.Write(temp); } } InputStream.Close(); } SyncInvokeCall = syncCall; // Create event which will be signalled when pipeline execution // is completed/failed/stoped. // Note:Runspace.Close waits for all the running pipeline // to finish. This Event must be created before pipeline is // added to list of running pipelines. This avoids the race condition // where Close is called after pipeline is added to list of // running pipeline but before event is created. PipelineFinishedEvent = new ManualResetEvent(false); // 1) Do the check to ensure that pipeline no other // pipeline is running. // 2) Runspace object maintains a list of pipelines in // execution. Add this pipeline to the list. RunspaceBase.DoConcurrentCheckAndAddToRunningPipelines(this, syncCall); // Note: Set PipelineState to Running only after adding pipeline to list // of pipelines in execution. AddForExecution checks that runspace is in // state where pipeline can be run. // StartPipelineExecution raises this event. See Windows Bug 1160481 for // more details. SetPipelineState(PipelineState.Running); } try { // Let the derived class start the pipeline execution. StartPipelineExecution(); } catch (Exception exception) { // If we fail in any of the above three steps, set the correct states. RunspaceBase.RemoveFromRunningPipelineList(this); SetPipelineState(PipelineState.Failed, exception); // Note: we are not raising the events in this case. However this is // fine as user is getting the exception. throw; } }
internal SessionStateProxy(RunspaceBase runspace) { this._runspace = runspace; }
internal SessionStateProxy(RunspaceBase runspace) { Dbg.Assert(runspace != null, "Caller should validate the parameter"); _runspace = runspace; }