Ejemplo n.º 1
0
        /// <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);
                    }
                }
            }
        }