File: Engine\EngineLoggingServicesOutProc.cs
Web Access
Project: ..\..\..\src\Deprecated\Engine\Microsoft.Build.Engine.csproj (Microsoft.Build.Engine)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
// THE ASSEMBLY BUILT FROM THIS SOURCE FILE HAS BEEN DEPRECATED FOR YEARS. IT IS BUILT ONLY TO PROVIDE
// BACKWARD COMPATIBILITY FOR API USERS WHO HAVE NOT YET MOVED TO UPDATED APIS. PLEASE DO NOT SEND PULL
// REQUESTS THAT CHANGE THIS FILE WITHOUT FIRST CHECKING WITH THE MAINTAINERS THAT THE FIX IS REQUIRED.
 
using System;
using System.Threading;
 
using Microsoft.Build.Framework;
 
namespace Microsoft.Build.BuildEngine
{
    /// <summary>
    /// This class implements the out-of-proc (node process) logging services, provided by the engine
    /// for internal logging purposes.
    /// </summary>
    internal class EngineLoggingServicesOutProc : EngineLoggingServices
    {
        #region Constructors
 
        /// <summary>
        /// Private default constructor -- do not allow instantation w/o parameters.
        /// </summary>
        private EngineLoggingServicesOutProc()
        {
            // do nothing
        }
 
        /// <summary>
        /// Creates an instance of this class for the given engine event source.
        /// </summary>
        internal EngineLoggingServicesOutProc(Node parentNode, ManualResetEvent flushRequestEvent)
        {
            this.parentNode = parentNode;
#pragma warning disable 1717
            this.onlyLogCriticalEvents = onlyLogCriticalEvents;
#pragma warning restore 1717
            this.loggingQueueReadLock = new object();
            this.eventArray = new NodeLoggingEvent[eventArrayChunkSize];
            base.Initialize(flushRequestEvent);
        }
        #endregion
 
        #region Methods
 
        /// <summary>
        /// The out of proc logging service is concerned with flushing the events out to the node provider
        /// to be sent to the parent engine. Events which are not marked with a logger id end up being wrapped
        /// in a NodeLoggingEvent which was a default loggerId of 0. All events posted as BuildEventArgs fall
        /// into this category. Events with a loggerId need be posted as NodeLoggerEventWithLoggerId objects.
        /// This function is thread safe and is called both from the engine thread and communication threads to
        /// ensure that the events are delivered in coherent order.
        /// </summary>
        internal override bool ProcessPostedLoggingEvents()
        {
            lock (loggingQueueReadLock)
            {
                bool processedEvents = false;
 
                lastFlushTime = DateTime.Now.Ticks;
 
                // We use a local array to hold the items that will be dequeueed. We can't reuse the queues because
                // we give up the control of the data structure once we pass it to the node provider and we also need to maintain
                // order between buildEventArgs and nodeLoggingEvent.
                current = 0;
 
                // Process all the events in that have been already posted
                BuildEventArgs buildEventArgs = null;
 
                // Grab all the event args out of the queue
                while ((buildEventArgs = loggingQueueOfBuildEvents.Dequeue()) != null)
                {
                    AddToCurrentArray(new NodeLoggingEvent(buildEventArgs));
                    processedEvents = true;
                }
 
                // Grab all the forwarded events
                NodeLoggingEvent nodeLoggingEvent = null;
                while ((nodeLoggingEvent = loggingQueueOfNodeEvents.Dequeue()) != null)
                {
                    AddToCurrentArray(nodeLoggingEvent);
                    processedEvents = true;
                }
 
                // If there are event - post them to the parent
                if (current != 0)
                {
                    NodeLoggingEvent[] trimmedEventArray = new NodeLoggingEvent[current];
                    Array.Copy(eventArray, trimmedEventArray, current);
                    parentNode.PostLoggingMessagesToHost(trimmedEventArray);
                    current = 0;
                }
                requestedQueueFlush = false;
 
                return processedEvents;
            }
        }
 
        /// <summary>
        /// Adds an event to an array. If the array is full it is posted to the parent and a new array is created
        /// </summary>
        /// <param name="e"></param>
        private void AddToCurrentArray(NodeLoggingEvent e)
        {
            eventArray[current] = e;
            current++;
 
            if (current == eventArrayChunkSize)
            {
                parentNode.PostLoggingMessagesToHost(eventArray);
                eventArray = new NodeLoggingEvent[eventArrayChunkSize];
                current = 0;
            }
        }
 
        /// <summary>
        /// Shutdown the logging service as appropriate
        /// </summary>
        internal override void Shutdown()
        {
            // Do nothing
        }
 
        /// <summary>
        /// Reports an exception thrown while sending logging event to the node
        /// </summary>
        internal void ReportLoggingFailure(Exception e)
        {
            parentNode.ReportUnhandledError(e);
        }
 
        #endregion
 
        #region Data
        /// <summary>
        /// This mutex protects the queue from multiple readers, which may happen in the
        /// out of proc implementation
        /// </summary>
        protected object loggingQueueReadLock;
 
        /// <summary>
        /// If this engine is running in child mode the parent node is used to post logging messages
        /// </summary>
        private Node parentNode;
 
        /// <summary>
        /// Current count of items in the array of events (access should be protected with loggingQueueReadLock)
        /// </summary>
        private int current;
 
        /// <summary>
        /// Array of events to be send to the parent (access should be protected with loggingQueueReadLock)
        /// </summary>
        private NodeLoggingEvent[] eventArray;
 
        /// <summary>
        /// The number of events in one array posted to the parent.
        /// </summary>
        private const int eventArrayChunkSize = 100;
        #endregion
    }
}