Esempio n. 1
0
        /// <summary>Adds a target to the registry.</summary>
        /// <param name="target">The target to add.</param>
        /// <param name="linkOptions">The link options.</param>
        internal void Add(ref ITargetBlock <T> target, DataflowLinkOptions linkOptions)
        {
            Contract.Requires(target != null, "The target that is supposed to be linked must not be null.");
            Contract.Requires(linkOptions != null, "The link options must not be null.");

            LinkedTargetInfo targetInfo;

            // If the target already exists in the registry, replace it with a new NopLinkPropagator to maintain uniqueness
            if (_targetInformation.TryGetValue(target, out targetInfo))
            {
                target = new NopLinkPropagator(_owningSource, target);
            }

            // Add the target to both stores, the list and the dictionary, which are used for different purposes
            var node = new LinkedTargetInfo(target, linkOptions);

            AddToList(node, linkOptions.Append);
            _targetInformation.Add(target, node);

            // Increment the optimization counter if needed
            Contract.Assert(_linksWithRemainingMessages >= 0, "_linksWithRemainingMessages must be non-negative at any time.");
            if (node.RemainingMessages > 0)
            {
                _linksWithRemainingMessages++;
            }
#if FEATURE_TRACING
            DataflowEtwProvider etwLog = DataflowEtwProvider.Log;
            if (etwLog.IsEnabled())
            {
                etwLog.DataflowBlockLinking(_owningSource, target);
            }
#endif
        }
Esempio n. 2
0
        /// <summary>Removes the LinkedTargetInfo node from the doubly-linked list.</summary>
        /// <param name="node">The node to be removed.</param>
        internal void RemoveFromList(LinkedTargetInfo node)
        {
            Contract.Requires(node != null, "Node to remove is required.");
            Contract.Assert(_firstTarget != null && _lastTarget != null, "Both first and last node must be non-null before RemoveFromList.");

            LinkedTargetInfo previous = node.Previous;
            LinkedTargetInfo next     = node.Next;

            // Remove the node by linking the adjacent nodes
            if (node.Previous != null)
            {
                node.Previous.Next = next;
                node.Previous      = null;
            }

            if (node.Next != null)
            {
                node.Next.Previous = previous;
                node.Next          = null;
            }

            // Adjust the list ends
            if (_firstTarget == node)
            {
                _firstTarget = next;
            }
            if (_lastTarget == node)
            {
                _lastTarget = previous;
            }

            Contract.Assert((_firstTarget != null) == (_lastTarget != null), "Both first and last node must either be null or non-null after RemoveFromList.");
        }
Esempio n. 3
0
        /// <summary>Adds a LinkedTargetInfo node to the doubly-linked list.</summary>
        /// <param name="node">The node to be added.</param>
        /// <param name="append">Whether to append or to prepend the node.</param>
        internal void AddToList(LinkedTargetInfo node, bool append)
        {
            Contract.Requires(node != null, "Requires a node to be added.");

            // If the list is empty, assign the ends to point to the new node and we are done
            if (_firstTarget == null && _lastTarget == null)
            {
                _firstTarget = _lastTarget = node;
            }
            else
            {
                Contract.Assert(_firstTarget != null && _lastTarget != null, "Both first and last node must either be null or non-null.");
                Contract.Assert(_lastTarget.Next == null, "The last node must not have a successor.");
                Contract.Assert(_firstTarget.Previous == null, "The first node must not have a predecessor.");

                if (append)
                {
                    // Link the new node to the end of the existing list
                    node.Previous    = _lastTarget;
                    _lastTarget.Next = node;
                    _lastTarget      = node;
                }
                else
                {
                    // Link the new node to the front of the existing list
                    node.Next             = _firstTarget;
                    _firstTarget.Previous = node;
                    _firstTarget          = node;
                }
            }

            Contract.Assert(_firstTarget != null && _lastTarget != null, "Both first and last node must be non-null after AddToList.");
        }
Esempio n. 4
0
        /// <summary>Clears the target registry entry points while allowing subsequent traversals of the linked list.</summary>
        internal LinkedTargetInfo ClearEntryPoints()
        {
            // Save _firstTarget so we can return it
            LinkedTargetInfo firstTarget = _firstTarget;

            // Clear out the entry points
            _firstTarget = _lastTarget = null;
            _targetInformation.Clear();
            Contract.Assert(_linksWithRemainingMessages >= 0, "_linksWithRemainingMessages must be non-negative at any time.");
            _linksWithRemainingMessages = 0;

            return(firstTarget);
        }
Esempio n. 5
0
        /// <summary>Propagated completion to the targets of the given linked list.</summary>
        /// <param name="firstTarget">The head of a saved linked list.</param>
        internal void PropagateCompletion(LinkedTargetInfo firstTarget)
        {
            Contract.Assert(_owningSource.Completion.IsCompleted, "The owning source must have completed before propagating completion.");

            // Cache the owning source's completion task to avoid calling the getter many times
            Task owningSourceCompletion = _owningSource.Completion;

            // Propagate completion to those targets that have requested it
            for (LinkedTargetInfo node = firstTarget; node != null; node = node.Next)
            {
                if (node.PropagateCompletion)
                {
                    Common.PropagateCompletion(owningSourceCompletion, node.Target, Common.AsyncExceptionHandler);
                }
            }
        }